From 7fba2107cd263b191a54da696015d81387fa3e0e 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 0768ba6b0c39b7fc4932dc832768b615524fc9e7 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 fcc141e067b9..f61a0dc9defe 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1079,6 +1079,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 2f6c89d1e277..fdac433ecfb7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -196,6 +196,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 dc8e79d740abceccb74a68c073686f8b2d56ee9e 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 78049752da7b265cc07bd661de1c4cf7eacdf76e 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 303a67a4c0bef9ee5111c5759c5de3e268728788 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 282a8233c1f1755a403472ca9af6207d5eb1426c 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 aa0a7bd7307c..1e2fe1f5bcac 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -230,6 +230,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 { @@ -1243,6 +1263,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 ca5897a5772f8df6ca3ac8830403d18432867043 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 1e2fe1f5bcac..2e4c660c2f0f 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -22,6 +22,7 @@ aliases { serial0 = &uart12; + serial1 = &uart6; sdhc2 = &sdhc_2; }; @@ -1232,6 +1233,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-state { pins = "gpio63"; function = "gpio"; @@ -1276,6 +1288,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 0d54bf5e11f7a0a3537d26d44e100e079a976941 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 2e4c660c2f0f..1bcb1ddcb86b 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -704,6 +704,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 3de6eeb15f149213465859c1a656f1b9fc9e2d08 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 3df8c3606e93..5a538bfd127e 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1866,6 +1866,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 []) { @@ -2171,7 +2177,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) { if (test_bit(QCA_BT_OFF, &qca->flags) || !test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -2335,6 +2342,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 4bbec77592e56a423bcf3a00583f79b22cdb6a00 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 5a538bfd127e..e71c373e7e5c 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1690,6 +1690,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