[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251105-pci-m2-v1-2-84b5f1f1e5e8@oss.qualcomm.com>
Date: Wed, 05 Nov 2025 14:45:50 +0530
From: Manivannan Sadhasivam <manivannan.sadhasivam@....qualcomm.com>
To: Bjorn Helgaas <bhelgaas@...gle.com>,
Manivannan Sadhasivam <mani@...nel.org>, Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Bartosz Golaszewski <brgl@...ev.pl>
Cc: linux-kernel@...r.kernel.org, linux-pci@...r.kernel.org,
devicetree@...r.kernel.org, linux-arm-msm@...r.kernel.org,
Stephan Gerhold <stephan.gerhold@...aro.org>,
Dmitry Baryshkov <dmitry.baryshkov@....qualcomm.com>,
Manivannan Sadhasivam <manivannan.sadhasivam@....qualcomm.com>
Subject: [PATCH 2/4] PCI/pwrctrl: Add support for handling PCIe M.2
connectors
Add support for handling the PCIe M.2 connectors as Power Sequencing
devices. These connectors are exposed as the Power Sequencing devices
as they often support multiple interfaces like PCIe/SATA, USB/UART to the
host machine and each interfaces could be driven by different client
drivers at the same time.
This driver handles the PCIe interface of these connectors. It first checks
for the presence of the graph port in the Root Port node with the help of
of_graph_is_present() API, if present, it acquires/poweres ON the
corresponding pwrseq device.
Once the pwrseq device is powered ON, the driver will skip parsing the Root
Port/Slot resources and registers with the pwrctrl framework.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@....qualcomm.com>
---
drivers/pci/pwrctrl/Kconfig | 1 +
drivers/pci/pwrctrl/slot.c | 35 ++++++++++++++++++++++++++++++-----
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig
index 6956c18548114ce12247b560f1ef159eb7e90b10..9a195cb7e117465625c68301534af22000dfca8d 100644
--- a/drivers/pci/pwrctrl/Kconfig
+++ b/drivers/pci/pwrctrl/Kconfig
@@ -13,6 +13,7 @@ config PCI_PWRCTRL_PWRSEQ
config PCI_PWRCTRL_SLOT
tristate "PCI Power Control driver for PCI slots"
+ select POWER_SEQUENCING
select PCI_PWRCTRL
help
Say Y here to enable the PCI Power Control driver to control the power
diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c
index 3320494b62d890ffbae6f125e2704167ebccf7b9..d46c2365208ac87c4e83ba8d69ac1914d9bf9088 100644
--- a/drivers/pci/pwrctrl/slot.c
+++ b/drivers/pci/pwrctrl/slot.c
@@ -8,8 +8,10 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/of_graph.h>
#include <linux/pci-pwrctrl.h>
#include <linux/platform_device.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -17,12 +19,18 @@ struct pci_pwrctrl_slot_data {
struct pci_pwrctrl ctx;
struct regulator_bulk_data *supplies;
int num_supplies;
+ struct pwrseq_desc *pwrseq;
};
static void devm_pci_pwrctrl_slot_power_off(void *data)
{
struct pci_pwrctrl_slot_data *slot = data;
+ if (slot->pwrseq) {
+ pwrseq_power_off(slot->pwrseq);
+ return;
+ }
+
regulator_bulk_disable(slot->num_supplies, slot->supplies);
regulator_bulk_free(slot->num_supplies, slot->supplies);
}
@@ -38,6 +46,20 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev)
if (!slot)
return -ENOMEM;
+ if (of_graph_is_present(dev_of_node(dev))) {
+ slot->pwrseq = devm_pwrseq_get(dev, "pcie");
+ if (IS_ERR(slot->pwrseq))
+ return dev_err_probe(dev, PTR_ERR(slot->pwrseq),
+ "Failed to get the power sequencer\n");
+
+ ret = pwrseq_power_on(slot->pwrseq);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to power-on the device\n");
+
+ goto skip_resources;
+ }
+
ret = of_regulator_bulk_get_all(dev, dev_of_node(dev),
&slot->supplies);
if (ret < 0) {
@@ -53,17 +75,20 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off,
- slot);
- if (ret)
- return ret;
-
clk = devm_clk_get_optional_enabled(dev, NULL);
if (IS_ERR(clk)) {
+ regulator_bulk_disable(slot->num_supplies, slot->supplies);
+ regulator_bulk_free(slot->num_supplies, slot->supplies);
return dev_err_probe(dev, PTR_ERR(clk),
"Failed to enable slot clock\n");
}
+skip_resources:
+ ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off,
+ slot);
+ if (ret)
+ return ret;
+
pci_pwrctrl_init(&slot->ctx, dev);
ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx);
--
2.48.1
Powered by blists - more mailing lists