Skip to content

Commit 75996c9

Browse files
Mani-Sadhasivamkwilczynski
authored andcommitted
PCI/pwrctrl: Add pwrctrl driver for PCI slots
This driver is used to control the power state of the devices attached to the PCI slots. Currently, it controls the voltage rails of the PCI slots defined in the devicetree node of the root port. The voltage rails for PCI slots are documented in the DT-schema: https://github.com/devicetree-org/dt-schema/blob/v2024.11/dtschema/schemas/pci/pci-bus-common.yaml#L153 Since this driver has to work with different kind of slots (PCIe x1/x4/x8/x16, Mini PCIe, PCI, etc.), the driver is thus using the of_regulator_bulk_get_all() API to obtain the voltage regulators defined in the DT node, instead of hardcoding them. As such, the DT node of the root port should define the relevant supply properties corresponding to the voltage rails of the PCI slot. Tested-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected] [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński <[email protected]>
1 parent 2a95c1f commit 75996c9

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

drivers/pci/pwrctrl/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,14 @@ config PCI_PWRCTL_PWRSEQ
1010
tristate
1111
select POWER_SEQUENCING
1212
select PCI_PWRCTL
13+
14+
config PCI_PWRCTL_SLOT
15+
tristate "PCI Power Control driver for PCI slots"
16+
select PCI_PWRCTL
17+
help
18+
Say Y here to enable the PCI Power Control driver to control the power
19+
state of PCI slots.
20+
21+
This is a generic driver that controls the power state of different
22+
PCI slots. The voltage regulators powering the rails of the PCI slots
23+
are expected to be defined in the devicetree node of the PCI bridge.

drivers/pci/pwrctrl/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctrl-core.o
44
pci-pwrctrl-core-y := core.o
55

66
obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctrl-pwrseq.o
7+
8+
obj-$(CONFIG_PCI_PWRCTL_SLOT) += pci-pwrctl-slot.o
9+
pci-pwrctl-slot-y := slot.o

drivers/pci/pwrctrl/slot.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2024 Linaro Ltd.
4+
* Author: Manivannan Sadhasivam <[email protected]>
5+
*/
6+
7+
#include <linux/device.h>
8+
#include <linux/mod_devicetable.h>
9+
#include <linux/module.h>
10+
#include <linux/pci-pwrctrl.h>
11+
#include <linux/platform_device.h>
12+
#include <linux/regulator/consumer.h>
13+
#include <linux/slab.h>
14+
15+
struct pci_pwrctrl_slot_data {
16+
struct pci_pwrctrl ctx;
17+
struct regulator_bulk_data *supplies;
18+
int num_supplies;
19+
};
20+
21+
static void devm_pci_pwrctrl_slot_power_off(void *data)
22+
{
23+
struct pci_pwrctrl_slot_data *slot = data;
24+
25+
regulator_bulk_disable(slot->num_supplies, slot->supplies);
26+
regulator_bulk_free(slot->num_supplies, slot->supplies);
27+
}
28+
29+
static int pci_pwrctrl_slot_probe(struct platform_device *pdev)
30+
{
31+
struct pci_pwrctrl_slot_data *slot;
32+
struct device *dev = &pdev->dev;
33+
int ret;
34+
35+
slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL);
36+
if (!slot)
37+
return -ENOMEM;
38+
39+
ret = of_regulator_bulk_get_all(dev, dev_of_node(dev),
40+
&slot->supplies);
41+
if (ret < 0) {
42+
dev_err_probe(dev, ret, "Failed to get slot regulators\n");
43+
return ret;
44+
}
45+
46+
slot->num_supplies = ret;
47+
ret = regulator_bulk_enable(slot->num_supplies, slot->supplies);
48+
if (ret < 0) {
49+
dev_err_probe(dev, ret, "Failed to enable slot regulators\n");
50+
goto err_regulator_free;
51+
}
52+
53+
ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off,
54+
slot);
55+
if (ret)
56+
goto err_regulator_disable;
57+
58+
pci_pwrctrl_init(&slot->ctx, dev);
59+
60+
ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx);
61+
if (ret)
62+
return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n");
63+
64+
return 0;
65+
66+
err_regulator_disable:
67+
regulator_bulk_disable(slot->num_supplies, slot->supplies);
68+
err_regulator_free:
69+
regulator_bulk_free(slot->num_supplies, slot->supplies);
70+
71+
return ret;
72+
}
73+
74+
static const struct of_device_id pci_pwrctrl_slot_of_match[] = {
75+
{
76+
.compatible = "pciclass,0604",
77+
},
78+
{ }
79+
};
80+
MODULE_DEVICE_TABLE(of, pci_pwrctrl_slot_of_match);
81+
82+
static struct platform_driver pci_pwrctrl_slot_driver = {
83+
.driver = {
84+
.name = "pci-pwrctrl-slot",
85+
.of_match_table = pci_pwrctrl_slot_of_match,
86+
},
87+
.probe = pci_pwrctrl_slot_probe,
88+
};
89+
module_platform_driver(pci_pwrctrl_slot_driver);
90+
91+
MODULE_AUTHOR("Manivannan Sadhasivam <[email protected]>");
92+
MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots");
93+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)