summaryrefslogtreecommitdiff
path: root/drivers/pci/pwrctrl
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>2026-01-28 21:07:15 +0530
committerBjorn Helgaas <bhelgaas@google.com>2026-01-28 10:39:17 -0600
commit9cb64f61ec7a9034299807b1e562413329ddac5b (patch)
tree002e3e1fdd1c31d5536a427358bd986989a65114 /drivers/pci/pwrctrl
parent54786d9806b2720659b4fc64af0ebde148780229 (diff)
downloadlinux-next-9cb64f61ec7a9034299807b1e562413329ddac5b.tar.gz
linux-next-9cb64f61ec7a9034299807b1e562413329ddac5b.zip
PCI/pwrctrl: Add PCIe M.2 connector support
Add support for handling PCIe M.2 connectors as Power Sequencing devices. These connectors are exposed as Power Sequencing devices as they often support multiple interfaces like PCIe/SATA, USB/UART to the host machine, and the interfaces may 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/powers ON the corresponding pwrseq device. Once the pwrseq device is powered ON, the driver will skip parsing the Root Port/Slot resources and register with the pwrctrl framework. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> Link: https://patch.msgid.link/20260128-pci-m2-v7-1-9b3a5fe3d244@oss.qualcomm.com
Diffstat (limited to 'drivers/pci/pwrctrl')
-rw-r--r--drivers/pci/pwrctrl/Kconfig1
-rw-r--r--drivers/pci/pwrctrl/slot.c31
2 files changed, 28 insertions, 4 deletions
diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig
index e0f999f299bb..cd3aa15bad00 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 44eccbca793c..082af81efe25 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>
@@ -18,6 +20,7 @@ struct slot_pwrctrl {
struct regulator_bulk_data *supplies;
int num_supplies;
struct clk *clk;
+ struct pwrseq_desc *pwrseq;
};
static int slot_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl)
@@ -26,6 +29,11 @@ static int slot_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl)
struct slot_pwrctrl, pwrctrl);
int ret;
+ if (slot->pwrseq) {
+ pwrseq_power_on(slot->pwrseq);
+ return 0;
+ }
+
ret = regulator_bulk_enable(slot->num_supplies, slot->supplies);
if (ret < 0) {
dev_err(slot->pwrctrl.dev, "Failed to enable slot regulators\n");
@@ -40,6 +48,11 @@ static int slot_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl)
struct slot_pwrctrl *slot = container_of(pwrctrl,
struct slot_pwrctrl, pwrctrl);
+ if (slot->pwrseq) {
+ pwrseq_power_off(slot->pwrseq);
+ return 0;
+ }
+
regulator_bulk_disable(slot->num_supplies, slot->supplies);
clk_disable_unprepare(slot->clk);
@@ -64,6 +77,15 @@ static int slot_pwrctrl_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");
+
+ goto skip_resources;
+ }
+
ret = of_regulator_bulk_get_all(dev, dev_of_node(dev),
&slot->supplies);
if (ret < 0) {
@@ -73,19 +95,20 @@ static int slot_pwrctrl_probe(struct platform_device *pdev)
slot->num_supplies = ret;
- ret = devm_add_action_or_reset(dev, devm_slot_pwrctrl_release, slot);
- if (ret)
- return ret;
-
slot->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(slot->clk)) {
return dev_err_probe(dev, PTR_ERR(slot->clk),
"Failed to enable slot clock\n");
}
+skip_resources:
slot->pwrctrl.power_on = slot_pwrctrl_power_on;
slot->pwrctrl.power_off = slot_pwrctrl_power_off;
+ ret = devm_add_action_or_reset(dev, devm_slot_pwrctrl_release, slot);
+ if (ret)
+ return ret;
+
pci_pwrctrl_init(&slot->pwrctrl, dev);
ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->pwrctrl);