PCI/pwrctl: Add a PCI power control driver for power sequenced devices
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 12 Jun 2024 08:20:18 +0000 (10:20 +0200)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 12 Jun 2024 11:20:56 +0000 (13:20 +0200)
Add a PCI power control driver that's capable of correctly powering up
devices using the power sequencing subsystem. The first users of this
driver are the ath11k module on QCA6390 and ath12k on WCN7850. These
packages require a certain delay between enabling the Bluetooth and WLAN
modules and the power sequencing subsystem takes care of it behind the
scenes.

Tested-by: Amit Pundir <amit.pundir@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD, SM8650-QRD & SM8650-HDK
Tested-by: Caleb Connolly <caleb.connolly@linaro.org> # OnePlus 8T
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/20240612082019.19161-6-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/pci/pwrctl/Kconfig
drivers/pci/pwrctl/Makefile
drivers/pci/pwrctl/pci-pwrctl-pwrseq.c [new file with mode: 0644]

index 9619539..f1b8249 100644 (file)
@@ -5,4 +5,13 @@ menu "PCI Power control drivers"
 config PCI_PWRCTL
        tristate
 
+config PCI_PWRCTL_PWRSEQ
+       tristate "PCI Power Control driver using the Power Sequencing subsystem"
+       select POWER_SEQUENCING
+       select PCI_PWRCTL
+       default m if ((ATH11K_PCI || ATH12K) && ARCH_QCOM)
+       help
+         Enable support for the PCI power control driver for device
+         drivers using the Power Sequencing subsystem.
+
 endmenu
index 52ae064..d308aae 100644 (file)
@@ -2,3 +2,5 @@
 
 obj-$(CONFIG_PCI_PWRCTL)               += pci-pwrctl-core.o
 pci-pwrctl-core-y                      := core.o
+
+obj-$(CONFIG_PCI_PWRCTL_PWRSEQ)                += pci-pwrctl-pwrseq.o
diff --git a/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c b/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
new file mode 100644 (file)
index 0000000..c7a113a
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Linaro Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci-pwrctl.h>
+#include <linux/platform_device.h>
+#include <linux/pwrseq/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+struct pci_pwrctl_pwrseq_data {
+       struct pci_pwrctl ctx;
+       struct pwrseq_desc *pwrseq;
+};
+
+static void devm_pci_pwrctl_pwrseq_power_off(void *data)
+{
+       struct pwrseq_desc *pwrseq = data;
+
+       pwrseq_power_off(pwrseq);
+}
+
+static int pci_pwrctl_pwrseq_probe(struct platform_device *pdev)
+{
+       struct pci_pwrctl_pwrseq_data *data;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->pwrseq = devm_pwrseq_get(dev, of_device_get_match_data(dev));
+       if (IS_ERR(data->pwrseq))
+               return dev_err_probe(dev, PTR_ERR(data->pwrseq),
+                                    "Failed to get the power sequencer\n");
+
+       ret = pwrseq_power_on(data->pwrseq);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to power-on the device\n");
+
+       ret = devm_add_action_or_reset(dev, devm_pci_pwrctl_pwrseq_power_off,
+                                      data->pwrseq);
+       if (ret)
+               return ret;
+
+       data->ctx.dev = dev;
+
+       ret = devm_pci_pwrctl_device_set_ready(dev, &data->ctx);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to register the pwrctl wrapper\n");
+
+       return 0;
+}
+
+static const struct of_device_id pci_pwrctl_pwrseq_of_match[] = {
+       {
+               /* ATH11K in QCA6390 package. */
+               .compatible = "pci17cb,1101",
+               .data = "wlan",
+       },
+       {
+               /* ATH12K in WCN7850 package. */
+               .compatible = "pci17cb,1107",
+               .data = "wlan",
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pci_pwrctl_pwrseq_of_match);
+
+static struct platform_driver pci_pwrctl_pwrseq_driver = {
+       .driver = {
+               .name = "pci-pwrctl-pwrseq",
+               .of_match_table = pci_pwrctl_pwrseq_of_match,
+       },
+       .probe = pci_pwrctl_pwrseq_probe,
+};
+module_platform_driver(pci_pwrctl_pwrseq_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
+MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices");
+MODULE_LICENSE("GPL");