diff options
| author | Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com> | 2026-09-09 16:55:55 +0200 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-10-21 13:15:17 -0500 |
| commit | cf3c9cc3c80da7679d52fadcdcd9bafe5929b117 (patch) | |
| tree | 0c75fe48e38c1acc952ff12d5d3d34519cb53a1a /drivers | |
| parent | 32184f8b8dc14100bd605e157ab70a5a278d7c1e (diff) | |
| download | linux-cf3c9cc3c80da7679d52fadcdcd9bafe5929b117.tar.gz linux-cf3c9cc3c80da7679d52fadcdcd9bafe5929b117.zip | |
PCI/pwrctrl: tc9563: Add GPIO auxiliary device support
The TC9563 embeds a GPIO controller used for per-port reset signals.
Create an auxiliary device for it so the gpio-tc9563 driver can register
the GPIO chip and enable DT-based GPIO lookups. Pass the tc9563 regmap to
the auxiliary device as its platform data.
The pwrctrl driver does not wait for the GPIO chip to be probed. The
per-port reset GPIO lookup, returning -EPROBE_DEFER until the chip is
registered, is added in the next patch.
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
[bhelgaas: squash Geert Uytterhoeven <geert+renesas@glider.be> Kconfig fix:
https://lore.kernel.org/all/45484c37512a3102495d8b75b6e9f72a141ba42e.1792574560.git.geert+renesas@glider.be,
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Acked-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Reviewed-by: Alex Elder <elder@riscstar.com>
Link: https://patch.msgid.link/20260909-pci-tc9563-aux-v5-3-c9b33f56c8d3@oss.qualcomm.com
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/pwrctrl/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 80 |
2 files changed, 81 insertions, 0 deletions
diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 1952ab4f29b6..a2fc2a359702 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -29,6 +29,7 @@ config PCI_PWRCTRL_TC9563 select PCI_PWRCTRL default m if ARCH_QCOM depends on I2C + select AUXILIARY_BUS select REGMAP_I2C help Say Y here to enable the PCI Power Control driver of TC9563 PCIe diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 59ad219c26c0..3fb862105fa5 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -4,12 +4,14 @@ */ #include <linux/array_size.h> +#include <linux/auxiliary_bus.h> #include <linux/bitfield.h> #include <linux/bits.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> +#include <linux/idr.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> @@ -18,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/soc/qcom/tc9563.h> #include <linux/string.h> #include <linux/types.h> @@ -151,6 +154,8 @@ static const struct reg_sequence dsp2_pwroff_seq[] = { {TC9563_PORT_ACCESS_ENABLE, 0x8}, }; +static DEFINE_IDA(tc9563_pwrctrl_ida); + static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl *tc9563, enum tc9563_pwrctrl_ports port) { @@ -393,6 +398,77 @@ static int tc9563_pwrctrl_parse_device_dt(struct device_node *node, return 0; } +static void tc9563_pwrctrl_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + ida_free(&tc9563_pwrctrl_ida, adev->id); + of_node_put(adev->dev.of_node); + kfree(adev); +} + +static void tc9563_pwrctrl_adev_remove(void *data) +{ + struct auxiliary_device *adev = data; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static int tc9563_pwrctrl_adev_add(struct device *dev, const char *name, + struct device_node *of_node, + void *priv_data) +{ + struct auxiliary_device *adev; + int id, ret; + + adev = kzalloc_obj(*adev); + if (!adev) + return -ENOMEM; + + id = ida_alloc(&tc9563_pwrctrl_ida, GFP_KERNEL); + if (id < 0) { + kfree(adev); + return id; + } + + adev->id = id; + adev->name = name; + adev->dev.parent = dev; + adev->dev.platform_data = priv_data; + adev->dev.release = tc9563_pwrctrl_adev_release; + adev->dev.of_node = of_node_get(of_node); + dev_set_of_node_reused(&adev->dev); + + ret = auxiliary_device_init(adev); + if (ret) { + ida_free(&tc9563_pwrctrl_ida, id); + of_node_put(adev->dev.of_node); + kfree(adev); + return ret; + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(dev, tc9563_pwrctrl_adev_remove, adev); +} + +static int tc9563_pwrctrl_add_gpio_adev(struct tc9563_pwrctrl *tc9563) +{ + struct device *dev = tc9563->pwrctrl.dev; + + if (!of_property_read_bool(dev->of_node, "gpio-controller") || + !of_property_present(dev->of_node, "#gpio-cells")) + return 0; + + return tc9563_pwrctrl_adev_add(dev, TC9563_GPIO_DEV_NAME, dev->of_node, + tc9563->regmap); +} + static int tc9563_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) { struct tc9563_pwrctrl *tc9563 = container_of(pwrctrl, @@ -596,6 +672,10 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) tc9563->pwrctrl.power_on = tc9563_pwrctrl_power_on; tc9563->pwrctrl.power_off = tc9563_pwrctrl_power_off; + ret = tc9563_pwrctrl_add_gpio_adev(tc9563); + if (ret) + goto remove_i2c; + ret = devm_pci_pwrctrl_device_set_ready(dev, &tc9563->pwrctrl); if (ret) goto power_off; |
