From cf3c9cc3c80da7679d52fadcdcd9bafe5929b117 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 9 Sep 2026 16:55:55 +0200 Subject: 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 [bhelgaas: squash Geert Uytterhoeven Kconfig fix: https://lore.kernel.org/all/45484c37512a3102495d8b75b6e9f72a141ba42e.1792574560.git.geert+renesas@glider.be, Reviewed-by: Bartosz Golaszewski Acked-by: Lorenzo Bianconi ] Signed-off-by: Bjorn Helgaas Reviewed-by: Bartosz Golaszewski Reviewed-by: Manivannan Sadhasivam Reviewed-by: Alex Elder Link: https://patch.msgid.link/20260909-pci-tc9563-aux-v5-3-c9b33f56c8d3@oss.qualcomm.com --- drivers/pci/pwrctrl/Kconfig | 1 + drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 80 ++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'drivers') 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 +#include #include #include #include #include #include #include +#include #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include @@ -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; -- cgit v1.2.3