From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
This driver is used to control the PCIe M.2 connectors of different
Mechanical Keys attached to the host machines and supporting different
interfaces like PCIe/SATA, USB/UART etc...
Currently, this driver supports only the Mechanical Key M connectors with
PCIe interface. The driver also only supports driving the mandatory 3.3v
and optional 1.8v power supplies. The optional signals of the Key M
connectors are not currently supported.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
MAINTAINERS | 7 ++
drivers/power/sequencing/Kconfig | 8 ++
drivers/power/sequencing/Makefile | 1 +
drivers/power/sequencing/pwrseq-pcie-m2.c | 169 ++++++++++++++++++++++++++++++
4 files changed, 185 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..2eb7b6d26573 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20791,6 +20791,13 @@ F: Documentation/driver-api/pwrseq.rst
F: drivers/power/sequencing/
F: include/linux/pwrseq/
+PCIE M.2 POWER SEQUENCING
+M: Manivannan Sadhasivam <mani@kernel.org>
+L: linux-pci@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/connector/pcie-m2-m-connector.yaml
+F: drivers/power/sequencing/pwrseq-pcie-m2.c
+
POWER STATE COORDINATION INTERFACE (PSCI)
M: Mark Rutland <mark.rutland@arm.com>
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
diff --git a/drivers/power/sequencing/Kconfig b/drivers/power/sequencing/Kconfig
index 280f92beb5d0..f5fff84566ba 100644
--- a/drivers/power/sequencing/Kconfig
+++ b/drivers/power/sequencing/Kconfig
@@ -35,4 +35,12 @@ config POWER_SEQUENCING_TH1520_GPU
GPU. This driver handles the complex clock and reset sequence
required to power on the Imagination BXM GPU on this platform.
+config POWER_SEQUENCING_PCIE_M2
+ tristate "PCIe M.2 connector power sequencing driver"
+ depends on OF || COMPILE_TEST
+ help
+ Say Y here to enable the power sequencing driver for PCIe M.2
+ connectors. This driver handles the power sequencing for the M.2
+ connectors exposing multiple interfaces like PCIe, SATA, UART, etc...
+
endif
diff --git a/drivers/power/sequencing/Makefile b/drivers/power/sequencing/Makefile
index 96c1cf0a98ac..0911d4618298 100644
--- a/drivers/power/sequencing/Makefile
+++ b/drivers/power/sequencing/Makefile
@@ -5,3 +5,4 @@ pwrseq-core-y := core.o
obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o
obj-$(CONFIG_POWER_SEQUENCING_TH1520_GPU) += pwrseq-thead-gpu.o
+obj-$(CONFIG_POWER_SEQUENCING_PCIE_M2) += pwrseq-pcie-m2.o
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
new file mode 100644
index 000000000000..e01e19123415
--- /dev/null
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pwrseq/provider.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct pwrseq_pcie_m2_pdata {
+ const struct pwrseq_target_data **targets;
+};
+
+struct pwrseq_pcie_m2_ctx {
+ struct pwrseq_device *pwrseq;
+ struct device_node *of_node;
+ const struct pwrseq_pcie_m2_pdata *pdata;
+ struct regulator_bulk_data *regs;
+ size_t num_vregs;
+ struct notifier_block nb;
+};
+
+static int pwrseq_pcie_m2_m_vregs_enable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_bulk_enable(ctx->num_vregs, ctx->regs);
+}
+
+static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_bulk_disable(ctx->num_vregs, ctx->regs);
+}
+
+static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = {
+ .name = "regulators-enable",
+ .enable = pwrseq_pcie_m2_m_vregs_enable,
+ .disable = pwrseq_pcie_m2_m_vregs_disable,
+};
+
+static const struct pwrseq_unit_data *pwrseq_pcie_m2_m_unit_deps[] = {
+ &pwrseq_pcie_m2_vregs_unit_data,
+ NULL
+};
+
+static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
+ .name = "pcie-enable",
+ .deps = pwrseq_pcie_m2_m_unit_deps,
+};
+
+static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
+ .name = "pcie",
+ .unit = &pwrseq_pcie_m2_m_pcie_unit_data,
+};
+
+static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = {
+ &pwrseq_pcie_m2_m_pcie_target_data,
+ NULL
+};
+
+static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = {
+ .targets = pwrseq_pcie_m2_m_targets,
+};
+
+static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
+ struct device *dev)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+ struct device_node *endpoint __free(device_node) = NULL;
+
+ /*
+ * Traverse the 'remote-endpoint' nodes and check if the remote node's
+ * parent matches the OF node of 'dev'.
+ */
+ for_each_endpoint_of_node(ctx->of_node, endpoint) {
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_port_parent(endpoint);
+ if (remote && (remote == dev_of_node(dev)))
+ return PWRSEQ_MATCH_OK;
+ }
+
+ return PWRSEQ_NO_MATCH;
+}
+
+static void pwrseq_pcie_free_resources(void *data)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = data;
+
+ regulator_bulk_free(ctx->num_vregs, ctx->regs);
+}
+
+static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pwrseq_pcie_m2_ctx *ctx;
+ struct pwrseq_config config = {};
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->of_node = of_node_get(dev->of_node);
+ ctx->pdata = device_get_match_data(dev);
+ if (!ctx->pdata)
+ return dev_err_probe(dev, -ENODEV,
+ "Failed to obtain platform data\n");
+
+ /*
+ * Currently, of_regulator_bulk_get_all() is the only regulator API that
+ * allows to get all supplies in the devicetree node without manually
+ * specifying them.
+ */
+ ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), &ctx->regs);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to get all regulators\n");
+
+ ctx->num_vregs = ret;
+
+ ret = devm_add_action_or_reset(dev, pwrseq_pcie_free_resources, ctx);
+ if (ret)
+ return ret;
+
+ config.parent = dev;
+ config.owner = THIS_MODULE;
+ config.drvdata = ctx;
+ config.match = pwrseq_pcie_m2_match;
+ config.targets = ctx->pdata->targets;
+
+ ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
+ if (IS_ERR(ctx->pwrseq))
+ return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
+ "Failed to register the power sequencer\n");
+
+ return 0;
+}
+
+static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
+ {
+ .compatible = "pcie-m2-m-connector",
+ .data = &pwrseq_pcie_m2_m_of_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match);
+
+static struct platform_driver pwrseq_pcie_m2_driver = {
+ .driver = {
+ .name = "pwrseq-pcie-m2",
+ .of_match_table = pwrseq_pcie_m2_of_match,
+ },
+ .probe = pwrseq_pcie_m2_probe,
+};
+module_platform_driver(pwrseq_pcie_m2_driver);
+
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>");
+MODULE_DESCRIPTION("Power Sequencing driver for PCIe M.2 connector");
+MODULE_LICENSE("GPL");
--
2.48.1
On Wed, Jan 7, 2026 at 3:11 PM Manivannan Sadhasivam via B4 Relay
<devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> wrote:
>
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> This driver is used to control the PCIe M.2 connectors of different
> Mechanical Keys attached to the host machines and supporting different
> interfaces like PCIe/SATA, USB/UART etc...
>
> Currently, this driver supports only the Mechanical Key M connectors with
> PCIe interface. The driver also only supports driving the mandatory 3.3v
> and optional 1.8v power supplies. The optional signals of the Key M
> connectors are not currently supported.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
This looks good to me, though there are some nits I may fix when applying.
I'll pick it up for v7.0 once the bindings are reviewed.
> +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> @@ -0,0 +1,169 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_platform.h>
It looks like this is a leftover from previous versions and you no
longer need it?
> +
> +static void pwrseq_pcie_free_resources(void *data)
> +{
> + struct pwrseq_pcie_m2_ctx *ctx = data;
> +
> + regulator_bulk_free(ctx->num_vregs, ctx->regs);
> +}
I would call it pwrseq_pcie_m2_free_regulators() if you don't mind.
Bart
On Thu, Jan 08, 2026 at 01:15:12PM +0100, Bartosz Golaszewski wrote:
> On Wed, Jan 7, 2026 at 3:11 PM Manivannan Sadhasivam via B4 Relay
> <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> wrote:
> >
> > From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> >
> > This driver is used to control the PCIe M.2 connectors of different
> > Mechanical Keys attached to the host machines and supporting different
> > interfaces like PCIe/SATA, USB/UART etc...
> >
> > Currently, this driver supports only the Mechanical Key M connectors with
> > PCIe interface. The driver also only supports driving the mandatory 3.3v
> > and optional 1.8v power supplies. The optional signals of the Key M
> > connectors are not currently supported.
> >
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> This looks good to me, though there are some nits I may fix when applying.
>
> I'll pick it up for v7.0 once the bindings are reviewed.
>
Ok. I'm expecting patch 1 to go through ATA tree, patch 2 through DT, and
patches 3,4 through PCI tree.
> > +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> > @@ -0,0 +1,169 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/of_platform.h>
>
> It looks like this is a leftover from previous versions and you no
> longer need it?
>
Yeah.
> > +
> > +static void pwrseq_pcie_free_resources(void *data)
> > +{
> > + struct pwrseq_pcie_m2_ctx *ctx = data;
> > +
> > + regulator_bulk_free(ctx->num_vregs, ctx->regs);
> > +}
>
> I would call it pwrseq_pcie_m2_free_regulators() if you don't mind.
>
Sure. I indeed missed '_m2'.
- Mani
--
மணிவண்ணன் சதாசிவம்
On 1/9/26 07:02, Manivannan Sadhasivam wrote: > On Thu, Jan 08, 2026 at 01:15:12PM +0100, Bartosz Golaszewski wrote: >> On Wed, Jan 7, 2026 at 3:11 PM Manivannan Sadhasivam via B4 Relay >> <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> wrote: >>> >>> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> >>> >>> This driver is used to control the PCIe M.2 connectors of different >>> Mechanical Keys attached to the host machines and supporting different >>> interfaces like PCIe/SATA, USB/UART etc... >>> >>> Currently, this driver supports only the Mechanical Key M connectors with >>> PCIe interface. The driver also only supports driving the mandatory 3.3v >>> and optional 1.8v power supplies. The optional signals of the Key M >>> connectors are not currently supported. >>> >>> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> >> >> This looks good to me, though there are some nits I may fix when applying. >> >> I'll pick it up for v7.0 once the bindings are reviewed. >> > > Ok. I'm expecting patch 1 to go through ATA tree, patch 2 through DT, and > patches 3,4 through PCI tree. Patch 1 seems to be completely unrelated to the power changes, so please send it to the ata list separately. It is otherwise very complicated and confusing for everyone to have patches from one series being applied through multiple trees. -- Damien Le Moal Western Digital Research
On Fri, Jan 09, 2026 at 10:02:10AM +0100, Damien Le Moal wrote: > On 1/9/26 07:02, Manivannan Sadhasivam wrote: > > On Thu, Jan 08, 2026 at 01:15:12PM +0100, Bartosz Golaszewski wrote: > >> On Wed, Jan 7, 2026 at 3:11 PM Manivannan Sadhasivam via B4 Relay > >> <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> wrote: > >>> > >>> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> > >>> > >>> This driver is used to control the PCIe M.2 connectors of different > >>> Mechanical Keys attached to the host machines and supporting different > >>> interfaces like PCIe/SATA, USB/UART etc... > >>> > >>> Currently, this driver supports only the Mechanical Key M connectors with > >>> PCIe interface. The driver also only supports driving the mandatory 3.3v > >>> and optional 1.8v power supplies. The optional signals of the Key M > >>> connectors are not currently supported. > >>> > >>> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> > >> > >> This looks good to me, though there are some nits I may fix when applying. > >> > >> I'll pick it up for v7.0 once the bindings are reviewed. > >> > > > > Ok. I'm expecting patch 1 to go through ATA tree, patch 2 through DT, and > > patches 3,4 through PCI tree. > > Patch 1 seems to be completely unrelated to the power changes, so please send it > to the ata list separately. It is otherwise very complicated and confusing for > everyone to have patches from one series being applied through multiple trees. > Many maintainers often prefer patches in a single series for the complete picture. That's why I clubbed all of them in a single series. But I can send the ATA binding separately also (once it got reviewed by Rob). Btw, with b4, it is no longer a hassle to apply individual patches from a single series. - Mani -- மணிவண்ணன் சதாசிவம்
On Fri, Jan 9, 2026 at 7:02 AM Manivannan Sadhasivam <mani@kernel.org> wrote: > > On Thu, Jan 08, 2026 at 01:15:12PM +0100, Bartosz Golaszewski wrote: > > On Wed, Jan 7, 2026 at 3:11 PM Manivannan Sadhasivam via B4 Relay > > <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org> wrote: > > > > > > From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> > > > > > > This driver is used to control the PCIe M.2 connectors of different > > > Mechanical Keys attached to the host machines and supporting different > > > interfaces like PCIe/SATA, USB/UART etc... > > > > > > Currently, this driver supports only the Mechanical Key M connectors with > > > PCIe interface. The driver also only supports driving the mandatory 3.3v > > > and optional 1.8v power supplies. The optional signals of the Key M > > > connectors are not currently supported. > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> > > > > This looks good to me, though there are some nits I may fix when applying. > > > > I'll pick it up for v7.0 once the bindings are reviewed. > > > > Ok. I'm expecting patch 1 to go through ATA tree, patch 2 through DT, and > patches 3,4 through PCI tree. > I think it would make sense for patch 2 to go through the pwrseq tree with an Ack from DT maintainers. Bartosz
© 2016 - 2026 Red Hat, Inc.