diff options
Diffstat (limited to 'recipes-kernel/linux/linux-yocto/qca6390-driver')
5 files changed, 726 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-yocto/qca6390-driver/0001-dt-bindings-mfd-qcom-qca639x-add-binding-for-QCA639x.patch b/recipes-kernel/linux/linux-yocto/qca6390-driver/0001-dt-bindings-mfd-qcom-qca639x-add-binding-for-QCA639x.patch new file mode 100644 index 0000000..a9881f0 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/qca6390-driver/0001-dt-bindings-mfd-qcom-qca639x-add-binding-for-QCA639x.patch @@ -0,0 +1,111 @@ +From 3b909d078f454238bb9e8ec454a891765df968f6 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Date: Sun, 20 Dec 2020 18:47:57 +0300 +Subject: [PATCH 1/5] dt-bindings: mfd: qcom,qca639x: add binding for QCA639x + defvice + +Qualcomm QCA639x is a family of WiFi + Bluetooth SoCs, with BT part +being controlled through the UART and WiFi being present on PCIe bus. +Both blocks share common power sources. Add binding to describe power +sequencing required to power up this device. + +Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Upstream-Status: Inappropriate +--- + .../devicetree/bindings/mfd/qcom,qca639x.yaml | 84 +++++++++++++++++++ + 1 file changed, 84 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mfd/qcom,qca639x.yaml + +diff --git a/Documentation/devicetree/bindings/mfd/qcom,qca639x.yaml b/Documentation/devicetree/bindings/mfd/qcom,qca639x.yaml +new file mode 100644 +index 000000000000..d43c75da136f +--- /dev/null ++++ b/Documentation/devicetree/bindings/mfd/qcom,qca639x.yaml +@@ -0,0 +1,84 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: "http://devicetree.org/schemas/mfd/qcom,qca639x.yaml#" ++$schema: "http://devicetree.org/meta-schemas/core.yaml#" ++ ++title: Qualcomm QCA639x WiFi + Bluetoot SoC bindings ++ ++maintainers: ++ - Andy Gross <agross@kernel.org> ++ - Bjorn Andersson <bjorn.andersson@linaro.org> ++ ++description: | ++ This binding describes thes Qualcomm QCA6390 or QCA6391 power supplies and ++ enablement pins. ++ ++properties: ++ compatible: ++ const: qcom,qca639x ++ ++ '#power-domain-cells': ++ const: 0 ++ ++ pinctrl-0: true ++ pinctrl-1: true ++ ++ pinctrl-names: ++ items: ++ - const: default ++ - const: active ++ ++ vddaon-supply: ++ description: ++ 0.95V always-on LDO power input ++ ++ vddpmu-supply: ++ description: ++ 0.95V LDO power input to PMU ++ ++ vddrfa1-supply: ++ description: ++ 0.95V LDO power input to RFA ++ ++ vddrfa2-supply: ++ description: ++ 1.25V LDO power input to RFA ++ ++ vddrfa3-supply: ++ description: ++ 2V LDO power input to RFA ++ ++ vddpcie1-supply: ++ description: ++ 1.25V LDO power input to PCIe part ++ ++ vddpcie2-supply: ++ description: ++ 2V LDO power input to PCIe part ++ ++ vddio-supply: ++ description: ++ 1.8V VIO input ++ ++additionalProperties: false ++ ++examples: ++ - | ++ qca639x: qca639x { ++ compatible = "qcom,qca639x"; ++ #power-domain-cells = <0>; ++ ++ vddaon-supply = <&vreg_s6a_0p95>; ++ vddpmu-supply = <&vreg_s2f_0p95>; ++ vddrfa1-supply = <&vreg_s2f_0p95>; ++ vddrfa2-supply = <&vreg_s8c_1p3>; ++ vddrfa3-supply = <&vreg_s5a_1p9>; ++ vddpcie1-supply = <&vreg_s8c_1p3>; ++ vddpcie2-supply = <&vreg_s5a_1p9>; ++ vddio-supply = <&vreg_s4a_1p8>; ++ pinctrl-names = "default", "active"; ++ pinctrl-0 = <&wlan_default_state &bt_default_state>; ++ pinctrl-1 = <&wlan_active_state &bt_active_state>; ++ }; ++... +-- +2.39.2 + diff --git a/recipes-kernel/linux/linux-yocto/qca6390-driver/0002-mfd-qca639x-add-support-for-QCA639x-powerup-sequence.patch b/recipes-kernel/linux/linux-yocto/qca6390-driver/0002-mfd-qca639x-add-support-for-QCA639x-powerup-sequence.patch new file mode 100644 index 0000000..2621853 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/qca6390-driver/0002-mfd-qca639x-add-support-for-QCA639x-powerup-sequence.patch @@ -0,0 +1,225 @@ +From 6cca247e22ac57fcc99241fee201056c1967278e Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Date: Fri, 18 Dec 2020 16:24:56 +0300 +Subject: [PATCH 2/5] mfd: qca639x: add support for QCA639x powerup sequence + +Qualcomm QCA639x is a family of WiFi + Bluetooth SoCs, with BT part +being controlled through the UART and WiFi being present on PCIe +bus. Both blocks share common power sources. So add mfd device driver +handling power sequencing of QCA6390/1. + +Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Upstream-Status: Inappropriate +--- + drivers/mfd/Kconfig | 12 +++ + drivers/mfd/Makefile | 1 + + drivers/mfd/qcom-qca639x.c | 162 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 175 insertions(+) + create mode 100644 drivers/mfd/qcom-qca639x.c + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index e90463c4441c..9abb4df8d66b 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -1086,6 +1086,18 @@ config MFD_PM8XXX + Say M here if you want to include support for PM8xxx chips as a + module. This will build a module called "pm8xxx-core". + ++config MFD_QCOM_QCA639X ++ tristate "Qualcomm QCA639x WiFi/Bluetooth module support" ++ depends on REGULATOR && PM_GENERIC_DOMAINS ++ help ++ If you say yes to this option, support will be included for Qualcomm ++ QCA639x family of WiFi and Bluetooth SoCs. Note, this driver supports ++ only power control for this SoC, you still have to enable individual ++ Bluetooth and WiFi drivers. ++ ++ Say M here if you want to include support for QCA639x chips as a ++ module. This will build a module called "qcom-qca639x". ++ + config MFD_QCOM_RPM + tristate "Qualcomm Resource Power Manager (RPM)" + depends on ARCH_QCOM && OF +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index 1d2392f06f78..f7f25ef9e17a 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -197,6 +197,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o + obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o + obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o + obj-$(CONFIG_MFD_PM8XXX) += qcom-pm8xxx.o ssbi.o ++obj-$(CONFIG_MFD_QCOM_QCA639X) += qcom-qca639x.o + obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o + obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o + obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o +diff --git a/drivers/mfd/qcom-qca639x.c b/drivers/mfd/qcom-qca639x.c +new file mode 100644 +index 000000000000..b31e4b65bec5 +--- /dev/null ++++ b/drivers/mfd/qcom-qca639x.c +@@ -0,0 +1,162 @@ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/pinctrl/consumer.h> ++#include <linux/pinctrl/devinfo.h> ++#include <linux/platform_device.h> ++#include <linux/pm_domain.h> ++#include <linux/regulator/consumer.h> ++#include <linux/slab.h> ++ ++#define MAX_NUM_REGULATORS 8 ++ ++static struct vreg { ++ const char *name; ++ unsigned int load_uA; ++} vregs [MAX_NUM_REGULATORS] = { ++ /* 2.0 V */ ++ { "vddpcie2", 15000 }, ++ { "vddrfa3", 400000 }, ++ ++ /* 0.95 V */ ++ { "vddaon", 100000 }, ++ { "vddpmu", 1250000 }, ++ { "vddrfa1", 200000 }, ++ ++ /* 1.35 V */ ++ { "vddrfa2", 400000 }, ++ { "vddpcie1", 35000 }, ++ ++ /* 1.8 V */ ++ { "vddio", 20000 }, ++}; ++ ++struct qca639x_data { ++ struct regulator_bulk_data regulators[MAX_NUM_REGULATORS]; ++ size_t num_vregs; ++ struct device *dev; ++ struct pinctrl_state *active_state; ++ struct generic_pm_domain pd; ++}; ++ ++#define domain_to_data(domain) container_of(domain, struct qca639x_data, pd) ++ ++static int qca639x_power_on(struct generic_pm_domain *domain) ++{ ++ struct qca639x_data *data = domain_to_data(domain); ++ int ret; ++ ++ dev_warn(&domain->dev, "DUMMY POWER ON\n"); ++ ++ ret = regulator_bulk_enable(data->num_vregs, data->regulators); ++ if (ret) { ++ dev_err(data->dev, "Failed to enable regulators"); ++ return ret; ++ } ++ ++ /* Wait for 1ms before toggling enable pins. */ ++ msleep(1); ++ ++ ret = pinctrl_select_state(data->dev->pins->p, data->active_state); ++ if (ret) { ++ dev_err(data->dev, "Failed to select active state"); ++ return ret; ++ } ++ ++ /* Wait for all power levels to stabilize */ ++ msleep(6); ++ ++ return 0; ++} ++ ++static int qca639x_power_off(struct generic_pm_domain *domain) ++{ ++ struct qca639x_data *data = domain_to_data(domain); ++ ++ dev_warn(&domain->dev, "DUMMY POWER OFF\n"); ++ ++ pinctrl_select_default_state(data->dev); ++ regulator_bulk_disable(data->num_vregs, data->regulators); ++ ++ return 0; ++} ++ ++static int qca639x_probe(struct platform_device *pdev) ++{ ++ struct qca639x_data *data; ++ struct device *dev = &pdev->dev; ++ int i, ret; ++ ++ if (!dev->pins || IS_ERR_OR_NULL(dev->pins->default_state)) ++ return -EINVAL; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->dev = dev; ++ data->num_vregs = ARRAY_SIZE(vregs); ++ ++ data->active_state = pinctrl_lookup_state(dev->pins->p, "active"); ++ if (IS_ERR(data->active_state)) { ++ ret = PTR_ERR(data->active_state); ++ dev_err(dev, "Failed to get active_state: %d\n", ret); ++ return ret; ++ } ++ ++ for (i = 0; i < data->num_vregs; i++) ++ data->regulators[i].supply = vregs[i].name; ++ ret = devm_regulator_bulk_get(dev, data->num_vregs, data->regulators); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < data->num_vregs; i++) { ++ ret = regulator_set_load(data->regulators[i].consumer, vregs[i].load_uA); ++ if (ret) ++ return ret; ++ } ++ ++ data->pd.name = dev_name(dev); ++ data->pd.power_on = qca639x_power_on; ++ data->pd.power_off = qca639x_power_off; ++ ++ ret = pm_genpd_init(&data->pd, NULL, true); ++ if (ret < 0) ++ return ret; ++ ++ ret = of_genpd_add_provider_simple(dev->of_node, &data->pd); ++ if (ret < 0) { ++ pm_genpd_remove(&data->pd); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, data); ++ ++ return 0; ++} ++ ++static int qca639x_remove(struct platform_device *pdev) ++{ ++ struct qca639x_data *data = platform_get_drvdata(pdev); ++ ++ pm_genpd_remove(&data->pd); ++ ++ return 0; ++} ++ ++static const struct of_device_id qca639x_of_match[] = { ++ { .compatible = "qcom,qca639x" }, ++}; ++ ++static struct platform_driver qca639x_driver = { ++ .probe = qca639x_probe, ++ .remove = qca639x_remove, ++ .driver = { ++ .name = "qca639x", ++ .of_match_table = qca639x_of_match, ++ }, ++}; ++ ++module_platform_driver(qca639x_driver); ++MODULE_LICENSE("GPL v2"); +-- +2.39.2 + diff --git a/recipes-kernel/linux/linux-yocto/qca6390-driver/0003-mfd-qcom-qca639x-switch-to-platform-config-data.patch b/recipes-kernel/linux/linux-yocto/qca6390-driver/0003-mfd-qcom-qca639x-switch-to-platform-config-data.patch new file mode 100644 index 0000000..72458ef --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/qca6390-driver/0003-mfd-qcom-qca639x-switch-to-platform-config-data.patch @@ -0,0 +1,189 @@ +From bf19679f9a583a5bfd0cb711984fbe456af652fd Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Date: Sat, 26 Feb 2022 21:13:18 +0300 +Subject: [PATCH 3/5] mfd: qcom-qca639x: switch to platform config data + +Change qcom-qca639x to use platform config data, in preparation to +supporting other devices. + +Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Upstream-Status: Inappropriate +--- + drivers/mfd/qcom-qca639x.c | 74 +++++++++++++++++++++++--------------- + 1 file changed, 46 insertions(+), 28 deletions(-) + +diff --git a/drivers/mfd/qcom-qca639x.c b/drivers/mfd/qcom-qca639x.c +index b31e4b65bec5..22792561dbad 100644 +--- a/drivers/mfd/qcom-qca639x.c ++++ b/drivers/mfd/qcom-qca639x.c +@@ -1,4 +1,5 @@ + #include <linux/delay.h> ++#include <linux/gpio/consumer.h> + #include <linux/init.h> + #include <linux/kernel.h> + #include <linux/module.h> +@@ -6,15 +7,21 @@ + #include <linux/pinctrl/devinfo.h> + #include <linux/platform_device.h> + #include <linux/pm_domain.h> ++#include <linux/property.h> + #include <linux/regulator/consumer.h> + #include <linux/slab.h> + +-#define MAX_NUM_REGULATORS 8 +- +-static struct vreg { ++struct vreg { + const char *name; + unsigned int load_uA; +-} vregs [MAX_NUM_REGULATORS] = { ++}; ++ ++struct qca_cfg_data { ++ const struct vreg *vregs; ++ size_t num_vregs; ++}; ++ ++static const struct vreg qca6390_vregs[] = { + /* 2.0 V */ + { "vddpcie2", 15000 }, + { "vddrfa3", 400000 }, +@@ -32,19 +39,24 @@ static struct vreg { + { "vddio", 20000 }, + }; + +-struct qca639x_data { +- struct regulator_bulk_data regulators[MAX_NUM_REGULATORS]; ++static const struct qca_cfg_data qca6390_cfg_data = { ++ .vregs = qca6390_vregs, ++ .num_vregs = ARRAY_SIZE(qca6390_vregs), ++}; ++ ++struct qca_data { + size_t num_vregs; + struct device *dev; + struct pinctrl_state *active_state; + struct generic_pm_domain pd; ++ struct regulator_bulk_data regulators[]; + }; + +-#define domain_to_data(domain) container_of(domain, struct qca639x_data, pd) ++#define domain_to_data(domain) container_of(domain, struct qca_data, pd) + +-static int qca639x_power_on(struct generic_pm_domain *domain) ++static int qca_power_on(struct generic_pm_domain *domain) + { +- struct qca639x_data *data = domain_to_data(domain); ++ struct qca_data *data = domain_to_data(domain); + int ret; + + dev_warn(&domain->dev, "DUMMY POWER ON\n"); +@@ -70,9 +82,9 @@ static int qca639x_power_on(struct generic_pm_domain *domain) + return 0; + } + +-static int qca639x_power_off(struct generic_pm_domain *domain) ++static int qca_power_off(struct generic_pm_domain *domain) + { +- struct qca639x_data *data = domain_to_data(domain); ++ struct qca_data *data = domain_to_data(domain); + + dev_warn(&domain->dev, "DUMMY POWER OFF\n"); + +@@ -82,21 +94,26 @@ static int qca639x_power_off(struct generic_pm_domain *domain) + return 0; + } + +-static int qca639x_probe(struct platform_device *pdev) ++static int qca_probe(struct platform_device *pdev) + { +- struct qca639x_data *data; ++ const struct qca_cfg_data *cfg; ++ struct qca_data *data; + struct device *dev = &pdev->dev; + int i, ret; + ++ cfg = device_get_match_data(&pdev->dev); ++ if (!cfg) ++ return -EINVAL; ++ + if (!dev->pins || IS_ERR_OR_NULL(dev->pins->default_state)) + return -EINVAL; + +- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ data = devm_kzalloc(dev, struct_size(data, regulators, cfg->num_vregs), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; +- data->num_vregs = ARRAY_SIZE(vregs); ++ data->num_vregs = cfg->num_vregs; + + data->active_state = pinctrl_lookup_state(dev->pins->p, "active"); + if (IS_ERR(data->active_state)) { +@@ -106,20 +123,20 @@ static int qca639x_probe(struct platform_device *pdev) + } + + for (i = 0; i < data->num_vregs; i++) +- data->regulators[i].supply = vregs[i].name; ++ data->regulators[i].supply = cfg->vregs[i].name; + ret = devm_regulator_bulk_get(dev, data->num_vregs, data->regulators); + if (ret < 0) + return ret; + + for (i = 0; i < data->num_vregs; i++) { +- ret = regulator_set_load(data->regulators[i].consumer, vregs[i].load_uA); ++ ret = regulator_set_load(data->regulators[i].consumer, cfg->vregs[i].load_uA); + if (ret) + return ret; + } + + data->pd.name = dev_name(dev); +- data->pd.power_on = qca639x_power_on; +- data->pd.power_off = qca639x_power_off; ++ data->pd.power_on = qca_power_on; ++ data->pd.power_off = qca_power_off; + + ret = pm_genpd_init(&data->pd, NULL, true); + if (ret < 0) +@@ -136,27 +153,28 @@ static int qca639x_probe(struct platform_device *pdev) + return 0; + } + +-static int qca639x_remove(struct platform_device *pdev) ++static int qca_remove(struct platform_device *pdev) + { +- struct qca639x_data *data = platform_get_drvdata(pdev); ++ struct qca_data *data = platform_get_drvdata(pdev); + + pm_genpd_remove(&data->pd); + + return 0; + } + +-static const struct of_device_id qca639x_of_match[] = { +- { .compatible = "qcom,qca639x" }, ++static const struct of_device_id qca_of_match[] = { ++ { .compatible = "qcom,qca6390", .data = &qca6390_cfg_data }, ++ { }, + }; + +-static struct platform_driver qca639x_driver = { +- .probe = qca639x_probe, +- .remove = qca639x_remove, ++static struct platform_driver qca_driver = { ++ .probe = qca_probe, ++ .remove = qca_remove, + .driver = { + .name = "qca639x", +- .of_match_table = qca639x_of_match, ++ .of_match_table = qca_of_match, + }, + }; + +-module_platform_driver(qca639x_driver); ++module_platform_driver(qca_driver); + MODULE_LICENSE("GPL v2"); +-- +2.39.2 + diff --git a/recipes-kernel/linux/linux-yocto/qca6390-driver/0004-mfd-qcom-qca639x-change-qca639x-to-use-gpios-rather-.patch b/recipes-kernel/linux/linux-yocto/qca6390-driver/0004-mfd-qcom-qca639x-change-qca639x-to-use-gpios-rather-.patch new file mode 100644 index 0000000..4520e37 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/qca6390-driver/0004-mfd-qcom-qca639x-change-qca639x-to-use-gpios-rather-.patch @@ -0,0 +1,90 @@ +From 3f07b11f1bf49c153df0248de9128ffdad0792f8 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Date: Sat, 26 Feb 2022 21:17:22 +0300 +Subject: [PATCH 4/5] mfd: qcom-qca639x: change qca639x to use gpios rather + than pinctrl + +Use gpio interface instead of pinctrl interface to toggle enable pins. + +Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Upstream-Status: Inappropriate +--- + drivers/mfd/qcom-qca639x.c | 33 +++++++++++++++++++-------------- + 1 file changed, 19 insertions(+), 14 deletions(-) + +diff --git a/drivers/mfd/qcom-qca639x.c b/drivers/mfd/qcom-qca639x.c +index 22792561dbad..4de860e9bbd0 100644 +--- a/drivers/mfd/qcom-qca639x.c ++++ b/drivers/mfd/qcom-qca639x.c +@@ -47,8 +47,9 @@ static const struct qca_cfg_data qca6390_cfg_data = { + struct qca_data { + size_t num_vregs; + struct device *dev; +- struct pinctrl_state *active_state; + struct generic_pm_domain pd; ++ struct gpio_desc *wlan_en_gpio; ++ struct gpio_desc *bt_en_gpio; + struct regulator_bulk_data regulators[]; + }; + +@@ -70,11 +71,10 @@ static int qca_power_on(struct generic_pm_domain *domain) + /* Wait for 1ms before toggling enable pins. */ + msleep(1); + +- ret = pinctrl_select_state(data->dev->pins->p, data->active_state); +- if (ret) { +- dev_err(data->dev, "Failed to select active state"); +- return ret; +- } ++ if (data->wlan_en_gpio) ++ gpiod_set_value(data->wlan_en_gpio, 1); ++ if (data->bt_en_gpio) ++ gpiod_set_value(data->bt_en_gpio, 1); + + /* Wait for all power levels to stabilize */ + msleep(6); +@@ -88,7 +88,11 @@ static int qca_power_off(struct generic_pm_domain *domain) + + dev_warn(&domain->dev, "DUMMY POWER OFF\n"); + +- pinctrl_select_default_state(data->dev); ++ if (data->wlan_en_gpio) ++ gpiod_set_value(data->wlan_en_gpio, 0); ++ if (data->bt_en_gpio) ++ gpiod_set_value(data->bt_en_gpio, 0); ++ + regulator_bulk_disable(data->num_vregs, data->regulators); + + return 0; +@@ -115,13 +119,6 @@ static int qca_probe(struct platform_device *pdev) + data->dev = dev; + data->num_vregs = cfg->num_vregs; + +- data->active_state = pinctrl_lookup_state(dev->pins->p, "active"); +- if (IS_ERR(data->active_state)) { +- ret = PTR_ERR(data->active_state); +- dev_err(dev, "Failed to get active_state: %d\n", ret); +- return ret; +- } +- + for (i = 0; i < data->num_vregs; i++) + data->regulators[i].supply = cfg->vregs[i].name; + ret = devm_regulator_bulk_get(dev, data->num_vregs, data->regulators); +@@ -134,6 +131,14 @@ static int qca_probe(struct platform_device *pdev) + return ret; + } + ++ data->wlan_en_gpio = devm_gpiod_get_optional(&pdev->dev, "wlan-en", GPIOD_OUT_LOW); ++ if (IS_ERR(data->wlan_en_gpio)) ++ return PTR_ERR(data->wlan_en_gpio); ++ ++ data->bt_en_gpio = devm_gpiod_get_optional(&pdev->dev, "bt-en", GPIOD_OUT_LOW); ++ if (IS_ERR(data->bt_en_gpio)) ++ return PTR_ERR(data->bt_en_gpio); ++ + data->pd.name = dev_name(dev); + data->pd.power_on = qca_power_on; + data->pd.power_off = qca_power_off; +-- +2.39.2 + diff --git a/recipes-kernel/linux/linux-yocto/qca6390-driver/0005-mfd-qcom-qca639x-Add-support-for-WCN6855.patch b/recipes-kernel/linux/linux-yocto/qca6390-driver/0005-mfd-qcom-qca639x-Add-support-for-WCN6855.patch new file mode 100644 index 0000000..734e778 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/qca6390-driver/0005-mfd-qcom-qca639x-Add-support-for-WCN6855.patch @@ -0,0 +1,111 @@ +From 87c18e7aa2071dc0c95b76360671c3b3f2dcedec Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Date: Sat, 26 Feb 2022 21:52:08 +0300 +Subject: [PATCH 5/5] mfd: qcom-qca639x: Add support for WCN6855 + +Add support for powering up WCN6855 WiFi/BT chip. + +Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> +Upstream-Status: Inappropriate +--- + drivers/mfd/qcom-qca639x.c | 49 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/drivers/mfd/qcom-qca639x.c b/drivers/mfd/qcom-qca639x.c +index 4de860e9bbd0..16ff767a34b0 100644 +--- a/drivers/mfd/qcom-qca639x.c ++++ b/drivers/mfd/qcom-qca639x.c +@@ -44,10 +44,38 @@ static const struct qca_cfg_data qca6390_cfg_data = { + .num_vregs = ARRAY_SIZE(qca6390_vregs), + }; + ++static const struct vreg wcn6855_vregs[] = { ++ /* 2.8 V */ ++ { "vddasd" }, /* external antenna switch */ ++ ++ /* 0.95 V */ ++ { "vddaon" }, ++ { "vddcx" }, ++ { "vddmx" }, ++ ++ /* 1.9 V - 2.1 V */ ++ { "vddrfa1" }, ++ ++ /* 1.35 V */ ++ { "vddrfa2" }, ++ ++ /* 2.2 V, optional */ ++ { "vddrfa3" }, ++ ++ /* 1.8 V */ ++ { "vddio" }, ++}; ++ ++static const struct qca_cfg_data wcn6855_cfg_data = { ++ .vregs = wcn6855_vregs, ++ .num_vregs = ARRAY_SIZE(wcn6855_vregs), ++}; ++ + struct qca_data { + size_t num_vregs; + struct device *dev; + struct generic_pm_domain pd; ++ struct gpio_desc *xo_clk_gpio; + struct gpio_desc *wlan_en_gpio; + struct gpio_desc *bt_en_gpio; + struct regulator_bulk_data regulators[]; +@@ -71,11 +99,24 @@ static int qca_power_on(struct generic_pm_domain *domain) + /* Wait for 1ms before toggling enable pins. */ + msleep(1); + ++ if (data->xo_clk_gpio) { ++ gpiod_set_value(data->xo_clk_gpio, 1); ++ ++ /*XO CLK must be asserted for some time before WLAN_EN */ ++ usleep_range(100, 200); ++ } ++ + if (data->wlan_en_gpio) + gpiod_set_value(data->wlan_en_gpio, 1); + if (data->bt_en_gpio) + gpiod_set_value(data->bt_en_gpio, 1); + ++ if (data->xo_clk_gpio) { ++ /* Assert XO CLK ~(2-5)ms before off for valid latch in HW */ ++ usleep_range(2000, 5000); ++ gpiod_set_value(data->xo_clk_gpio, 0); ++ } ++ + /* Wait for all power levels to stabilize */ + msleep(6); + +@@ -126,11 +167,18 @@ static int qca_probe(struct platform_device *pdev) + return ret; + + for (i = 0; i < data->num_vregs; i++) { ++ if (!cfg->vregs[i].load_uA) ++ continue; ++ + ret = regulator_set_load(data->regulators[i].consumer, cfg->vregs[i].load_uA); + if (ret) + return ret; + } + ++ data->xo_clk_gpio = devm_gpiod_get_optional(&pdev->dev, "xo-clk", GPIOD_OUT_LOW); ++ if (IS_ERR(data->xo_clk_gpio)) ++ return PTR_ERR(data->xo_clk_gpio); ++ + data->wlan_en_gpio = devm_gpiod_get_optional(&pdev->dev, "wlan-en", GPIOD_OUT_LOW); + if (IS_ERR(data->wlan_en_gpio)) + return PTR_ERR(data->wlan_en_gpio); +@@ -169,6 +217,7 @@ static int qca_remove(struct platform_device *pdev) + + static const struct of_device_id qca_of_match[] = { + { .compatible = "qcom,qca6390", .data = &qca6390_cfg_data }, ++ { .compatible = "qcom,wcn6855", .data = &wcn6855_cfg_data }, + { }, + }; + +-- +2.39.2 + |