While we are waiting for all users of wcn399x-bt to be converted to the
pwrseq declaration in the device tree, provide support for the pwrseq
fallback: if the regulators are declared in the device itself, create
pwrseq instance. This way the hci_qca driver doesn't have to cope with
old and new dts bindings.

Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@linaro.org>
---
 drivers/power/pwrseq/pwrseq_qca.c | 155 +++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/drivers/power/pwrseq/pwrseq_qca.c 
b/drivers/power/pwrseq/pwrseq_qca.c
index c15508cc80d2..f237cf2f1880 100644
--- a/drivers/power/pwrseq/pwrseq_qca.c
+++ b/drivers/power/pwrseq/pwrseq_qca.c
@@ -11,9 +11,11 @@
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/pwrseq/driver.h>
+#include <linux/pwrseq/fallback.h>
 #include <linux/regulator/consumer.h>
 
 /* susclk rate */
@@ -369,5 +371,156 @@ static struct platform_driver pwrseq_qca_driver = {
        },
 };
 
-module_platform_driver(pwrseq_qca_driver);
+struct pwrseq_qca_fallback {
+       struct pwrseq_qca_one qca_one;
+       struct pwrseq_qca_common common;
+};
+
+static const struct of_device_id pwrseq_qca_bt_of_match[] = {
+       { .compatible = "qcom,qca6174-bt" },
+       { .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
+       { .compatible = "qcom,qca9377-bt" },
+       { .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990 },
+       { .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3990 },
+       { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998 },
+       { .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750 },
+       { /* sentinel */ },
+};
+
+static const struct qca_device_data qca_soc_data_wifi = {
+       .vregs = {
+               { "vdd-1.8-xo", 80000  },
+               { "vdd-1.3-rfa", 300000 },
+               { "vdd-3.3-ch0", 450000 },
+               { "vdd-3.3-ch1", 450000 },
+       },
+       .num_vregs = 4,
+};
+
+static const struct of_device_id pwrseq_qca_wifi_of_match[] = {
+       { .compatible = "qcom,wcn3990-wifi", .data = &qca_soc_data_wifi },
+       { /* sentinel */ }
+};
+
+static struct pwrseq * pwrseq_qca_fallback_get(struct device *dev)
+{
+       struct pwrseq_qca_fallback *fallback;
+       struct pwrseq *pwrseq;
+       const struct of_device_id *match;
+       const struct qca_device_data *data;
+       struct gpio_desc *gpiod;
+       int ret;
+
+       match = of_match_device(pwrseq_qca_bt_of_match, dev);
+       if (!match)
+               return ERR_PTR(-ENODEV);
+
+       data = match->data;
+       if (!data)
+               data = &qca_soc_data_default;
+
+       fallback = devm_kzalloc(dev, struct_size(fallback, common.vregs, 
data->num_vregs), GFP_KERNEL);
+       if (!data)
+               return ERR_PTR(-ENOMEM);
+
+       fallback->qca_one.common = &fallback->common;
+
+       ret = pwrseq_qca_common_init(dev, &fallback->common, data);
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (data->has_enable_gpios) {
+               gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+               if (IS_ERR(gpiod))
+                       return ERR_PTR(dev_err_probe(dev, PTR_ERR(gpiod), 
"failed to acquire enable GPIO\n"));
+               fallback->qca_one.enable = gpiod;
+       }
+
+       /* If we have no control over device's enablement, make sure that sleep 
clock is always running */
+       if (!fallback->common.vddio ||
+           !fallback->common.num_vregs ||
+           !fallback->qca_one.enable) {
+               ret = clk_set_rate(fallback->common.susclk, SUSCLK_RATE_32KHZ);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               ret = clk_prepare_enable(fallback->common.susclk);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               ret = devm_add_action_or_reset(dev, 
pwrseq_qca_unprepare_susclk, &fallback->common);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
+       pwrseq = devm_pwrseq_create(dev, &pwrseq_qca_ops);
+       if (IS_ERR(pwrseq))
+               return pwrseq;
+
+       pwrseq_set_drvdata(pwrseq, &fallback->qca_one);
+
+       return pwrseq;
+}
+
+static struct pwrseq * pwrseq_qca_fallback_get_bt(struct device *dev, const 
char *id)
+{
+       if (strcmp(id, "bt"))
+               return ERR_PTR(-ENODEV);
+
+       return pwrseq_qca_fallback_get(dev);
+}
+
+static struct pwrseq * pwrseq_qca_fallback_get_wifi(struct device *dev, const 
char *id)
+{
+       if (strcmp(id, "wifi"))
+               return ERR_PTR(-ENODEV);
+
+       return pwrseq_qca_fallback_get(dev);
+}
+
+static struct pwrseq_fallback pwrseq_qca_fallback_bt = {
+       .get = pwrseq_qca_fallback_get_bt,
+       .of_match_table = pwrseq_qca_bt_of_match,
+};
+
+static struct pwrseq_fallback pwrseq_qca_fallback_wifi = {
+       .get = pwrseq_qca_fallback_get_wifi,
+       .of_match_table = pwrseq_qca_wifi_of_match,
+};
+
+static int __init pwrseq_qca_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&pwrseq_qca_driver);
+       if (ret)
+               return ret;
+
+       ret = pwrseq_fallback_register(&pwrseq_qca_fallback_bt);
+       if (ret)
+               goto err_bt;
+
+       ret = pwrseq_fallback_register(&pwrseq_qca_fallback_wifi);
+       if (ret)
+               goto err_wifi;
+
+       return 0;
+
+err_wifi:
+       pwrseq_fallback_unregister(&pwrseq_qca_fallback_bt);
+err_bt:
+       platform_driver_unregister(&pwrseq_qca_driver);
+
+       return ret;
+}
+module_init(pwrseq_qca_init);
+
+static void __exit pwrseq_qca_exit(void)
+{
+       pwrseq_fallback_unregister(&pwrseq_qca_fallback_wifi);
+       pwrseq_fallback_unregister(&pwrseq_qca_fallback_bt);
+       platform_driver_unregister(&pwrseq_qca_driver);
+}
+module_exit(pwrseq_qca_exit);
+
 MODULE_LICENSE("GPL v2");
-- 
2.33.0


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

Reply via email to