* [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
@ 2026-11-10 9:29 Shuai Zhang
2026-11-10 9:29 ` [PATCH v4 1/2] " Shuai Zhang
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Shuai Zhang @ 2026-11-10 9:29 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
xiuzhuo.shang, wei.deng, jinwang.li, Shuai Zhang
QCA2066 does not reopen the UART after the controller is enabled, which
causes RX/TX out-of-sync errors. The UART has to be reopened once the
controller is powered on.
qca_regulator_init() already enables the controller and then reopens the
UART, but QCA2066 does not go through it. QCA2066 was added with its own
SoC type and handled in the default case.
Let QCA2066 go through qca_regulator_init() as well, and handle it in the
other places that check the SoC type in the same way.
Patch 1 reopens the UART after enabling QCA2066.
Patch 2 keeps HCI_UART_PROTO_READY in sync with the port state, so that a
port which failed to reopen is not closed or flushed again.
Changes in v4:
- Let QCA2066 go through qca_regulator_init() instead of adding a QCA2066
specific case.
- Link to v3
https://lore.kernel.org/all/20261028111839.2148515-1-shuai.zhang@oss.qualcomm.com/
Changes in v3:
- Patch 1 is unchanged from v2.
- Add patch 2. If serdev_device_open() fails during the reopen, the
port stays closed but HCI_UART_PROTO_READY stays set, so the later
serdev_device_close() and hci_uart_flush() use a closed port. Keep
the flag in sync with the port state and skip the port flush when
the port is not open.
- Link to v2:
https://lore.kernel.org/all/20261016022302.4003647-1-shuai.zhang@oss.qualcomm.com/
Changes in v2:
- Use a separate case for clearer logic.
- Link to v1:
https://lore.kernel.org/all/20261015092224.262158-1-shuai.zhang@oss.qualcomm.com/
Shuai Zhang (2):
Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
Bluetooth: hci_qca: Don't use the serdev port after a failed reopen
drivers/bluetooth/btqca.c | 1 +
drivers/bluetooth/hci_qca.c | 46 +++++++++++++++++++++++++++++-----
drivers/bluetooth/hci_serdev.c | 6 +++--
3 files changed, 45 insertions(+), 8 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
2026-11-10 9:29 [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Shuai Zhang
@ 2026-11-10 9:29 ` Shuai Zhang
2026-11-10 13:52 ` Bartosz Golaszewski
2026-11-10 9:29 ` [PATCH v4 2/2] Bluetooth: hci_qca: Don't use the serdev port after a failed reopen Shuai Zhang
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Shuai Zhang @ 2026-11-10 9:29 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
xiuzhuo.shang, wei.deng, jinwang.li, Shuai Zhang
QCA2066 does not reopen the UART after the controller is enabled, which
causes RX/TX out-of-sync errors. The UART has to be reopened once the
controller is powered on.
qca_regulator_init() already enables the controller and then reopens the
UART, but QCA2066 does not go through it. QCA2066 was added with its own
SoC type and handled in the default case.
Let QCA2066 go through qca_regulator_init() as well, and handle it in the
other places that check the SoC type in the same way. This also applies
the baudrate switching, flow control, shutdown and probe handling of
those chips to QCA2066. btqca.c checks the SoC type in the same way, so
the firmware version is also shown in the log.
Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 1 +
drivers/bluetooth/hci_qca.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 60735b70d..9f54e33e4 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -983,6 +983,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
switch (soc_type) {
case QCA_WCN3991:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
/* get fw build info */
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 7089e9b63..520cb84a1 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1381,6 +1381,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
usleep_range(1000, 10000);
@@ -1468,6 +1469,7 @@ static int qca_check_speeds(struct hci_uart *hu)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
@@ -1511,6 +1513,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
hci_uart_set_flow_control(hu, true);
@@ -1546,6 +1549,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
hci_uart_set_flow_control(hu, false);
@@ -1862,6 +1866,7 @@ static int qca_power_on(struct hci_dev *hdev)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
ret = qca_regulator_init(hu);
@@ -1984,6 +1989,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
if (qcadev && qcadev->bdaddr_property_broken)
@@ -2017,6 +2023,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
break;
@@ -2279,6 +2286,7 @@ static void qca_power_off(struct hci_uart *hu)
break;
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
msleep(100);
@@ -2433,6 +2441,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
qcadev->bt_power = devm_kzalloc(&serdev->dev,
@@ -2452,6 +2461,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
if (!device_property_present(&serdev->dev, "enable-gpios")) {
@@ -2495,6 +2505,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->bt_en &&
(data->soc_type == QCA_WCN6750 ||
+ data->soc_type == QCA_QCA2066 ||
data->soc_type == QCA_WCN6855 ||
data->soc_type == QCA_WCN7850))
power_ctrl_enabled = false;
@@ -2503,6 +2514,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
GPIOD_IN);
if (IS_ERR(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
+ data->soc_type == QCA_QCA2066 ||
data->soc_type == QCA_WCN6855 ||
data->soc_type == QCA_WCN7850)) {
dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
@@ -2587,6 +2599,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
+ case QCA_QCA2066:
case QCA_WCN6855:
case QCA_WCN7850:
if (power->vregs_on)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 2/2] Bluetooth: hci_qca: Don't use the serdev port after a failed reopen
2026-11-10 9:29 [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Shuai Zhang
2026-11-10 9:29 ` [PATCH v4 1/2] " Shuai Zhang
@ 2026-11-10 9:29 ` Shuai Zhang
2026-11-10 13:51 ` [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Bartosz Golaszewski
2026-11-10 16:10 ` patchwork-bot+bluetooth
3 siblings, 0 replies; 6+ messages in thread
From: Shuai Zhang @ 2026-11-10 9:29 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
xiuzhuo.shang, wei.deng, jinwang.li, Shuai Zhang,
Bartosz Golaszewski
If serdev_device_open() fails in qca_port_reopen(), qca_regulator_init()
or the qca_setup() retry path, the port is left closed but
HCI_UART_PROTO_READY stays set. The error reaches qca_setup(), whose
retry loop calls serdev_device_close() again, and hci_uart_close() or
hci_uart_unregister_device() close it once more later. The HCI core
also calls hci_uart_flush() from hci_dev_close_sync() before
hdev->close(), which writes to the closed port.
serdev_device_close() and serdev_device_write_flush() have no "not open"
check. ttyport_open() clears serport->tty when it fails, so both end up
passing NULL to the tty layer, and the runtime PM usage count is dropped
once too often.
Keep HCI_UART_PROTO_READY in sync with the port state in hci_qca: clear
it when the port is closed, set it only after a successful open, and
only call serdev_device_close() when it was set. hci_uart_open() already
treats the flag as "port is open" and reopens the port when it is
clear, so the next power on recovers. Make hci_uart_flush() skip the
port flush when the flag is clear, as it already does for the proto
flush.
Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 33 +++++++++++++++++++++++++++------
drivers/bluetooth/hci_serdev.c | 6 ++++--
2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 520cb84a1..700ecc3a2 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1749,6 +1749,27 @@ static bool qca_wakeup(struct hci_dev *hdev)
return wakeup;
}
+static void qca_port_close(struct hci_uart *hu)
+{
+ /* HCI_UART_PROTO_READY tracks whether the port is open, so a port
+ * left closed by a failed qca_port_open() is not closed again by
+ * hci_uart_close() or hci_uart_unregister_device().
+ */
+ if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags))
+ serdev_device_close(hu->serdev);
+}
+
+static int qca_port_open(struct hci_uart *hu)
+{
+ int ret;
+
+ ret = serdev_device_open(hu->serdev);
+ if (!ret)
+ set_bit(HCI_UART_PROTO_READY, &hu->flags);
+
+ return ret;
+}
+
static int qca_port_reopen(struct hci_uart *hu)
{
int ret;
@@ -1758,8 +1779,8 @@ static int qca_port_reopen(struct hci_uart *hu)
* Without this, we will have RTS and CTS synchronization
* issues.
*/
- serdev_device_close(hu->serdev);
- ret = serdev_device_open(hu->serdev);
+ qca_port_close(hu);
+ ret = qca_port_open(hu);
if (ret) {
bt_dev_err(hu->hdev, "failed to open port");
return ret;
@@ -1783,12 +1804,12 @@ static int qca_regulator_init(struct hci_uart *hu)
qcadev = serdev_device_get_drvdata(hu->serdev);
if (!qcadev->bt_power->vregs_on) {
- serdev_device_close(hu->serdev);
+ qca_port_close(hu);
ret = qca_regulator_enable(qcadev);
if (ret)
return ret;
- ret = serdev_device_open(hu->serdev);
+ ret = qca_port_open(hu);
if (ret) {
bt_dev_err(hu->hdev, "failed to open port");
return ret;
@@ -2067,8 +2088,8 @@ static int qca_setup(struct hci_uart *hu)
if (retries < MAX_INIT_RETRIES) {
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
if (hu->serdev) {
- serdev_device_close(hu->serdev);
- ret = serdev_device_open(hu->serdev);
+ qca_port_close(hu);
+ ret = qca_port_open(hu);
if (ret) {
bt_dev_err(hdev, "failed to open port");
return ret;
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
index 48ba017e2..d2c48df34 100644
--- a/drivers/bluetooth/hci_serdev.c
+++ b/drivers/bluetooth/hci_serdev.c
@@ -101,11 +101,13 @@ static int hci_uart_flush(struct hci_dev *hdev)
kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
}
+ if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
+ return 0;
+
/* Flush any pending characters in the driver and discipline. */
serdev_device_write_flush(hu->serdev);
- if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
- hu->proto->flush(hu);
+ hu->proto->flush(hu);
return 0;
}
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
2026-11-10 9:29 [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Shuai Zhang
2026-11-10 9:29 ` [PATCH v4 1/2] " Shuai Zhang
2026-11-10 9:29 ` [PATCH v4 2/2] Bluetooth: hci_qca: Don't use the serdev port after a failed reopen Shuai Zhang
@ 2026-11-10 13:51 ` Bartosz Golaszewski
2026-11-10 16:10 ` patchwork-bot+bluetooth
3 siblings, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2026-11-10 13:51 UTC (permalink / raw)
To: Shuai Zhang
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-arm-msm,
linux-bluetooth, linux-kernel, cheng.jiang, xiuzhuo.shang,
wei.deng, jinwang.li
On Tue, Nov 10, 2026 at 05:29:27PM +0800, Shuai Zhang wrote:
> QCA2066 does not reopen the UART after the controller is enabled, which
> causes RX/TX out-of-sync errors. The UART has to be reopened once the
> controller is powered on.
>
> qca_regulator_init() already enables the controller and then reopens the
> UART, but QCA2066 does not go through it. QCA2066 was added with its own
> SoC type and handled in the default case.
>
> Let QCA2066 go through qca_regulator_init() as well, and handle it in the
> other places that check the SoC type in the same way.
>
> Patch 1 reopens the UART after enabling QCA2066.
>
> Patch 2 keeps HCI_UART_PROTO_READY in sync with the port state, so that a
> port which failed to reopen is not closed or flushed again.
>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 1/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
2026-11-10 9:29 ` [PATCH v4 1/2] " Shuai Zhang
@ 2026-11-10 13:52 ` Bartosz Golaszewski
0 siblings, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2026-11-10 13:52 UTC (permalink / raw)
To: Shuai Zhang
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-arm-msm,
linux-bluetooth, linux-kernel, cheng.jiang, xiuzhuo.shang,
wei.deng, jinwang.li
On Tue, Nov 10, 2026 at 05:29:28PM +0800, Shuai Zhang wrote:
> QCA2066 does not reopen the UART after the controller is enabled, which
> causes RX/TX out-of-sync errors. The UART has to be reopened once the
> controller is powered on.
>
> qca_regulator_init() already enables the controller and then reopens the
> UART, but QCA2066 does not go through it. QCA2066 was added with its own
> SoC type and handled in the default case.
>
> Let QCA2066 go through qca_regulator_init() as well, and handle it in the
> other places that check the SoC type in the same way. This also applies
> the baudrate switching, flow control, shutdown and probe handling of
> those chips to QCA2066. btqca.c checks the SoC type in the same way, so
> the firmware version is also shown in the log.
>
> Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
> ---
As suggested by sashiko:
Fixes: a7f8dedb4be2 ("Bluetooth: qca: add support for QCA2066")
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
2026-11-10 9:29 [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Shuai Zhang
` (2 preceding siblings ...)
2026-11-10 13:51 ` [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Bartosz Golaszewski
@ 2026-11-10 16:10 ` patchwork-bot+bluetooth
3 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+bluetooth @ 2026-11-10 16:10 UTC (permalink / raw)
To: Shuai Zhang
Cc: brgl, marcel, luiz.dentz, linux-arm-msm, linux-bluetooth,
linux-kernel, cheng.jiang, xiuzhuo.shang, wei.deng, jinwang.li
Hello:
This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Tue, 10 Nov 2026 17:29:27 +0800 you wrote:
> QCA2066 does not reopen the UART after the controller is enabled, which
> causes RX/TX out-of-sync errors. The UART has to be reopened once the
> controller is powered on.
>
> qca_regulator_init() already enables the controller and then reopens the
> UART, but QCA2066 does not go through it. QCA2066 was added with its own
> SoC type and handled in the default case.
>
> [...]
Here is the summary with links:
- [v4,1/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066
https://git.kernel.org/bluetooth/bluetooth-next/c/a57a255ce204
- [v4,2/2] Bluetooth: hci_qca: Don't use the serdev port after a failed reopen
https://git.kernel.org/bluetooth/bluetooth-next/c/45e28b01e4d0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-10 16:10 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 9:29 [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Shuai Zhang
2026-11-10 9:29 ` [PATCH v4 1/2] " Shuai Zhang
2026-11-10 13:52 ` Bartosz Golaszewski
2026-11-10 9:29 ` [PATCH v4 2/2] Bluetooth: hci_qca: Don't use the serdev port after a failed reopen Shuai Zhang
2026-11-10 13:51 ` [PATCH v4 0/2] Bluetooth: hci_qca: Reopen the UART after enabling QCA2066 Bartosz Golaszewski
2026-11-10 16:10 ` patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®