[PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices

From: Manivannan Sadhasivam via B4 Relay

Date: Wed Apr 22 2026 - 07:29:48 EST


From: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxxxxxxxx>

Commit 'db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT
driver")' tried to check the presence of the BT_EN GPIO in Qcom WCN devices
to indicate the HCI layer whether this BT device can be power controlled or
not.

But it was broken for two reasons:

1. Assumes that when devm_pwrseq_get() API returns an error, BT_EN is not
controllable. This is no way true as the API can fail for various reasons
and also the pwrseq-qcom-wcn driver treats the BT_EN GPIO as optional. So
even if the GPIO is not present, it will not fail the probe and this API
will not fail.

2. By skipping the error return, probe deferral is completely broken as the
API may return -EPROBE_DEFER to indicate the caller that the pwrseq driver
is not yet probed. Skipping the return value means, this driver is not
going to depend on pwrseq driver probing again and it just assumes that
the pwrseq is not available.

So to fix these issues, fail the probe if devm_pwrseq_get() returns an
error and if it succeeds, use the newly introduced pwrseq_is_fixed() API to
check whether the power sequencer is fixed or not (i.e., whether the
Bluetooth interface on the Qcom WCN device is controllable using BT_EN GPIO
or not) and set the 'bt_en_available' flag accordingly.

Cc: <stable+noautosel@xxxxxxxxxx> # Depends on pwrseq change
Fixes: db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxxxxxxxx>
---
drivers/bluetooth/hci_qca.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 27e52b08ec47..dd1d93cbb3d8 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2470,16 +2470,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
"bluetooth");

- /*
- * Some modules have BT_EN enabled via a hardware pull-up,
- * meaning it is not defined in the DTS and is not controlled
- * through the power sequence. In such cases, fall through
- * to follow the legacy flow.
- */
if (IS_ERR(qcadev->bt_power->pwrseq))
- qcadev->bt_power->pwrseq = NULL;
- else
- break;
+ return PTR_ERR(qcadev->bt_power->pwrseq);
+
+ if (pwrseq_is_fixed(qcadev->bt_power->pwrseq))
+ bt_en_available = false;
+
+ break;
}

qcadev->bt_power->dev = &serdev->dev;

--
2.51.0