From 595d35aaf430011bbee490f5f1132029642d477a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 20 Dec 2020 18:47:57 +0300 Subject: 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 --- .../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 + - Bjorn Andersson + +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>; + }; +... -- cgit v1.2.3 From afb4fb3ee15f2f6eb5243606c6df29d56a924131 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 18 Dec 2020 16:24:56 +0300 Subject: 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 --- 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 ba0b3eb131f1..da22a4d1aa05 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1052,6 +1052,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 df1ecc4a4c95..34772423c5e0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -198,6 +198,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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); -- cgit v1.2.3 From 10a4409b524404c58a1d2ca0e6247e5a563eb018 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 26 Feb 2022 21:13:18 +0300 Subject: 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 --- 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 +#include #include #include #include @@ -6,15 +7,21 @@ #include #include #include +#include #include #include -#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"); -- cgit v1.2.3 From 770608fced61b5e73ea67b9d39a53032a2276c9a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 26 Feb 2022 21:17:22 +0300 Subject: 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 --- 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; -- cgit v1.2.3 From f67bb6fadc85ae67b63302805fed06248f86ee1d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 26 Feb 2022 21:52:08 +0300 Subject: mfd: qcom-qca639x: Add support for WCN6855 Add support for powering up WCN6855 WiFi/BT chip. Signed-off-by: Dmitry Baryshkov --- 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 }, { }, }; -- cgit v1.2.3 From 786d29c9af6f9eade0853d72713e7b7601d3bfec Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 20 Dec 2020 02:44:08 +0300 Subject: arm64: dts: qcom: qrb5165-rb5: add qca639x power domain Add QCA639x power sequencing device to be used as power domain for respective bluetooth and WiFi devices. Signed-off-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 845eb7a6bf92..4fbfad661fa9 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -224,6 +224,26 @@ regulator-max-microvolt = <1800000>; regulator-always-on; }; + + qca639x: qca639x { + compatible = "qcom,qca6390"; + #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"; + pinctrl-0 = <&wlan_en_state>; + + wlan-en-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; + }; + }; &adsp { @@ -1203,6 +1223,17 @@ function = "gpio"; bias-pull-up; }; + + wlan_en_state: wlan-default-state { + wlan-en { + pins = "gpio20"; + function = "gpio"; + + drive-strength = <16>; + output-low; + bias-pull-up; + }; + }; }; &uart12 { -- cgit v1.2.3 From 619ed4ee2e6909915f6b41480b24e7a90dae63dc Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 2 Sep 2020 09:03:29 +0530 Subject: arm64: dts: qcom: Add Bluetooth support on RB5 Add Bluetooth support on RB5 using the onboard QCA6391 WLAN+BT chipset. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 4fbfad661fa9..752a393c8acd 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -21,6 +21,7 @@ aliases { serial0 = &uart12; + serial1 = &uart6; sdhc2 = &sdhc_2; }; @@ -1192,6 +1193,17 @@ "HST_WLAN_UART_TX", "HST_WLAN_UART_RX"; + bt_en_state: bt-default-state { + bt-en { + pins = "gpio21"; + function = "gpio"; + + drive-strength = <16>; + output-low; + bias-pull-up; + }; + }; + lt9611_irq_pin: lt9611-irq { pins = "gpio63"; function = "gpio"; @@ -1236,6 +1248,18 @@ }; }; +&uart6 { + status = "okay"; + bluetooth { + compatible = "qcom,qca6390-bt"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_state>; + + power-domains = <&qca639x>; + enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + }; +}; + &uart12 { status = "okay"; }; -- cgit v1.2.3 From bbeac6225527cfc2d90403e6d38a35f0beb86c29 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 20 Dec 2020 03:17:50 +0300 Subject: arm64: dtb: qcom: qrb5165-rb5: add power domain to pcie0 phy If QCA6391 chip (connected to PCIe0) is not powered at the PCIe probe time, PCIe0 bus probe will timeout and the device will not be detected. To ease device power up support, use qca639x as pcie0 phy power-domain. This allows us to make sure that QCA6391 chip is powered on before PCIe0 probe happens. Signed-off-by: Dmitry Baryshkov --- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 752a393c8acd..2eeeed11f8f6 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -698,6 +698,9 @@ status = "okay"; vdda-phy-supply = <&vreg_l5a_0p88>; vdda-pll-supply = <&vreg_l9a_1p2>; + + /* Power on QCA639x chip, otherwise PCIe bus timeouts */ + power-domains = <&qca639x>; }; &pcie1 { -- cgit v1.2.3 From 57018e106fc993c8a404ec19e1d65c77c70e7dc5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 26 Feb 2022 23:03:31 +0300 Subject: Bluetooth: btqca: add support for WCN6855 Add initial support for WCN6855 chip used over UART. Some features might be disabled. Signed-off-by: Dmitry Baryshkov --- drivers/bluetooth/btqca.c | 8 +++++++- drivers/bluetooth/btqca.h | 1 + drivers/bluetooth/hci_qca.c | 10 +++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index c9064d34d830..0150fe169cad 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -614,6 +614,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, config.type = ELF_TYPE_PATCH; snprintf(config.fwname, sizeof(config.fwname), "qca/msbtfw%02x.mbn", rom_ver); + } else if (soc_type == QCA_WCN6855) { + snprintf(config.fwname, sizeof(config.fwname), + "qca/hpbtfw%02x.tlv", rom_ver); } else { snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin", soc_ver); @@ -648,6 +651,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, else if (soc_type == QCA_WCN6750) snprintf(config.fwname, sizeof(config.fwname), "qca/msnv%02x.bin", rom_ver); + else if (soc_type == QCA_WCN6855) + snprintf(config.fwname, sizeof(config.fwname), + "qca/hpnv%02x.bin", rom_ver); else snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin", soc_ver); @@ -685,7 +691,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, return err; } - if (soc_type == QCA_WCN3991 || soc_type == QCA_WCN6750) { + if (soc_type == QCA_WCN3991 || soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) { /* get fw build info */ err = qca_read_fw_build_info(hdev); if (err < 0) diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 61e9a50e66ae..928fd4d6b10c 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -147,6 +147,7 @@ enum qca_btsoc_type { QCA_WCN3991, QCA_QCA6390, QCA_WCN6750, + QCA_WCN6855, }; #if IS_ENABLED(CONFIG_BT_QCA) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index f6e91fb432a3..140a0a421bcf 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1858,6 +1858,12 @@ static const struct qca_device_data qca_soc_data_qca6390 = { .num_vregs = 0, }; +static const struct qca_device_data qca_soc_data_wcn6855 = { + .soc_type = QCA_WCN6855, + .num_vregs = 0, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, +}; + static const struct qca_device_data qca_soc_data_wcn6750 = { .soc_type = QCA_WCN6750, .vregs = (struct qca_vreg []) { @@ -2160,7 +2166,8 @@ static void qca_serdev_shutdown(struct device *dev) const u8 ibs_wake_cmd[] = { 0xFD }; const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 }; - if (qcadev->btsoc_type == QCA_QCA6390) { + if (qcadev->btsoc_type == QCA_QCA6390 || + qcadev->btsoc_type == QCA_WCN6855) { serdev_device_write_flush(serdev); ret = serdev_device_write_buf(serdev, ibs_wake_cmd, sizeof(ibs_wake_cmd)); @@ -2320,6 +2327,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = { { .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991}, { .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998}, { .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750}, + { .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match); -- cgit v1.2.3 From 609262bec9ed01640258d5ccfa1853dfd7234e56 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 26 Feb 2022 23:07:54 +0300 Subject: Bluetooth: hci_qca: reopen serial port after toggling power Reopen the serial port after toggling the power. This saves us from getting command timeouts on first command submitted. Signed-off-by: Dmitry Baryshkov --- drivers/bluetooth/hci_qca.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 140a0a421bcf..b32e358fcf96 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1683,6 +1683,8 @@ static int qca_power_on(struct hci_dev *hdev) gpiod_set_value_cansleep(qcadev->bt_en, 1); /* Controller needs time to bootup. */ msleep(150); + serdev_device_close(hu->serdev); + ret = serdev_device_open(hu->serdev); } } -- cgit v1.2.3