From 4b20d3b1bb32b8da6d202161c8c2e49eabf2429c Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Fri, 10 Jul 2026 17:52:48 +0800 Subject: [PATCH 1/5] FROMLIST: arm64: dts: qcom: shikra: Add WCN3988 PMU and fix WiFi/BT supply routing Align with latest upstream submission by adding the wcn3988-pmu node, routing bluetooth/wifi supplies through PMU child regulators, adding sw_ctrl pinctrl and bluetooth compatible to the shared dtsi, and fixing the wifi firmware-name to "shikra" across all EVK variants. Link: https://lore.kernel.org/all/20260714-shikra-dt-m1-v6-10-bee265d3499b@oss.qualcomm.com/ Signed-off-by: Komal Bajaj --- arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts | 24 +----- arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi | 74 ++++++++++++++++++ arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts | 24 +----- arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts | 40 ---------- arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi | 82 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/shikra.dtsi | 7 -- 6 files changed, 158 insertions(+), 93 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts index 5a8ec61e1c7cc..19861ef5daf51 100644 --- a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts @@ -21,7 +21,6 @@ mmc0 = &sdhc_1; mmc1 = &sdhc_2; /* SDC2 SD card slot */ serial0 = &uart0; - serial1 = &uart8; }; chosen { @@ -127,6 +126,7 @@ regulator-always-on; regulator-boot-on; }; + }; &audiocorecc { @@ -673,17 +673,6 @@ }; }; -&uart8 { - status = "okay"; - - bluetooth { - vddio-supply = <&pm4125_l7>; - vddxo-supply = <&pm4125_l13>; - vddrf-supply = <&pm4125_l10>; - vddch0-supply = <&pm4125_l22>; - }; -}; - &usb_1 { dr_mode = "otg"; @@ -720,14 +709,3 @@ qcom,dmic-sample-rate = <4800000>; status = "okay"; }; - -&wifi { - vdd-0.8-cx-mx-supply = <&pm4125_l7>; - vdd-1.8-xo-supply = <&pm4125_l13>; - vdd-1.3-rfa-supply = <&pm4125_l10>; - vdd-3.3-ch0-supply = <&pm4125_l22>; - qcom,calibration-variant = "Shikra_EVK"; - firmware-name = "cq2390"; - - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi index 9c87316444c80..e2bc4d4a2be8d 100644 --- a/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi @@ -12,6 +12,10 @@ #include "pm8005.dtsi" / { + aliases { + serial1 = &uart8; + }; + gpio-key { compatible = "gpio-keys"; label = "gpio-keys"; @@ -29,6 +33,42 @@ }; }; + wcn3988-pmu { + compatible = "qcom,wcn3988-pmu"; + + pinctrl-0 = <&sw_ctrl_default>; + pinctrl-names = "default"; + + swctrl-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&pm4125_l7>; + vddxo-supply = <&pm4125_l13>; + vddrf-supply = <&pm4125_l10>; + vddch0-supply = <&pm4125_l22>; + + regulators { + vreg_pmu_io: ldo0 { + regulator-name = "vreg_pmu_io"; + }; + + vreg_pmu_xo: ldo1 { + regulator-name = "vreg_pmu_xo"; + }; + + vreg_pmu_rf: ldo2 { + regulator-name = "vreg_pmu_rf"; + }; + + vreg_pmu_ch0: ldo3 { + regulator-name = "vreg_pmu_ch0"; + }; + + vreg_pmu_ch1: ldo4 { + regulator-name = "vreg_pmu_ch1"; + }; + }; + }; + pm4125_msm_therm_bridge: pm4125-msm-therm-bridge { compatible = "generic-adc-thermal"; io-channels = <&pm4125_adc ADC5_AMUX_THM3_100K_PU>; @@ -382,3 +422,37 @@ }; }; }; + +&tlmm { + sw_ctrl_default: sw-ctrl-default-state { + pins = "gpio88"; + function = "gpio"; + bias-pull-down; + }; +}; + +&uart8 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3988-bt"; + max-speed = <3200000>; + + vddio-supply = <&vreg_pmu_io>; + vddxo-supply = <&vreg_pmu_xo>; + vddrf-supply = <&vreg_pmu_rf>; + vddch0-supply = <&vreg_pmu_ch0>; + }; +}; + +&wifi { + vdd-0.8-cx-mx-supply = <&pm4125_l7>; + vdd-1.8-xo-supply = <&vreg_pmu_xo>; + vdd-1.3-rfa-supply = <&vreg_pmu_rf>; + vdd-3.3-ch0-supply = <&vreg_pmu_ch0>; + + qcom,calibration-variant = "Shikra_EVK"; + firmware-name = "shikra"; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts index 8c3cd39cbd238..09a1838e7566a 100644 --- a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts @@ -20,7 +20,6 @@ mmc0 = &sdhc_1; mmc1 = &sdhc_2; /* SDC2 SD card slot */ serial0 = &uart0; - serial1 = &uart8; }; chosen { @@ -109,6 +108,7 @@ regulator-always-on; regulator-boot-on; }; + }; &audiocorecc { @@ -595,17 +595,6 @@ }; }; -&uart8 { - status = "okay"; - - bluetooth { - vddio-supply = <&pm4125_l7>; - vddxo-supply = <&pm4125_l13>; - vddrf-supply = <&pm4125_l10>; - vddch0-supply = <&pm4125_l22>; - }; -}; - &usb_1 { dr_mode = "otg"; @@ -647,14 +636,3 @@ qcom,dmic-sample-rate = <4800000>; status = "okay"; }; - -&wifi { - vdd-0.8-cx-mx-supply = <&pm4125_l7>; - vdd-1.8-xo-supply = <&pm4125_l13>; - vdd-1.3-rfa-supply = <&pm4125_l10>; - vdd-3.3-ch0-supply = <&pm4125_l22>; - qcom,calibration-variant = "Shikra_EVK"; - firmware-name = "cq2390"; - - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts index 98ab8380a3178..eba4fdf7b71f1 100644 --- a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts +++ b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts @@ -19,7 +19,6 @@ mmc0 = &sdhc_1; mmc1 = &sdhc_2; /* SDC2 SD card slot */ serial0 = &uart0; - serial1 = &uart8; i2c3 = &i2c3; }; @@ -96,22 +95,6 @@ }; }; - vreg_bt_3p3_dummy: regulator-bt-3p3-dummy { - compatible = "regulator-fixed"; - regulator-name = "bt_3p3_dummy"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - - vreg_wlan_3p3_dummy: regulator-wlan-3p3-dummy { - compatible = "regulator-fixed"; - regulator-name = "wlan_3p3_dummy"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; - vreg_0p9: regulator-0v9 { compatible = "regulator-fixed"; regulator-name = "VREG_0P9"; @@ -131,7 +114,6 @@ regulator-always-on; regulator-boot-on; }; - }; ðernet0 { @@ -595,17 +577,6 @@ }; }; -&uart8 { - status = "okay"; - - bluetooth { - vddio-supply = <&pm8150_s4>; - vddxo-supply = <&pm8150_l12>; - vddrf-supply = <&pm8150_l8>; - vddch0-supply = <&vreg_bt_3p3_dummy>; - }; -}; - &usb_1 { dr_mode = "otg"; @@ -641,17 +612,6 @@ status = "okay"; }; -&wifi { - vdd-0.8-cx-mx-supply = <&pm8150_s4>; - vdd-1.8-xo-supply = <&pm8150_l12>; - vdd-1.3-rfa-supply = <&pm8150_l8>; - vdd-3.3-ch0-supply = <&vreg_wlan_3p3_dummy>; - qcom,calibration-variant = "Shikra_EVK"; - firmware-name = "cq2390"; - - status = "okay"; -}; - &tlmm { pcie_default_state: pcie-default-state { clkreq-pins { diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi b/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi index 9ab0b44b00bed..52a3152ae9445 100644 --- a/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi @@ -11,6 +11,10 @@ #include "pm8150.dtsi" / { + aliases { + serial1 = &uart8; + }; + gpio-key { compatible = "gpio-keys"; label = "gpio-keys"; @@ -28,6 +32,50 @@ }; }; + vreg_wcn_3p3: regulator-wcn-3p3 { + compatible = "regulator-fixed"; + regulator-name = "wcn_3p3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + wcn3988-pmu { + compatible = "qcom,wcn3988-pmu"; + + pinctrl-0 = <&sw_ctrl_default>; + pinctrl-names = "default"; + + swctrl-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&pm8150_s4>; + vddxo-supply = <&pm8150_l12>; + vddrf-supply = <&pm8150_l8>; + vddch0-supply = <&vreg_wcn_3p3>; + + regulators { + vreg_pmu_io: ldo0 { + regulator-name = "vreg_pmu_io"; + }; + + vreg_pmu_xo: ldo1 { + regulator-name = "vreg_pmu_xo"; + }; + + vreg_pmu_rf: ldo2 { + regulator-name = "vreg_pmu_rf"; + }; + + vreg_pmu_ch0: ldo3 { + regulator-name = "vreg_pmu_ch0"; + }; + + vreg_pmu_ch1: ldo4 { + regulator-name = "vreg_pmu_ch1"; + }; + }; + }; + thermal-zones { sys-1-thermal { thermal-sensors = <&pm8150_adc_tm 0>; @@ -281,3 +329,37 @@ }; }; }; + +&tlmm { + sw_ctrl_default: sw-ctrl-default-state { + pins = "gpio88"; + function = "gpio"; + bias-pull-down; + }; +}; + +&uart8 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3988-bt"; + max-speed = <3200000>; + + vddio-supply = <&vreg_pmu_io>; + vddxo-supply = <&vreg_pmu_xo>; + vddrf-supply = <&vreg_pmu_rf>; + vddch0-supply = <&vreg_pmu_ch0>; + }; +}; + +&wifi { + vdd-0.8-cx-mx-supply = <&pm8150_s4>; + vdd-1.8-xo-supply = <&vreg_pmu_xo>; + vdd-1.3-rfa-supply = <&vreg_pmu_rf>; + vdd-3.3-ch0-supply = <&vreg_pmu_ch0>; + + qcom,calibration-variant = "Shikra_EVK"; + firmware-name = "shikra"; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi index fd675f7ec47f3..d4f1831203dc5 100644 --- a/arch/arm64/boot/dts/qcom/shikra.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi @@ -2433,13 +2433,6 @@ pinctrl-names = "default"; status = "disabled"; - - bluetooth { - compatible = "qcom,wcn3988-bt"; - enable-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>; - max-speed = <3200000>; - }; - }; i2c9: i2c@4aa4000 { From c86e894efa4ef5561a10b6a11b7d42569354e4ee Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 6 Jan 2026 03:01:11 +0530 Subject: [PATCH 2/5] UPSTREAM: regulator: dt-bindings: qcom,wcn3990-pmu: describe PMUs on WCN39xx WCN3990 and other similar WiFi/BT chips incorporate a simple on-chip PMU (clearly described as such in the documentation). Provide DT schema covering other Qualcomm WiFi/BT chips to cover these devices too. Signed-off-by: Dmitry Baryshkov Acked-by: Mark Brown Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-1-0386204328be@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit a5fae429ec2ac72372bc874a0334a7fb9eadee83) (cherry picked from commit 7234b9c63b32bff89aa249d011e6bbbb553fbfce) --- .../bindings/regulator/qcom,wcn3990-pmu.yaml | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/qcom,wcn3990-pmu.yaml diff --git a/Documentation/devicetree/bindings/regulator/qcom,wcn3990-pmu.yaml b/Documentation/devicetree/bindings/regulator/qcom,wcn3990-pmu.yaml new file mode 100644 index 0000000000000..9a7abc878b831 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/qcom,wcn3990-pmu.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/qcom,wcn3990-pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. WCN3990 PMU Regulators + +maintainers: + - Bartosz Golaszewski + +description: + The WCN3990 package contains discrete modules for WLAN and Bluetooth. They + are powered by the Power Management Unit (PMU) that takes inputs from the + host and provides LDO outputs. This document describes this module. + +properties: + compatible: + enum: + - qcom,wcn3950-pmu + - qcom,wcn3988-pmu + - qcom,wcn3990-pmu + - qcom,wcn3991-pmu + - qcom,wcn3998-pmu + + vddio-supply: + description: VDD_IO supply regulator handle + + vddxo-supply: + description: VDD_XTAL supply regulator handle + + vddrf-supply: + description: VDD_RF supply regulator handle + + vddch0-supply: + description: chain 0 supply regulator handle + + vddch1-supply: + description: chain 1 supply regulator handle + + swctrl-gpios: + maxItems: 1 + description: GPIO line indicating the state of the clock supply to the BT module + + clocks: + maxItems: 1 + description: Reference clock handle + + regulators: + type: object + description: + LDO outputs of the PMU + + patternProperties: + "^ldo[0-9]$": + $ref: regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - regulators + - vddio-supply + - vddxo-supply + - vddrf-supply + - vddch0-supply + +additionalProperties: false + +examples: + - | + #include + pmu { + compatible = "qcom,wcn3990-pmu"; + + vddio-supply = <&vreg_io>; + vddxo-supply = <&vreg_xo>; + vddrf-supply = <&vreg_rf>; + vddch0-supply = <&vreg_ch0>; + + regulators { + vreg_pmu_io: ldo0 { + regulator-name = "vreg_pmu_io"; + }; + + vreg_pmu_xo: ldo1 { + regulator-name = "vreg_pmu_xo"; + }; + + vreg_pmu_rf: ldo2 { + regulator-name = "vreg_pmu_rf"; + }; + + vreg_pmu_ch0: ldo3 { + regulator-name = "vreg_pmu_ch0"; + }; + }; + }; From 082c72d2c3bc92dc74c005c8a412bd6266df7806 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 6 Jan 2026 03:01:15 +0200 Subject: [PATCH 3/5] UPSTREAM: power: sequencing: qcom-wcn: add support for WCN39xx The WCN39xx family of WiFi/BT chips incorporates a simple PMU, spreading voltages over internal rails. Implement power sequencing support for this generation of WCN chips. Unlike later devices, they don't have separate enable GPIO lines, letting the chip figure out the necessary parts on its own. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260106-wcn3990-pwrctl-v2-5-0386204328be@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit 0eb85f468ef515fbd2538375ef3884f6dd376382) (cherry picked from commit 92ad19f04c117367482dbec0405545caf7e79633) --- drivers/power/sequencing/pwrseq-qcom-wcn.c | 130 ++++++++++++++++++++- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index 916fa056025f5..1c80690c90ec4 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -23,6 +23,8 @@ struct pwrseq_qcom_wcn_pdata { unsigned int pwup_delay_ms; unsigned int gpio_enable_delay_ms; const struct pwrseq_target_data **targets; + bool has_vddio; /* separate VDD IO regulator */ + int (*match)(struct pwrseq_device *pwrseq, struct device *dev); }; struct pwrseq_qcom_wcn_ctx { @@ -30,6 +32,7 @@ struct pwrseq_qcom_wcn_ctx { struct device_node *of_node; const struct pwrseq_qcom_wcn_pdata *pdata; struct regulator_bulk_data *regs; + struct regulator *vddio; struct gpio_desc *bt_gpio; struct gpio_desc *wlan_gpio; struct gpio_desc *xo_clk_gpio; @@ -52,6 +55,26 @@ static void pwrseq_qcom_wcn_ensure_gpio_delay(struct pwrseq_qcom_wcn_ctx *ctx) msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs); } +static int pwrseq_qcom_wcn_vddio_enable(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + return regulator_enable(ctx->vddio); +} + +static int pwrseq_qcom_wcn_vddio_disable(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + return regulator_disable(ctx->vddio); +} + +static const struct pwrseq_unit_data pwrseq_qcom_wcn_vddio_unit_data = { + .name = "vddio-enable", + .enable = pwrseq_qcom_wcn_vddio_enable, + .disable = pwrseq_qcom_wcn_vddio_disable, +}; + static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -94,6 +117,19 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_clk_unit_data = { .disable = pwrseq_qcom_wcn_clk_disable, }; +static const struct pwrseq_unit_data *pwrseq_qcom_wcn3990_unit_deps[] = { + &pwrseq_qcom_wcn_vddio_unit_data, + &pwrseq_qcom_wcn_vregs_unit_data, + NULL, +}; + +static const struct pwrseq_unit_data pwrseq_qcom_wcn3990_unit_data = { + .name = "clock-enable", + .deps = pwrseq_qcom_wcn3990_unit_deps, + .enable = pwrseq_qcom_wcn_clk_enable, + .disable = pwrseq_qcom_wcn_clk_disable, +}; + static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = { &pwrseq_qcom_wcn_vregs_unit_data, &pwrseq_qcom_wcn_clk_unit_data, @@ -229,6 +265,17 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = { .post_enable = pwrseq_qcom_wcn_pwup_delay, }; +/* There are no separate BT and WLAN enablement pins */ +static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = { + .name = "bluetooth", + .unit = &pwrseq_qcom_wcn3990_unit_data, +}; + +static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = { + .name = "wlan", + .unit = &pwrseq_qcom_wcn3990_unit_data, +}; + static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = { .name = "bluetooth", .unit = &pwrseq_qcom_wcn6855_bt_unit_data, @@ -247,6 +294,12 @@ static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = { NULL }; +static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = { + &pwrseq_qcom_wcn3990_bt_target_data, + &pwrseq_qcom_wcn3990_wlan_target_data, + NULL +}; + static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = { &pwrseq_qcom_wcn6855_bt_target_data, &pwrseq_qcom_wcn6855_wlan_target_data, @@ -272,6 +325,26 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = { .targets = pwrseq_qcom_wcn_targets, }; +static const char *const pwrseq_wcn3990_vregs[] = { + /* vddio is handled separately */ + "vddxo", + "vddrf", + "vddch0", + "vddch1", +}; + +static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq, + struct device *dev); + +static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = { + .vregs = pwrseq_wcn3990_vregs, + .num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs), + .pwup_delay_ms = 50, + .targets = pwrseq_qcom_wcn3990_targets, + .has_vddio = true, + .match = pwrseq_qcom_wcn3990_match, +}; + static const char *const pwrseq_wcn6750_vregs[] = { "vddaon", "vddasd", @@ -328,8 +401,9 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = { .targets = pwrseq_qcom_wcn_targets, }; -static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, - struct device *dev) +static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq, + struct device *dev, + const char *name) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); struct device_node *dev_node = dev->of_node; @@ -340,11 +414,11 @@ static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, * 'vddaon-supply' property and whether it leads us to the right * device. */ - if (!of_property_present(dev_node, "vddaon-supply")) + if (!of_property_present(dev_node, name)) return PWRSEQ_NO_MATCH; struct device_node *reg_node __free(device_node) = - of_parse_phandle(dev_node, "vddaon-supply", 0); + of_parse_phandle(dev_node, name, 0); if (!reg_node) return PWRSEQ_NO_MATCH; @@ -374,6 +448,26 @@ static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, return PWRSEQ_MATCH_OK; } +static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, + struct device *dev) +{ + return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply"); +} + +static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq, + struct device *dev) +{ + int ret; + + /* BT device */ + ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply"); + if (ret == PWRSEQ_MATCH_OK) + return ret; + + /* WiFi device match */ + return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply"); +} + static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -405,6 +499,12 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to get all regulators\n"); + if (ctx->pdata->has_vddio) { + ctx->vddio = devm_regulator_get(dev, "vddio"); + if (IS_ERR(ctx->vddio)) + return dev_err_probe(dev, ret, "Failed to get VDDIO\n"); + } + ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW); if (IS_ERR(ctx->bt_gpio)) return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio), @@ -446,7 +546,7 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) config.parent = dev; config.owner = THIS_MODULE; config.drvdata = ctx; - config.match = pwrseq_qcom_wcn_match; + config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match; config.targets = ctx->pdata->targets; ctx->pwrseq = devm_pwrseq_device_register(dev, &config); @@ -458,6 +558,26 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) } static const struct of_device_id pwrseq_qcom_wcn_of_match[] = { + { + .compatible = "qcom,wcn3950-pmu", + .data = &pwrseq_wcn3990_of_data, + }, + { + .compatible = "qcom,wcn3988-pmu", + .data = &pwrseq_wcn3990_of_data, + }, + { + .compatible = "qcom,wcn3990-pmu", + .data = &pwrseq_wcn3990_of_data, + }, + { + .compatible = "qcom,wcn3991-pmu", + .data = &pwrseq_wcn3990_of_data, + }, + { + .compatible = "qcom,wcn3998-pmu", + .data = &pwrseq_wcn3990_of_data, + }, { .compatible = "qcom,qca6390-pmu", .data = &pwrseq_qca6390_of_data, From 3308419df1eede47e8ef2ff295c825396caebec7 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 11 Mar 2026 01:02:58 +0530 Subject: [PATCH 4/5] UPSTREAM: Bluetooth: qca: enable pwrseq support for WCN39xx devices The WCN39xx family of WiFi/BT chips incorporates a simple PMU, spreading voltages over internal rails. Implement support for using powersequencer for this family of QCA devices in addition to using regulators. Reviewed-by: Bartosz Golaszewski Signed-off-by: Dmitry Baryshkov Signed-off-by: Luiz Augusto von Dentz Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9f168e4de5fd43766f6d49b393f445be805c1e05 (cherry picked from commit 9f168e4de5fd43766f6d49b393f445be805c1e05) --- drivers/bluetooth/hci_qca.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 5d1730e58e47b..67bf0df8bed71 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2254,6 +2254,18 @@ static void qca_power_shutdown(struct hci_uart *hu) qcadev = serdev_device_get_drvdata(hu->serdev); power = qcadev->bt_power; + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + host_set_baudrate(hu, 2400); + qca_send_power_pulse(hu, false); + break; + default: + break; + } + if (power && power->pwrseq) { pwrseq_power_off(power->pwrseq); set_bit(QCA_BT_OFF, &qca->flags); @@ -2265,8 +2277,6 @@ static void qca_power_shutdown(struct hci_uart *hu) case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - host_set_baudrate(hu, 2400); - qca_send_power_pulse(hu, false); qca_regulator_disable(qcadev); break; @@ -2441,6 +2451,11 @@ static int qca_serdev_probe(struct serdev_device *serdev) switch (qcadev->btsoc_type) { case QCA_QCC2072: + case QCA_WCN3950: + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: case QCA_WCN6855: case QCA_WCN7850: case QCA_WCN6750: @@ -2465,12 +2480,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) else break; } - fallthrough; - case QCA_WCN3950: - case QCA_WCN3988: - case QCA_WCN3990: - case QCA_WCN3991: - case QCA_WCN3998: + qcadev->bt_power->dev = &serdev->dev; err = qca_init_regulators(qcadev->bt_power, data->vregs, data->num_vregs); From bc49a085ab41c092fec1c7fd1fa73acf4e4a560c Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Fri, 10 Jul 2026 17:53:22 +0800 Subject: [PATCH 5/5] WORKAROUND: power: sequencing: qcom-wcn: skip BT devices without bt-enable GPIO Add a bt_gpio_required flag to the per-platform data to indicate that a chip's BT enable path requires a dedicated GPIO. Only skip matching the "bluetooth" device node when this flag is set and bt_gpio is absent. Previously the bt_gpio check was applied unconditionally, which caused chips like WCN3990 that have no separate BT/WLAN enable pins by design to fail matching even when bt-enable GPIO is legitimately absent from the DT. Set bt_gpio_required for WCN6855 and WCN7850 which do require a dedicated BT enable GPIO. CRs-Fixed: 4602678 Signed-off-by: Shuai Zhang --- drivers/power/sequencing/pwrseq-qcom-wcn.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index 1c80690c90ec4..7e749ca0c2313 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -23,6 +23,7 @@ struct pwrseq_qcom_wcn_pdata { unsigned int pwup_delay_ms; unsigned int gpio_enable_delay_ms; const struct pwrseq_target_data **targets; + bool bt_gpio_required; /* BT enable path requires a dedicated GPIO */ bool has_vddio; /* separate VDD IO regulator */ int (*match)(struct pwrseq_device *pwrseq, struct device *dev); }; @@ -382,6 +383,7 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6855_of_data = { .pwup_delay_ms = 50, .gpio_enable_delay_ms = 5, .targets = pwrseq_qcom_wcn6855_targets, + .bt_gpio_required = true, }; static const char *const pwrseq_wcn7850_vregs[] = { @@ -399,6 +401,7 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = { .num_vregs = ARRAY_SIZE(pwrseq_wcn7850_vregs), .pwup_delay_ms = 50, .targets = pwrseq_qcom_wcn_targets, + .bt_gpio_required = true, }; static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq, @@ -432,17 +435,20 @@ static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq, return PWRSEQ_NO_MATCH; /* - * If this is a Bluetooth consumer device but the bt-enable GPIO is not - * configured in the power sequencer (e.g. BT_EN is tied high via a - * hardware pull-up and therefore absent from the DT), don't match. - * The consumer driver will fall back to its legacy power control path - * and correctly set power_ctrl_enabled to false. + * If this chip requires a dedicated BT enable GPIO (bt_gpio_required) + * but the bt-enable GPIO is not configured in the power sequencer + * (e.g. BT_EN is tied high via a hardware pull-up and therefore absent + * from the DT), don't match. The consumer driver will fall back to its + * legacy power control path and correctly set power_ctrl_enabled to + * false. Chips like WCN3990 have no separate BT/WLAN enable pins by + * design, so the flag is left unset for them and matching proceeds. * * BT device nodes are conventionally named "bluetooth" in the DT, * so use of_node_name_eq() as a generic check rather than enumerating * specific compatible strings. */ - if (!ctx->bt_gpio && of_node_name_eq(dev_node, "bluetooth")) + if (ctx->pdata->bt_gpio_required && !ctx->bt_gpio && + of_node_name_eq(dev_node, "bluetooth")) return PWRSEQ_NO_MATCH; return PWRSEQ_MATCH_OK;