From 0d9f16382e3cc9b33d15d0187acba7236200a76d Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Wed, 11 Mar 2026 18:12:12 +0800 Subject: [PATCH 1/2] FROMLIST: arm64: dts: qcom: hamoa-iot-evk: support Bluetooth over both USB and UART When Bluetooth supports both USB and UART, the BT UART driver is always loaded, while USB is hot-pluggable. As a result, when Bluetooth is used over USB, the UART driver still be probed and drive BT_EN low, which causes the Bluetooth device on USB to be disconnected. Configure BT_EN as a GPIO hog so that it is controlled by the platform instead of the UART driver, preventing BT over USB from being unintentionally powered down. Link: https://lore.kernel.org/all/20260311090921.1892191-1-shuai.zhang@oss.qualcomm.com/ Signed-off-by: Shuai Zhang --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index e9d8a2890541a..4f82e80f700a4 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -620,10 +620,9 @@ vddrfa1p2-supply = <&vreg_wcn_1p9>; vddrfa1p8-supply = <&vreg_wcn_1p9>; - bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>; wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; - pinctrl-0 = <&wcn_bt_en>, <&wcn_wlan_en>; + pinctrl-0 = <&wcn_wlan_en>; pinctrl-names = "default"; regulators { @@ -1315,11 +1314,12 @@ output-low; }; - wcn_bt_en: wcn-bt-en-state { - pins = "gpio116"; - function = "gpio"; - drive-strength = <2>; - bias-disable; + wcn_bt_en_hog: wcn-bt-en-state-hog { + gpio-hog; + gpios = <116 GPIO_ACTIVE_HIGH>; + output-high; + input-disable; + line-name = "BT_EN"; }; wcn_wlan_en: wcn-wlan-en-state { From 227eb0cbad9b3dc7a34530153ef97524c2abbd8e Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Wed, 18 Mar 2026 15:59:07 +0800 Subject: [PATCH 2/2] QCLINUX: Bluetooth: support Bluetooth over both USB and UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Hamoa boards, a single M.2 slot may host either a UART-based Bluetooth card or a USB-based Bluetooth card. As a result, the UART controller node is always present in the device tree, while the USB Bluetooth path is hot‑pluggable. When Bluetooth is actually used over USB, the hci_qca UART driver still probes due to the DT node being present. During probe/power sequencing it drive BT_EN low (either directly or via the WCN power sequencer), which can cut power to the shared Bluetooth device and cause the USB Bluetooth interface to disconnect. Model BT_EN as an always-on fixed regulator and ensure the UART path does not claim power control when BT_EN is not described for that consumer: - Describe BT_EN as a fixed regulator (GPIO 116) that is boot-on and always-on, so it cannot be inadvertently deasserted by the UART probe. - Remove bt-enable-gpios from the WCN7850 power sequencer node and drop its BT pinctrl entry. - Wire the bluetooth DT supplies to the always-on 3.3V rail so the UART driver can acquire its regulators without depending on the WCN PMU regulators in this dual-path configuration. - Treat WCN7850 like WCN6750/WCN6855 in hci_qca: if no bt_en GPIO is provided for the UART device, disable power control for that instance. - In pwrseq-qcom-wcn, do not match a "bluetooth" consumer if the sequencer has no bt-enable GPIO configured. This prevents the sequencer from binding to a bluetooth consumer node in the "BT_EN tied high / absent from DT" case and allows the consumer to fall back accordingly. With these changes, probing the UART path no longer deasserts BT_EN when Bluetooth is operating over USB, avoiding unexpected USB disconnects. Signed-off-by: Shuai Zhang --- arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 42 +++++++++++++++------- drivers/bluetooth/hci_qca.c | 3 +- drivers/power/sequencing/pwrseq-qcom-wcn.c | 14 ++++++++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts index 4f82e80f700a4..33beb81e12cdc 100644 --- a/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts +++ b/arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts @@ -470,6 +470,23 @@ vin-supply = <&vreg_wcn_3p3>; }; + vreg_wcn_bt_en: regulator-wcn-bt-en { + compatible = "regulator-fixed"; + + regulator-name = "VREG_WCN_BT_EN"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + gpio = <&tlmm 116 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&wcn_bt_en>; + pinctrl-names = "default"; + + regulator-always-on; + regulator-boot-on; + }; + vreg_wcn_3p3: regulator-wcn-3p3 { compatible = "regulator-fixed"; @@ -1314,12 +1331,11 @@ output-low; }; - wcn_bt_en_hog: wcn-bt-en-state-hog { - gpio-hog; - gpios = <116 GPIO_ACTIVE_HIGH>; - output-high; - input-disable; - line-name = "BT_EN"; + wcn_bt_en: wcn-bt-en-state { + pins = "gpio116"; + function = "gpio"; + drive-strength = <2>; + bias-disable; }; wcn_wlan_en: wcn-wlan-en-state { @@ -1360,13 +1376,13 @@ compatible = "qcom,wcn7850-bt"; max-speed = <3200000>; - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; - vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; - vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; - vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; - vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddrfacmn-supply = <&vreg_wcn_3p3>; + vddaon-supply = <&vreg_wcn_3p3>; + vddwlcx-supply = <&vreg_wcn_3p3>; + vddwlmx-supply = <&vreg_wcn_3p3>; + vddrfa0p8-supply = <&vreg_wcn_3p3>; + vddrfa1p2-supply = <&vreg_wcn_3p3>; + vddrfa1p8-supply = <&vreg_wcn_3p3>; }; }; diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index c0cc04995fc2f..56663f6717311 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2467,7 +2467,8 @@ static int qca_serdev_probe(struct serdev_device *serdev) if (!qcadev->bt_en && (data->soc_type == QCA_WCN6750 || - data->soc_type == QCA_WCN6855)) + data->soc_type == QCA_WCN6855 || + data->soc_type == QCA_WCN7850)) power_ctrl_enabled = false; qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index 663d9a5370653..6ad6d999a7039 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -357,6 +357,20 @@ static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, reg_node->parent->parent != ctx->of_node) 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. + * + * 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")) + return PWRSEQ_NO_MATCH; + return PWRSEQ_MATCH_OK; }