summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pwrctrl/Kconfig1
-rw-r--r--drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c80
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;