From fce1a9244a0f85683be8530e623bc729f24c5067 Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Wed, 3 Dec 2025 11:37:12 +0800 Subject: [PATCH 01/40] Bluetooth: hci_qca: Fix SSR (SubSystem Restart) fail when BT_EN is pulled up by hw On QCS9075 and QCA8275 platforms, the BT_EN pin is always pulled up by hw and cannot be controlled by the host. As a result, in case of a firmware crash, the host cannot trigger a cold reset. Instead, the BT controller performs a warm restart on its own, without reloading the firmware. This leads to the controller remaining in IBS_WAKE state, while the host expects it to be in sleep mode. The mismatch causes HCI reset commands to time out. Additionally, the driver does not clear internal flags QCA_SSR_TRIGGERED and QCA_IBS_DISABLED, which blocks the reset sequence. If the SSR duration exceeds 2 seconds, the host may enter TX sleep mode due to tx_idle_timeout, further preventing recovery. Also, memcoredump_flag is not cleared, so only the first SSR generates a coredump. Tell the driver that the BT controller has undergone a proper restart sequence: - Clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED flags after SSR. - Add a 50ms delay to allow the controller to complete its warm reset. - Reset tx_idle_timer to prevent the host from entering TX sleep mode. - Clear memcoredump_flag to allow multiple coredump captures. Apply these steps only when HCI_QUIRK_NON_PERSISTENT_SETUP is not set, which indicates that BT_EN is defined in DTS and cannot be toggled. Refer to the comment in include/net/bluetooth/hci.h for details on HCI_QUIRK_NON_PERSISTENT_SETUP. Reviewed-by: Dmitry Baryshkov Signed-off-by: Shuai Zhang Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 888176b0faa9..a3c217571c3c 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1653,6 +1653,39 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) skb_queue_purge(&qca->rx_memdump_q); } + /* + * If the BT chip's bt_en pin is connected to a 3.3V power supply via + * hardware and always stays high, driver cannot control the bt_en pin. + * As a result, during SSR (SubSystem Restart), QCA_SSR_TRIGGERED and + * QCA_IBS_DISABLED flags cannot be cleared, which leads to a reset + * command timeout. + * Add an msleep delay to ensure controller completes the SSR process. + * + * Host will not download the firmware after SSR, controller to remain + * in the IBS_WAKE state, and the host needs to synchronize with it + * + * Since the bluetooth chip has been reset, clear the memdump state. + */ + if (!hci_test_quirk(hu->hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) { + /* + * When the SSR (SubSystem Restart) duration exceeds 2 seconds, + * it triggers host tx_idle_delay, which sets host TX state + * to sleep. Reset tx_idle_timer after SSR to prevent + * host enter TX IBS_Sleep mode. + */ + mod_timer(&qca->tx_idle_timer, jiffies + + msecs_to_jiffies(qca->tx_idle_delay)); + + /* Controller reset completion time is 50ms */ + msleep(50); + + clear_bit(QCA_SSR_TRIGGERED, &qca->flags); + clear_bit(QCA_IBS_DISABLED, &qca->flags); + + qca->tx_ibs_state = HCI_IBS_TX_AWAKE; + qca->memdump_state = QCA_MEMDUMP_IDLE; + } + clear_bit(QCA_HW_ERROR_EVENT, &qca->flags); } From 129d1ef3c5e60d51678e6359beaba85771a49e46 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 10 Dec 2025 11:38:08 -0500 Subject: [PATCH 02/40] Bluetooth: hci_conn: Fix using conn->le_{tx,rx}_phy as supported PHYs conn->le_{tx,rx}_phy is not actually a bitfield as it set by HCI_EV_LE_PHY_UPDATE_COMPLETE it is actually correspond to the current PHY in use not what is supported by the controller, so this introduces different fields (conn->le_{tx,rx}_def_phys) to track what PHYs are supported by the connection. Fixes: eab2404ba798 ("Bluetooth: Add BT_PHY socket option") Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 17 +++++++++++------ net/bluetooth/hci_event.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4263e71a23ef..8aadf4cdead2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -730,6 +730,8 @@ struct hci_conn { __u16 le_per_adv_data_offset; __u8 le_adv_phy; __u8 le_adv_sec_phy; + __u8 le_tx_def_phys; + __u8 le_rx_def_phys; __u8 le_tx_phy; __u8 le_rx_phy; __s8 rssi; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index c3f7828bf9d5..5a4374ccf8e8 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1008,6 +1008,11 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, /* conn->src should reflect the local identity address */ hci_copy_identity_address(hdev, &conn->src, &conn->src_type); conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; + /* Use the controller supported PHYS as default until the + * remote features are resolved. + */ + conn->le_tx_def_phys = hdev->le_tx_def_phys; + conn->le_rx_def_phys = hdev->le_tx_def_phys; break; case CIS_LINK: /* conn->src should reflect the local identity address */ @@ -2928,22 +2933,22 @@ u32 hci_conn_get_phy(struct hci_conn *conn) break; case LE_LINK: - if (conn->le_tx_phy & HCI_LE_SET_PHY_1M) + if (conn->le_tx_def_phys & HCI_LE_SET_PHY_1M) phys |= BT_PHY_LE_1M_TX; - if (conn->le_rx_phy & HCI_LE_SET_PHY_1M) + if (conn->le_rx_def_phys & HCI_LE_SET_PHY_1M) phys |= BT_PHY_LE_1M_RX; - if (conn->le_tx_phy & HCI_LE_SET_PHY_2M) + if (conn->le_tx_def_phys & HCI_LE_SET_PHY_2M) phys |= BT_PHY_LE_2M_TX; - if (conn->le_rx_phy & HCI_LE_SET_PHY_2M) + if (conn->le_rx_def_phys & HCI_LE_SET_PHY_2M) phys |= BT_PHY_LE_2M_RX; - if (conn->le_tx_phy & HCI_LE_SET_PHY_CODED) + if (conn->le_tx_def_phys & HCI_LE_SET_PHY_CODED) phys |= BT_PHY_LE_CODED_TX; - if (conn->le_rx_phy & HCI_LE_SET_PHY_CODED) + if (conn->le_rx_def_phys & HCI_LE_SET_PHY_CODED) phys |= BT_PHY_LE_CODED_RX; break; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a9868f17ef40..58075bf72055 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6607,8 +6607,20 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { - if (!ev->status) - memcpy(conn->features[0], ev->features, 8); + if (!ev->status) { + memcpy(conn->le_features, ev->features, 8); + + /* Update supported PHYs */ + if (!(conn->le_features[1] & HCI_LE_PHY_2M)) { + conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M; + conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M; + } + + if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) { + conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED; + conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED; + } + } if (conn->state == BT_CONFIG) { __u8 status; @@ -7221,9 +7233,21 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev, if (!conn) goto unlock; - if (!ev->status) + if (!ev->status) { memcpy(conn->le_features, ev->features, 248); + /* Update supported PHYs */ + if (!(conn->le_features[1] & HCI_LE_PHY_2M)) { + conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M; + conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M; + } + + if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) { + conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED; + conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED; + } + } + if (conn->state == BT_CONFIG) { __u8 status; From 2630bcc8343a9d2a38dc1793068e6754b3156811 Mon Sep 17 00:00:00 2001 From: Bluecross Date: Wed, 10 Dec 2025 23:22:25 +0300 Subject: [PATCH 03/40] Bluetooth: btusb: Add support for MediaTek7920 0489:e158 Add support for MediaTek7920 0489:e158 /sys/kernel/debug/usb/devices reports for that device: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=03 Dev#= 5 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e158 Rev= 1.00 S: Manufacturer=MediaTek Inc. S: Product=Wireless_Device S: SerialNumber=000000000 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us Signed-off-by: Andrew Elatsev Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ded09e94d296..646de80c7e7b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -637,6 +637,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3622), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe158), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, /* Additional MediaTek MT7921 Bluetooth devices */ { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | From 502a5731d3538b9b00fc7edea3aaf378bf916b96 Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Wed, 10 Dec 2025 23:21:09 +0000 Subject: [PATCH 04/40] Bluetooth: hci_bcm4377: Use generic power management Switch to the generic PCI power management framework and remove legacy callbacks like .suspend() and .resume(). With the generic framework, the standard PCI related work like: - pci_save/restore_state() - pci_enable/disable_device() - pci_set_power_state() is handled by the PCI core and this driver should implement only hci_bcm4377 specific operations in its respective callback functions. Signed-off-by: Vaibhav Gupta Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_bcm4377.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 45e6d84224ee..925d0a635945 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2416,8 +2416,9 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) hdev); } -static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state) +static int bcm4377_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); int ret; @@ -2431,8 +2432,9 @@ static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int bcm4377_resume(struct pci_dev *pdev) +static int bcm4377_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE, @@ -2441,6 +2443,8 @@ static int bcm4377_resume(struct pci_dev *pdev) return hci_resume_dev(bcm4377->hdev); } +static DEFINE_SIMPLE_DEV_PM_OPS(bcm4377_ops, bcm4377_suspend, bcm4377_resume); + static const struct dmi_system_id bcm4377_dmi_board_table[] = { { .matches = { @@ -2541,8 +2545,7 @@ static struct pci_driver bcm4377_pci_driver = { .name = "hci_bcm4377", .id_table = bcm4377_devid_table, .probe = bcm4377_probe, - .suspend = bcm4377_suspend, - .resume = bcm4377_resume, + .driver.pm = &bcm4377_ops, }; module_pci_driver(bcm4377_pci_driver); From 544a237adaaf95e8aff1964c6d2182a915a8692e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 17 Dec 2025 12:20:33 +0100 Subject: [PATCH 05/40] Bluetooth: btmtksdio: Use pm_ptr instead of #ifdef CONFIG_PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This increases build coverage and allows to drop an #ifdef. Signed-off-by: Uwe Kleine-König Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btmtksdio.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index fba3ab6d30a5..e986e5af51ae 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -1472,7 +1472,6 @@ static void btmtksdio_remove(struct sdio_func *func) hci_free_dev(hdev); } -#ifdef CONFIG_PM static int btmtksdio_runtime_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); @@ -1542,18 +1541,13 @@ static const struct dev_pm_ops btmtksdio_pm_ops = { RUNTIME_PM_OPS(btmtksdio_runtime_suspend, btmtksdio_runtime_resume, NULL) }; -#define BTMTKSDIO_PM_OPS (&btmtksdio_pm_ops) -#else /* CONFIG_PM */ -#define BTMTKSDIO_PM_OPS NULL -#endif /* CONFIG_PM */ - static struct sdio_driver btmtksdio_driver = { .name = "btmtksdio", .probe = btmtksdio_probe, .remove = btmtksdio_remove, .id_table = btmtksdio_table, .drv = { - .pm = BTMTKSDIO_PM_OPS, + .pm = pm_ptr(&btmtksdio_pm_ops), } }; From 49d0901e260739de2fcc90c0c29f9e31e39a2d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Tue, 16 Dec 2025 10:20:09 +0100 Subject: [PATCH 06/40] Bluetooth: hci_conn: use mod_delayed_work for active mode timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hci_conn_enter_active_mode() uses queue_delayed_work() with the intention that the work will run after the given timeout. However, queue_delayed_work() does nothing if the work is already queued, so depending on the link policy we may end up putting the connection into idle mode every hdev->idle_timeout ms. Use mod_delayed_work() instead so the work is queued if not already queued, and the timeout is updated otherwise. Signed-off-by: Stefan Sørensen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5a4374ccf8e8..1b98b6467485 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2619,8 +2619,8 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) timer: if (hdev->idle_timeout > 0) - queue_delayed_work(hdev->workqueue, &conn->idle_work, - msecs_to_jiffies(hdev->idle_timeout)); + mod_delayed_work(hdev->workqueue, &conn->idle_work, + msecs_to_jiffies(hdev->idle_timeout)); } /* Drop all connection on the device */ From 4bb091013ab0f2edfed3f58bebe658a798cbcc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Tue, 16 Dec 2025 10:20:10 +0100 Subject: [PATCH 07/40] Bluetooth: hci_conn: Set link_policy on incoming ACL connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The connection link policy is only set when establishing an outgoing ACL connection causing connection idle modes not to be available on incoming connections. Move the setting of the link policy to the creation of the connection so all ACL connection will use the link policy set on the HCI device. Signed-off-by: Stefan Sørensen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_conn.c | 1 + net/bluetooth/hci_sync.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1b98b6467485..dc085856f5e9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1002,6 +1002,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, switch (type) { case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; + conn->link_policy = hdev->link_policy; conn->mtu = hdev->acl_mtu; break; case LE_LINK: diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index cbc3a75d7326..334eb4376a26 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -6897,8 +6897,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) conn->attempt++; - conn->link_policy = hdev->link_policy; - memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; From 48fea7d4b363cfc051d50639a135f8be5d0be7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Tue, 16 Dec 2025 10:20:11 +0100 Subject: [PATCH 08/40] Bluetooth: mgmt: Add idle_timeout to configurable system parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the configurable system parameters allow controlling the SNIFF mode parameters, they do not include the idle_timeout parameter responsible for enabling SNIFF mode. Add the idle_timeout parameter to allow controlling the idle timeout of BR/EDR connections. Signed-off-by: Stefan Sørensen Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt_config.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/net/bluetooth/mgmt_config.c b/net/bluetooth/mgmt_config.c index c4063d200c0a..fdcc752c6f13 100644 --- a/net/bluetooth/mgmt_config.c +++ b/net/bluetooth/mgmt_config.c @@ -11,6 +11,12 @@ #include "mgmt_util.h" #include "mgmt_config.h" +#define HDEV_PARAM_U32(_param_name_) \ + struct {\ + struct mgmt_tlv_hdr entry; \ + __le32 value; \ + } __packed _param_name_ + #define HDEV_PARAM_U16(_param_name_) \ struct {\ struct mgmt_tlv_hdr entry; \ @@ -29,6 +35,12 @@ cpu_to_le16(hdev->_param_name_) \ } +#define TLV_SET_U32(_param_code_, _param_name_) \ + { \ + { cpu_to_le16(_param_code_), sizeof(__u32) }, \ + cpu_to_le32(hdev->_param_name_) \ + } + #define TLV_SET_U8(_param_code_, _param_name_) \ { \ { cpu_to_le16(_param_code_), sizeof(__u8) }, \ @@ -78,6 +90,7 @@ int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, HDEV_PARAM_U16(advmon_allowlist_duration); HDEV_PARAM_U16(advmon_no_filter_duration); HDEV_PARAM_U8(enable_advmon_interleave_scan); + HDEV_PARAM_U32(idle_timeout); } __packed rp = { TLV_SET_U16(0x0000, def_page_scan_type), TLV_SET_U16(0x0001, def_page_scan_int), @@ -111,6 +124,7 @@ int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, TLV_SET_U16(0x001d, advmon_allowlist_duration), TLV_SET_U16(0x001e, advmon_no_filter_duration), TLV_SET_U8(0x001f, enable_advmon_interleave_scan), + TLV_SET_U32(0x0020, idle_timeout), }; bt_dev_dbg(hdev, "sock %p", sk); @@ -122,6 +136,7 @@ int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, } #define TO_TLV(x) ((struct mgmt_tlv *)(x)) +#define TLV_GET_LE32(tlv) le32_to_cpu(*((__le32 *)(TO_TLV(tlv)->value))) #define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value))) #define TLV_GET_U8(tlv) (*((__u8 *)(TO_TLV(tlv)->value))) @@ -191,6 +206,9 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, case 0x001f: exp_type_len = sizeof(u8); break; + case 0x0020: + exp_type_len = sizeof(u32); + break; default: exp_type_len = 0; bt_dev_warn(hdev, "unsupported parameter %u", type); @@ -314,6 +332,9 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, case 0x0001f: hdev->enable_advmon_interleave_scan = TLV_GET_U8(buffer); break; + case 0x00020: + hdev->idle_timeout = TLV_GET_LE32(buffer); + break; default: bt_dev_warn(hdev, "unsupported parameter %u", type); break; From fe05e3c0593fda2c476b359b012065a42dccdd71 Mon Sep 17 00:00:00 2001 From: Naga Bhavani Akella Date: Wed, 17 Dec 2025 16:55:23 +0530 Subject: [PATCH 09/40] Bluetooth: hci_sync: Add LE Channel Sounding HCI Command/event structures 1. Implement LE Event Mask to include events required for LE Channel Sounding 2. Enable Channel Sounding feature bit in the LE Host Supported Features command 3. Define HCI command and event structures necessary for LE Channel Sounding functionality Signed-off-by: Naga Bhavani Akella Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 323 +++++++++++++++++++++++++++++++ include/net/bluetooth/hci_core.h | 6 + net/bluetooth/hci_sync.c | 45 ++++- 3 files changed, 367 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index a27cd3626b87..4a731e1bec53 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -654,6 +654,8 @@ enum { #define HCI_LE_ISO_BROADCASTER 0x40 #define HCI_LE_ISO_SYNC_RECEIVER 0x80 #define HCI_LE_LL_EXT_FEATURE 0x80 +#define HCI_LE_CS 0x40 +#define HCI_LE_CS_HOST 0x80 /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 @@ -2269,6 +2271,204 @@ struct hci_cp_le_read_all_remote_features { __u8 pages; } __packed; +/* Channel Sounding Commands */ +#define HCI_OP_LE_CS_RD_LOCAL_SUPP_CAP 0x2089 +struct hci_rp_le_cs_rd_local_supp_cap { + __u8 status; + __u8 num_config_supported; + __le16 max_consecutive_procedures_supported; + __u8 num_antennas_supported; + __u8 max_antenna_paths_supported; + __u8 roles_supported; + __u8 modes_supported; + __u8 rtt_capability; + __u8 rtt_aa_only_n; + __u8 rtt_sounding_n; + __u8 rtt_random_payload_n; + __le16 nadm_sounding_capability; + __le16 nadm_random_capability; + __u8 cs_sync_phys_supported; + __le16 subfeatures_supported; + __le16 t_ip1_times_supported; + __le16 t_ip2_times_supported; + __le16 t_fcs_times_supported; + __le16 t_pm_times_supported; + __u8 t_sw_time_supported; + __u8 tx_snr_capability; +} __packed; + +#define HCI_OP_LE_CS_RD_RMT_SUPP_CAP 0x208A +struct hci_cp_le_cs_rd_local_supp_cap { + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_WR_CACHED_RMT_SUPP_CAP 0x208B +struct hci_cp_le_cs_wr_cached_rmt_supp_cap { + __le16 handle; + __u8 num_config_supported; + __le16 max_consecutive_procedures_supported; + __u8 num_antennas_supported; + __u8 max_antenna_paths_supported; + __u8 roles_supported; + __u8 modes_supported; + __u8 rtt_capability; + __u8 rtt_aa_only_n; + __u8 rtt_sounding_n; + __u8 rtt_random_payload_n; + __le16 nadm_sounding_capability; + __le16 nadm_random_capability; + __u8 cs_sync_phys_supported; + __le16 subfeatures_supported; + __le16 t_ip1_times_supported; + __le16 t_ip2_times_supported; + __le16 t_fcs_times_supported; + __le16 t_pm_times_supported; + __u8 t_sw_time_supported; + __u8 tx_snr_capability; +} __packed; + +struct hci_rp_le_cs_wr_cached_rmt_supp_cap { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_SEC_ENABLE 0x208C +struct hci_cp_le_cs_sec_enable { + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_SET_DEFAULT_SETTINGS 0x208D +struct hci_cp_le_cs_set_default_settings { + __le16 handle; + __u8 role_enable; + __u8 cs_sync_ant_sel; + __s8 max_tx_power; +} __packed; + +struct hci_rp_le_cs_set_default_settings { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_RD_RMT_FAE_TABLE 0x208E +struct hci_cp_le_cs_rd_rmt_fae_table { + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_WR_CACHED_RMT_FAE_TABLE 0x208F +struct hci_cp_le_cs_wr_rmt_cached_fae_table { + __le16 handle; + __u8 remote_fae_table[72]; +} __packed; + +struct hci_rp_le_cs_wr_rmt_cached_fae_table { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_CREATE_CONFIG 0x2090 +struct hci_cp_le_cs_create_config { + __le16 handle; + __u8 config_id; + __u8 create_context; + __u8 main_mode_type; + __u8 sub_mode_type; + __u8 min_main_mode_steps; + __u8 max_main_mode_steps; + __u8 main_mode_repetition; + __u8 mode_0_steps; + __u8 role; + __u8 rtt_type; + __u8 cs_sync_phy; + __u8 channel_map[10]; + __u8 channel_map_repetition; + __u8 channel_selection_type; + __u8 ch3c_shape; + __u8 ch3c_jump; + __u8 reserved; +} __packed; + +#define HCI_OP_LE_CS_REMOVE_CONFIG 0x2091 +struct hci_cp_le_cs_remove_config { + __le16 handle; + __u8 config_id; +} __packed; + +#define HCI_OP_LE_CS_SET_CH_CLASSIFICATION 0x2092 +struct hci_cp_le_cs_set_ch_classification { + __u8 ch_classification[10]; +} __packed; + +struct hci_rp_le_cs_set_ch_classification { + __u8 status; +} __packed; + +#define HCI_OP_LE_CS_SET_PROC_PARAM 0x2093 +struct hci_cp_le_cs_set_proc_param { + __le16 handle; + __u8 config_id; + __le16 max_procedure_len; + __le16 min_procedure_interval; + __le16 max_procedure_interval; + __le16 max_procedure_count; + __u8 min_subevent_len[3]; + __u8 max_subevent_len[3]; + __u8 tone_antenna_config_selection; + __u8 phy; + __u8 tx_power_delta; + __u8 preferred_peer_antenna; + __u8 snr_control_initiator; + __u8 snr_control_reflector; +} __packed; + +struct hci_rp_le_cs_set_proc_param { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_CS_SET_PROC_ENABLE 0x2094 +struct hci_cp_le_cs_set_proc_enable { + __le16 handle; + __u8 config_id; + __u8 enable; +} __packed; + +#define HCI_OP_LE_CS_TEST 0x2095 +struct hci_cp_le_cs_test { + __u8 main_mode_type; + __u8 sub_mode_type; + __u8 main_mode_repetition; + __u8 mode_0_steps; + __u8 role; + __u8 rtt_type; + __u8 cs_sync_phy; + __u8 cs_sync_antenna_selection; + __u8 subevent_len[3]; + __le16 subevent_interval; + __u8 max_num_subevents; + __u8 transmit_power_level; + __u8 t_ip1_time; + __u8 t_ip2_time; + __u8 t_fcs_time; + __u8 t_pm_time; + __u8 t_sw_time; + __u8 tone_antenna_config_selection; + __u8 reserved; + __u8 snr_control_initiator; + __u8 snr_control_reflector; + __le16 drbg_nonce; + __u8 channel_map_repetition; + __le16 override_config; + __u8 override_parameters_length; + __u8 override_parameters_data[]; +} __packed; + +struct hci_rp_le_cs_test { + __u8 status; +} __packed; + +#define HCI_OP_LE_CS_TEST_END 0x2096 + /* ---- HCI Events ---- */ struct hci_ev_status { __u8 status; @@ -2960,6 +3160,129 @@ struct hci_evt_le_read_all_remote_features_complete { __u8 features[248]; } __packed; +/* Channel Sounding Events */ +#define HCI_EVT_LE_CS_READ_RMT_SUPP_CAP_COMPLETE 0x2C +struct hci_evt_le_cs_read_rmt_supp_cap_complete { + __u8 status; + __le16 handle; + __u8 num_configs_supp; + __le16 max_consec_proc_supp; + __u8 num_ant_supp; + __u8 max_ant_path_supp; + __u8 roles_supp; + __u8 modes_supp; + __u8 rtt_cap; + __u8 rtt_aa_only_n; + __u8 rtt_sounding_n; + __u8 rtt_rand_payload_n; + __le16 nadm_sounding_cap; + __le16 nadm_rand_cap; + __u8 cs_sync_phys_supp; + __le16 sub_feat_supp; + __le16 t_ip1_times_supp; + __le16 t_ip2_times_supp; + __le16 t_fcs_times_supp; + __le16 t_pm_times_supp; + __u8 t_sw_times_supp; + __u8 tx_snr_cap; +} __packed; + +#define HCI_EVT_LE_CS_READ_RMT_FAE_TABLE_COMPLETE 0x2D +struct hci_evt_le_cs_read_rmt_fae_table_complete { + __u8 status; + __le16 handle; + __u8 remote_fae_table[72]; +} __packed; + +#define HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE 0x2E +struct hci_evt_le_cs_security_enable_complete { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_EVT_LE_CS_CONFIG_COMPLETE 0x2F +struct hci_evt_le_cs_config_complete { + __u8 status; + __le16 handle; + __u8 config_id; + __u8 action; + __u8 main_mode_type; + __u8 sub_mode_type; + __u8 min_main_mode_steps; + __u8 max_main_mode_steps; + __u8 main_mode_rep; + __u8 mode_0_steps; + __u8 role; + __u8 rtt_type; + __u8 cs_sync_phy; + __u8 channel_map[10]; + __u8 channel_map_rep; + __u8 channel_sel_type; + __u8 ch3c_shape; + __u8 ch3c_jump; + __u8 reserved; + __u8 t_ip1_time; + __u8 t_ip2_time; + __u8 t_fcs_time; + __u8 t_pm_time; +} __packed; + +#define HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE 0x30 +struct hci_evt_le_cs_procedure_enable_complete { + __u8 status; + __le16 handle; + __u8 config_id; + __u8 state; + __u8 tone_ant_config_sel; + __s8 sel_tx_pwr; + __u8 sub_evt_len[3]; + __u8 sub_evts_per_evt; + __le16 sub_evt_intrvl; + __le16 evt_intrvl; + __le16 proc_intrvl; + __le16 proc_counter; + __le16 max_proc_len; +} __packed; + +#define HCI_EVT_LE_CS_SUBEVENT_RESULT 0x31 +struct hci_evt_le_cs_subevent_result { + __le16 handle; + __u8 config_id; + __le16 start_acl_conn_evt_counter; + __le16 proc_counter; + __le16 freq_comp; + __u8 ref_pwr_lvl; + __u8 proc_done_status; + __u8 subevt_done_status; + __u8 abort_reason; + __u8 num_ant_paths; + __u8 num_steps_reported; + __u8 step_mode[0]; /* depends on num_steps_reported */ + __u8 step_channel[0]; /* depends on num_steps_reported */ + __u8 step_data_length[0]; /* depends on num_steps_reported */ + __u8 step_data[0]; /* depends on num_steps_reported */ +} __packed; + +#define HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE 0x32 +struct hci_evt_le_cs_subevent_result_continue { + __le16 handle; + __u8 config_id; + __u8 proc_done_status; + __u8 subevt_done_status; + __u8 abort_reason; + __u8 num_ant_paths; + __u8 num_steps_reported; + __u8 step_mode[0]; /* depends on num_steps_reported */ + __u8 step_channel[0]; /* depends on num_steps_reported */ + __u8 step_data_length[0]; /* depends on num_steps_reported */ + __u8 step_data[0]; /* depends on num_steps_reported */ +} __packed; + +#define HCI_EVT_LE_CS_TEST_END_COMPLETE 0x33 +struct hci_evt_le_cs_test_end_complete { + __u8 status; +} __packed; + #define HCI_EV_VENDOR 0xff /* Internal events generated by Bluetooth stack */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8aadf4cdead2..a7d5beb01b69 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2073,6 +2073,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define ll_ext_feature_capable(dev) \ ((dev)->le_features[7] & HCI_LE_LL_EXT_FEATURE) +/* Channel sounding support */ +#define le_cs_capable(dev) \ + ((dev)->le_features[5] & HCI_LE_CS) +#define le_cs_host_capable(dev) \ + ((dev)->le_features[5] & HCI_LE_CS_HOST) + #define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \ (!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG))) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 334eb4376a26..4163d9b16e1a 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4428,6 +4428,17 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev) events[4] |= 0x02; /* LE BIG Info Advertising Report */ } + if (le_cs_capable(hdev)) { + /* Channel Sounding events */ + events[5] |= 0x08; /* LE CS Read Remote Supported Cap Complete event */ + events[5] |= 0x10; /* LE CS Read Remote FAE Table Complete event */ + events[5] |= 0x20; /* LE CS Security Enable Complete event */ + events[5] |= 0x40; /* LE CS Config Complete event */ + events[5] |= 0x80; /* LE CS Procedure Enable Complete event */ + events[6] |= 0x01; /* LE CS Subevent Result event */ + events[6] |= 0x02; /* LE CS Subevent Result Continue event */ + events[6] |= 0x04; /* LE CS Test End Complete event */ + } return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events, HCI_CMD_TIMEOUT); } @@ -4560,23 +4571,43 @@ static int hci_set_le_support_sync(struct hci_dev *hdev) } /* LE Set Host Feature */ -static int hci_le_set_host_feature_sync(struct hci_dev *hdev) +static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u8 bit, u8 value) { struct hci_cp_le_set_host_feature cp; - if (!iso_capable(hdev)) - return 0; - memset(&cp, 0, sizeof(cp)); /* Connected Isochronous Channels (Host Support) */ - cp.bit_number = 32; - cp.bit_value = iso_enabled(hdev) ? 0x01 : 0x00; + cp.bit_number = bit; + cp.bit_value = value; return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_HOST_FEATURE, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } +/* Set Host Features, each feature needs to be sent separately since + * HCI_OP_LE_SET_HOST_FEATURE doesn't support setting all of them at once. + */ +static int hci_le_set_host_features_sync(struct hci_dev *hdev) +{ + int err; + + if (iso_capable(hdev)) { + /* Connected Isochronous Channels (Host Support) */ + err = hci_le_set_host_feature_sync(hdev, 32, + (iso_enabled(hdev) ? 0x01 : + 0x00)); + if (err) + return err; + } + + if (le_cs_capable(hdev)) + /* Channel Sounding (Host Support) */ + err = hci_le_set_host_feature_sync(hdev, 47, 0x01); + + return err; +} + /* LE Controller init stage 3 command sequence */ static const struct hci_init_stage le_init3[] = { /* HCI_OP_LE_SET_EVENT_MASK */ @@ -4604,7 +4635,7 @@ static const struct hci_init_stage le_init3[] = { /* HCI_OP_WRITE_LE_HOST_SUPPORTED */ HCI_INIT(hci_set_le_support_sync), /* HCI_OP_LE_SET_HOST_FEATURE */ - HCI_INIT(hci_le_set_host_feature_sync), + HCI_INIT(hci_le_set_host_features_sync), {} }; From 132c0779d4a2d08541519cf04783bca52c6ec85c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 17 Dec 2025 10:50:51 -0500 Subject: [PATCH 10/40] Bluetooth: L2CAP: Add support for setting BT_PHY This enables client to use setsockopt(BT_PHY) to set the connection packet type/PHY: Example setting BT_PHY_BR_1M_1SLOT: < HCI Command: Change Conne.. (0x01|0x000f) plen 4 Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation) Packet type: 0x331e 2-DH1 may not be used 3-DH1 may not be used DM1 may be used DH1 may be used 2-DH3 may not be used 3-DH3 may not be used 2-DH5 may not be used 3-DH5 may not be used > HCI Event: Command Status (0x0f) plen 4 Change Connection Packet Type (0x01|0x000f) ncmd 1 Status: Success (0x00) > HCI Event: Connection Packet Typ.. (0x1d) plen 5 Status: Success (0x00) Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation) Packet type: 0x331e 2-DH1 may not be used 3-DH1 may not be used DM1 may be used DH1 may be used 2-DH3 may not be used 3-DH3 may not be used 2-DH5 may not be used Example setting BT_PHY_LE_1M_TX and BT_PHY_LE_1M_RX: < HCI Command: LE Set PHY (0x08|0x0032) plen 7 Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation) All PHYs preference: 0x00 TX PHYs preference: 0x01 LE 1M RX PHYs preference: 0x01 LE 1M PHY options preference: Reserved (0x0000) > HCI Event: Command Status (0x0f) plen 4 LE Set PHY (0x08|0x0032) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 6 LE PHY Update Complete (0x0c) Status: Success (0x00) Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation) TX PHY: LE 1M (0x01) RX PHY: LE 1M (0x01) Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 39 ++++++----- include/net/bluetooth/hci.h | 9 +++ include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/hci_sync.h | 3 + net/bluetooth/hci_conn.c | 105 ++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 26 ++++++++ net/bluetooth/hci_sync.c | 72 ++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 20 +++++- 8 files changed, 259 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index d46ed9011ee5..89a60919050b 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -130,21 +130,30 @@ struct bt_voice { #define BT_RCVMTU 13 #define BT_PHY 14 -#define BT_PHY_BR_1M_1SLOT 0x00000001 -#define BT_PHY_BR_1M_3SLOT 0x00000002 -#define BT_PHY_BR_1M_5SLOT 0x00000004 -#define BT_PHY_EDR_2M_1SLOT 0x00000008 -#define BT_PHY_EDR_2M_3SLOT 0x00000010 -#define BT_PHY_EDR_2M_5SLOT 0x00000020 -#define BT_PHY_EDR_3M_1SLOT 0x00000040 -#define BT_PHY_EDR_3M_3SLOT 0x00000080 -#define BT_PHY_EDR_3M_5SLOT 0x00000100 -#define BT_PHY_LE_1M_TX 0x00000200 -#define BT_PHY_LE_1M_RX 0x00000400 -#define BT_PHY_LE_2M_TX 0x00000800 -#define BT_PHY_LE_2M_RX 0x00001000 -#define BT_PHY_LE_CODED_TX 0x00002000 -#define BT_PHY_LE_CODED_RX 0x00004000 +#define BT_PHY_BR_1M_1SLOT BIT(0) +#define BT_PHY_BR_1M_3SLOT BIT(1) +#define BT_PHY_BR_1M_5SLOT BIT(2) +#define BT_PHY_EDR_2M_1SLOT BIT(3) +#define BT_PHY_EDR_2M_3SLOT BIT(4) +#define BT_PHY_EDR_2M_5SLOT BIT(5) +#define BT_PHY_EDR_3M_1SLOT BIT(6) +#define BT_PHY_EDR_3M_3SLOT BIT(7) +#define BT_PHY_EDR_3M_5SLOT BIT(8) +#define BT_PHY_LE_1M_TX BIT(9) +#define BT_PHY_LE_1M_RX BIT(10) +#define BT_PHY_LE_2M_TX BIT(11) +#define BT_PHY_LE_2M_RX BIT(12) +#define BT_PHY_LE_CODED_TX BIT(13) +#define BT_PHY_LE_CODED_RX BIT(14) + +#define BT_PHY_BREDR_MASK (BT_PHY_BR_1M_1SLOT | BT_PHY_BR_1M_3SLOT | \ + BT_PHY_BR_1M_5SLOT | BT_PHY_EDR_2M_1SLOT | \ + BT_PHY_EDR_2M_3SLOT | BT_PHY_EDR_2M_5SLOT | \ + BT_PHY_EDR_3M_1SLOT | BT_PHY_EDR_3M_3SLOT | \ + BT_PHY_EDR_3M_5SLOT) +#define BT_PHY_LE_MASK (BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX | \ + BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX | \ + BT_PHY_LE_CODED_TX | BT_PHY_LE_CODED_RX) #define BT_MODE 15 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4a731e1bec53..db76c2d1eeaa 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1885,6 +1885,15 @@ struct hci_cp_le_set_default_phy { #define HCI_LE_SET_PHY_2M 0x02 #define HCI_LE_SET_PHY_CODED 0x04 +#define HCI_OP_LE_SET_PHY 0x2032 +struct hci_cp_le_set_phy { + __le16 handle; + __u8 all_phys; + __u8 tx_phys; + __u8 rx_phys; + __le16 phy_opts; +} __packed; + #define HCI_OP_LE_SET_EXT_SCAN_PARAMS 0x2041 struct hci_cp_le_set_ext_scan_params { __u8 own_addr_type; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a7d5beb01b69..a7bffb908c1e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2342,6 +2342,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); void *hci_recv_event_data(struct hci_dev *hdev, __u8 event); u32 hci_conn_get_phy(struct hci_conn *conn); +int hci_conn_set_phy(struct hci_conn *conn, u32 phys); /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 56076bbc981d..73e494b2591d 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -191,3 +191,6 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn); int hci_past_sync(struct hci_conn *conn, struct hci_conn *le); int hci_le_read_remote_features(struct hci_conn *conn); + +int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type); +int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dc085856f5e9..1a4b6badf2b3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2958,6 +2958,111 @@ u32 hci_conn_get_phy(struct hci_conn *conn) return phys; } +static u16 bt_phy_pkt_type(struct hci_conn *conn, u32 phys) +{ + u16 pkt_type = conn->pkt_type; + + if (phys & BT_PHY_BR_1M_3SLOT) + pkt_type |= HCI_DM3 | HCI_DH3; + else + pkt_type &= ~(HCI_DM3 | HCI_DH3); + + if (phys & BT_PHY_BR_1M_5SLOT) + pkt_type |= HCI_DM5 | HCI_DH5; + else + pkt_type &= ~(HCI_DM5 | HCI_DH5); + + if (phys & BT_PHY_EDR_2M_1SLOT) + pkt_type &= ~HCI_2DH1; + else + pkt_type |= HCI_2DH1; + + if (phys & BT_PHY_EDR_2M_3SLOT) + pkt_type &= ~HCI_2DH3; + else + pkt_type |= HCI_2DH3; + + if (phys & BT_PHY_EDR_2M_5SLOT) + pkt_type &= ~HCI_2DH5; + else + pkt_type |= HCI_2DH5; + + if (phys & BT_PHY_EDR_3M_1SLOT) + pkt_type &= ~HCI_3DH1; + else + pkt_type |= HCI_3DH1; + + if (phys & BT_PHY_EDR_3M_3SLOT) + pkt_type &= ~HCI_3DH3; + else + pkt_type |= HCI_3DH3; + + if (phys & BT_PHY_EDR_3M_5SLOT) + pkt_type &= ~HCI_3DH5; + else + pkt_type |= HCI_3DH5; + + return pkt_type; +} + +static int bt_phy_le_phy(u32 phys, u8 *tx_phys, u8 *rx_phys) +{ + if (!tx_phys || !rx_phys) + return -EINVAL; + + *tx_phys = 0; + *rx_phys = 0; + + if (phys & BT_PHY_LE_1M_TX) + *tx_phys |= HCI_LE_SET_PHY_1M; + + if (phys & BT_PHY_LE_1M_RX) + *rx_phys |= HCI_LE_SET_PHY_1M; + + if (phys & BT_PHY_LE_2M_TX) + *tx_phys |= HCI_LE_SET_PHY_2M; + + if (phys & BT_PHY_LE_2M_RX) + *rx_phys |= HCI_LE_SET_PHY_2M; + + if (phys & BT_PHY_LE_CODED_TX) + *tx_phys |= HCI_LE_SET_PHY_CODED; + + if (phys & BT_PHY_LE_CODED_RX) + *rx_phys |= HCI_LE_SET_PHY_CODED; + + return 0; +} + +int hci_conn_set_phy(struct hci_conn *conn, u32 phys) +{ + u8 tx_phys, rx_phys; + + switch (conn->type) { + case SCO_LINK: + case ESCO_LINK: + return -EINVAL; + case ACL_LINK: + /* Only allow setting BR/EDR PHYs if link type is ACL */ + if (phys & ~BT_PHY_BREDR_MASK) + return -EINVAL; + + return hci_acl_change_pkt_type(conn, + bt_phy_pkt_type(conn, phys)); + case LE_LINK: + /* Only allow setting LE PHYs if link type is LE */ + if (phys & ~BT_PHY_LE_MASK) + return -EINVAL; + + if (bt_phy_le_phy(phys, &tx_phys, &rx_phys)) + return -EINVAL; + + return hci_le_set_phy(conn, tx_phys, rx_phys); + default: + return -EINVAL; + } +} + static int abort_conn_sync(struct hci_dev *hdev, void *data) { struct hci_conn *conn = data; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 58075bf72055..467710a42d45 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2869,6 +2869,31 @@ static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status) hci_dev_unlock(hdev); } +static void hci_cs_le_set_phy(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_le_set_phy *cp; + struct hci_conn *conn; + + bt_dev_dbg(hdev, "status 0x%2.2x", status); + + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_PHY); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + conn->le_tx_def_phys = cp->tx_phys; + conn->le_rx_def_phys = cp->rx_phys; + } + + hci_dev_unlock(hdev); +} + static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status) { struct hci_cp_le_read_remote_features *cp; @@ -4359,6 +4384,7 @@ static const struct hci_cs { HCI_CS(HCI_OP_LE_CREATE_CONN, hci_cs_le_create_conn), HCI_CS(HCI_OP_LE_READ_REMOTE_FEATURES, hci_cs_le_read_remote_features), HCI_CS(HCI_OP_LE_START_ENC, hci_cs_le_start_enc), + HCI_CS(HCI_OP_LE_SET_PHY, hci_cs_le_set_phy), HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn), HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis), HCI_CS(HCI_OP_LE_CREATE_BIG, hci_cs_le_create_big), diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 4163d9b16e1a..0e6660ddc00a 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -7448,3 +7448,75 @@ int hci_le_read_remote_features(struct hci_conn *conn) return err; } + +static void pkt_type_changed(struct hci_dev *hdev, void *data, int err) +{ + struct hci_cp_change_conn_ptype *cp = data; + + bt_dev_dbg(hdev, "err %d", err); + + kfree(cp); +} + +static int hci_change_conn_ptype_sync(struct hci_dev *hdev, void *data) +{ + struct hci_cp_change_conn_ptype *cp = data; + + return __hci_cmd_sync_status_sk(hdev, HCI_OP_CHANGE_CONN_PTYPE, + sizeof(*cp), cp, + HCI_EV_PKT_TYPE_CHANGE, + HCI_CMD_TIMEOUT, NULL); +} + +int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_cp_change_conn_ptype *cp; + + cp = kmalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + cp->handle = cpu_to_le16(conn->handle); + cp->pkt_type = cpu_to_le16(pkt_type); + + return hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp, + pkt_type_changed); +} + +static void le_phy_update_complete(struct hci_dev *hdev, void *data, int err) +{ + struct hci_cp_le_set_phy *cp = data; + + bt_dev_dbg(hdev, "err %d", err); + + kfree(cp); +} + +static int hci_le_set_phy_sync(struct hci_dev *hdev, void *data) +{ + struct hci_cp_le_set_phy *cp = data; + + return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_SET_PHY, + sizeof(*cp), cp, + HCI_EV_LE_PHY_UPDATE_COMPLETE, + HCI_CMD_TIMEOUT, NULL); +} + +int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_cp_le_set_phy *cp; + + cp = kmalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + memset(cp, 0, sizeof(*cp)); + cp->handle = cpu_to_le16(conn->handle); + cp->tx_phys = tx_phys; + cp->rx_phys = rx_phys; + + return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp, + le_phy_update_complete); +} diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 9ee189c815d4..3ba3ce7eaa98 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -885,7 +885,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, struct bt_power pwr; struct l2cap_conn *conn; int err = 0; - u32 opt; + u32 opt, phys; u16 mtu; u8 mode; @@ -1059,6 +1059,24 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; + case BT_PHY: + if (sk->sk_state != BT_CONNECTED) { + err = -ENOTCONN; + break; + } + + err = copy_safe_from_sockptr(&phys, sizeof(phys), optval, + optlen); + if (err) + break; + + if (!chan->conn) + break; + + conn = chan->conn; + err = hci_conn_set_phy(conn->hcon, phys); + break; + case BT_MODE: if (!enable_ecred) { err = -ENOPROTOOPT; From ff3bb47ab4ca4f3bac5f680d63456353892b4500 Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Tue, 6 Jan 2026 12:35:02 +0800 Subject: [PATCH 11/40] Bluetooth: btqca: move WCN7850 workaround to the caller WCN7850 will first attempt to use ELF_TYPE_PATCH, and if that fails, it will fall back to TLV_TYPE_PATCH. To code uniformity, move WCN7850 workaround to the caller. Reviewed-by: Dmitry Baryshkov Signed-off-by: Shuai Zhang Acked-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btqca.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 7c958d6065be..0af3e2109f31 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -581,28 +581,11 @@ static int qca_download_firmware(struct hci_dev *hdev, ret = request_firmware(&fw, config->fwname, &hdev->dev); if (ret) { - /* For WCN6750, if mbn file is not present then check for - * tlv file. - */ - if (soc_type == QCA_WCN6750 && config->type == ELF_TYPE_PATCH) { - bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)", - config->fwname, ret); - config->type = TLV_TYPE_PATCH; - snprintf(config->fwname, sizeof(config->fwname), - "qca/msbtfw%02x.tlv", rom_ver); - bt_dev_info(hdev, "QCA Downloading %s", config->fwname); - ret = request_firmware(&fw, config->fwname, &hdev->dev); - if (ret) { - bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", - config->fwname, ret); - return ret; - } - } /* If the board-specific file is missing, try loading the default * one, unless that was attempted already. */ - else if (config->type == TLV_TYPE_NVM && - qca_get_alt_nvm_file(config->fwname, sizeof(config->fwname))) { + if (config->type == TLV_TYPE_NVM && + qca_get_alt_nvm_file(config->fwname, sizeof(config->fwname))) { bt_dev_info(hdev, "QCA Downloading %s", config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); if (ret) { @@ -861,8 +844,22 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } err = qca_download_firmware(hdev, &config, soc_type, rom_ver); + /* For WCN6750, if mbn file is not present then check for + * tlv file. + */ + if (err < 0 && soc_type == QCA_WCN6750) { + bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)", + config.fwname, err); + config.type = TLV_TYPE_PATCH; + snprintf(config.fwname, sizeof(config.fwname), + "qca/msbtfw%02x.tlv", rom_ver); + bt_dev_info(hdev, "QCA Downloading %s", config.fwname); + err = qca_download_firmware(hdev, &config, soc_type, rom_ver); + } + if (err < 0) { - bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); + bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", + config.fwname, err); return err; } From 520257cff5edc57e3a940a45cec3de7c69d60913 Mon Sep 17 00:00:00 2001 From: Shuai Zhang Date: Tue, 6 Jan 2026 12:35:03 +0800 Subject: [PATCH 12/40] Bluetooth: btqca: Add WCN6855 firmware priority selection feature Historically, WCN685x and QCA2066 shared the same firmware files. Now, changes are planned for the firmware that will make it incompatible with QCA2066, so a new firmware name is required for WCN685x. Test Steps: - Boot device - Check the BTFW loading status via dmesg Sanity pass and Test Log: QCA Downloading qca/wcnhpbftfw21.tlv Direct firmware load for qca/wcnhpbftfw21.tlv failed with error -2 QCA Downloading qca/hpbftfw21.tlv Reviewed-by: Dmitry Baryshkov Signed-off-by: Shuai Zhang Acked-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btqca.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 0af3e2109f31..74f820e89655 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -830,8 +830,12 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, "qca/msbtfw%02x.mbn", rom_ver); break; case QCA_WCN6855: + /* Due to historical reasons, WCN685x chip has been using firmware + * without the "wcn" prefix. The mapping between the chip and its + * corresponding firmware has now been corrected. + */ snprintf(config.fwname, sizeof(config.fwname), - "qca/hpbtfw%02x.tlv", rom_ver); + "qca/wcnhpbtfw%02x.tlv", rom_ver); break; case QCA_WCN7850: snprintf(config.fwname, sizeof(config.fwname), @@ -855,6 +859,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, "qca/msbtfw%02x.tlv", rom_ver); bt_dev_info(hdev, "QCA Downloading %s", config.fwname); err = qca_download_firmware(hdev, &config, soc_type, rom_ver); + } else if (err < 0 && !rampatch_name && soc_type == QCA_WCN6855) { + snprintf(config.fwname, sizeof(config.fwname), + "qca/hpbtfw%02x.tlv", rom_ver); + err = qca_download_firmware(hdev, &config, soc_type, rom_ver); } if (err < 0) { @@ -920,7 +928,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, case QCA_WCN6855: qca_read_fw_board_id(hdev, &boardid); qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname), - "hpnv", soc_type, ver, rom_ver, boardid); + "wcnhpnv", soc_type, ver, rom_ver, boardid); break; case QCA_WCN7850: qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname), @@ -933,8 +941,15 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } err = qca_download_firmware(hdev, &config, soc_type, rom_ver); + if (err < 0 && !firmware_name && soc_type == QCA_WCN6855) { + qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname), + "hpnv", soc_type, ver, rom_ver, boardid); + err = qca_download_firmware(hdev, &config, soc_type, rom_ver); + } + if (err < 0) { - bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); + bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", + config.fwname, err); return err; } From e07094a51ad8faf98ea64320799ce550828e97cd Mon Sep 17 00:00:00 2001 From: Techie Ernie Date: Wed, 24 Dec 2025 11:31:29 +0800 Subject: [PATCH 13/40] Bluetooth: btusb: Add USB ID 0489:e112 for Realtek 8851BE Add USB ID 0489:e112 for the Realtek 8851BE Bluetooth adapter. Without this entry, the device is not handled correctly by btusb and Bluetooth fails to initialise. Adding the ID enables proper Realtek initialization for Bluetooth to work on various motherboards using this Bluetooth adapter. The device identifies as: Bus 001 Device XXX: ID 0489:e112 Foxconn / Hon Hai Bluetooth Radio Tested on Realtek 8851BE. Bluetooth works after this change is made. Signed-off-by: Techie Ernie Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 646de80c7e7b..de9e484efef7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -521,6 +521,8 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3601), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x0489, 0xe112), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8851BU Bluetooth devices */ { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | From 0e2a6af81042e048bef1fddc70a022272d11ae84 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 22 Dec 2025 14:36:45 -0500 Subject: [PATCH 14/40] Bluetooth: Fix using PHYs bitfields as PHY value This renames the PHY fields in bt_iso_io_qos to PHYs (plural) since it represents a bitfield where multiple PHYs can be set and make the same change also to HCI_OP_LE_SET_CIG_PARAMS since both c_phy and p_phy fields are bitfields. This also fixes the assumption that hci_evt_le_cis_established PHYs fields are compatible with bt_iso_io_qos, they are not, the fields in hci_evt_le_cis_established represent just a single PHY value so they need to be converted to bitfield when set in bt_iso_io_qos. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 8 +++---- include/net/bluetooth/hci.h | 6 +++--- net/bluetooth/hci_conn.c | 35 ++++++++++++++++--------------- net/bluetooth/hci_event.c | 23 ++++++++++++++++---- net/bluetooth/hci_sync.c | 6 +++--- net/bluetooth/iso.c | 10 ++++----- 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 89a60919050b..69eed69f7f26 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -182,7 +182,7 @@ struct bt_iso_io_qos { __u32 interval; __u16 latency; __u16 sdu; - __u8 phy; + __u8 phys; __u8 rtn; }; @@ -221,9 +221,9 @@ struct bt_iso_qos { }; }; -#define BT_ISO_PHY_1M 0x01 -#define BT_ISO_PHY_2M 0x02 -#define BT_ISO_PHY_CODED 0x04 +#define BT_ISO_PHY_1M BIT(0) +#define BT_ISO_PHY_2M BIT(1) +#define BT_ISO_PHY_CODED BIT(2) #define BT_ISO_PHY_ANY (BT_ISO_PHY_1M | BT_ISO_PHY_2M | \ BT_ISO_PHY_CODED) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index db76c2d1eeaa..89ad9470fa71 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1891,7 +1891,7 @@ struct hci_cp_le_set_phy { __u8 all_phys; __u8 tx_phys; __u8 rx_phys; - __le16 phy_opts; + __le16 phy_opts; } __packed; #define HCI_OP_LE_SET_EXT_SCAN_PARAMS 0x2041 @@ -2147,8 +2147,8 @@ struct hci_cis_params { __u8 cis_id; __le16 c_sdu; __le16 p_sdu; - __u8 c_phy; - __u8 p_phy; + __u8 c_phys; + __u8 p_phys; __u8 c_rtn; __u8 p_rtn; } __packed; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1a4b6badf2b3..0795818963a5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1825,7 +1825,7 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos) cp.bis.sdu = cpu_to_le16(qos->bcast.out.sdu); cp.bis.latency = cpu_to_le16(qos->bcast.out.latency); cp.bis.rtn = qos->bcast.out.rtn; - cp.bis.phy = qos->bcast.out.phy; + cp.bis.phy = qos->bcast.out.phys; cp.bis.packing = qos->bcast.packing; cp.bis.framing = qos->bcast.framing; cp.bis.encryption = qos->bcast.encryption; @@ -1875,10 +1875,10 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data) cis->cis_id = cis_id; cis->c_sdu = cpu_to_le16(conn->iso_qos.ucast.out.sdu); cis->p_sdu = cpu_to_le16(conn->iso_qos.ucast.in.sdu); - cis->c_phy = qos->ucast.out.phy ? qos->ucast.out.phy : - qos->ucast.in.phy; - cis->p_phy = qos->ucast.in.phy ? qos->ucast.in.phy : - qos->ucast.out.phy; + cis->c_phys = qos->ucast.out.phys ? qos->ucast.out.phys : + qos->ucast.in.phys; + cis->p_phys = qos->ucast.in.phys ? qos->ucast.in.phys : + qos->ucast.out.phys; cis->c_rtn = qos->ucast.out.rtn; cis->p_rtn = qos->ucast.in.rtn; } @@ -1980,8 +1980,8 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, return cis; /* Update LINK PHYs according to QoS preference */ - cis->le_tx_phy = qos->ucast.out.phy; - cis->le_rx_phy = qos->ucast.in.phy; + cis->le_tx_phy = qos->ucast.out.phys; + cis->le_rx_phy = qos->ucast.in.phys; /* If output interval is not set use the input interval as it cannot be * 0x000000. @@ -2096,15 +2096,15 @@ int hci_le_create_cis_pending(struct hci_dev *hdev) } static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, - struct bt_iso_io_qos *qos, __u8 phy) + struct bt_iso_io_qos *qos, __u8 phys) { /* Only set MTU if PHY is enabled */ - if (!qos->sdu && qos->phy) + if (!qos->sdu && qos->phys) qos->sdu = conn->mtu; /* Use the same PHY as ACL if set to any */ - if (qos->phy == BT_ISO_PHY_ANY) - qos->phy = phy; + if (qos->phys == BT_ISO_PHY_ANY) + qos->phys = phys; /* Use LE ACL connection interval if not set */ if (!qos->interval) @@ -2124,7 +2124,7 @@ static int create_big_sync(struct hci_dev *hdev, void *data) u32 flags = 0; int err; - if (qos->bcast.out.phy == 0x02) + if (qos->bcast.out.phys == BIT(1)) flags |= MGMT_ADV_FLAG_SEC_2M; /* Align intervals */ @@ -2233,8 +2233,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, return conn; /* Update LINK PHYs according to QoS preference */ - conn->le_tx_phy = qos->bcast.out.phy; - conn->le_tx_phy = qos->bcast.out.phy; + conn->le_tx_def_phys = qos->bcast.out.phys; /* Add Basic Announcement into Peridic Adv Data if BASE is set */ if (base_len && base) { @@ -2243,7 +2242,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, } hci_iso_qos_setup(hdev, conn, &qos->bcast.out, - conn->le_tx_phy ? conn->le_tx_phy : + conn->le_tx_def_phys ? conn->le_tx_def_phys : hdev->le_tx_def_phys); conn->iso_qos = *qos; @@ -2363,9 +2362,11 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, return le; hci_iso_qos_setup(hdev, le, &qos->ucast.out, - le->le_tx_phy ? le->le_tx_phy : hdev->le_tx_def_phys); + le->le_tx_def_phys ? le->le_tx_def_phys : + hdev->le_tx_def_phys); hci_iso_qos_setup(hdev, le, &qos->ucast.in, - le->le_rx_phy ? le->le_rx_phy : hdev->le_rx_def_phys); + le->le_rx_def_phys ? le->le_rx_def_phys : + hdev->le_rx_def_phys); cis = hci_bind_cis(hdev, dst, dst_type, qos, timeout); if (IS_ERR(cis)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 467710a42d45..286529d2e554 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6867,6 +6867,21 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, void *data, hci_dev_unlock(hdev); } +/* Convert LE PHY to QoS PHYs */ +static u8 le_phy_qos(u8 phy) +{ + switch (phy) { + case 0x01: + return HCI_LE_SET_PHY_1M; + case 0x02: + return HCI_LE_SET_PHY_2M; + case 0x03: + return HCI_LE_SET_PHY_CODED; + } + + return 0; +} + static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -6928,8 +6943,8 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, 1000); qos->ucast.in.sdu = ev->c_bn ? le16_to_cpu(ev->c_mtu) : 0; qos->ucast.out.sdu = ev->p_bn ? le16_to_cpu(ev->p_mtu) : 0; - qos->ucast.in.phy = ev->c_phy; - qos->ucast.out.phy = ev->p_phy; + qos->ucast.in.phys = le_phy_qos(ev->c_phy); + qos->ucast.out.phys = le_phy_qos(ev->p_phy); break; case HCI_ROLE_MASTER: qos->ucast.in.interval = p_sdu_interval; @@ -6943,8 +6958,8 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, 1000); qos->ucast.out.sdu = ev->c_bn ? le16_to_cpu(ev->c_mtu) : 0; qos->ucast.in.sdu = ev->p_bn ? le16_to_cpu(ev->p_mtu) : 0; - qos->ucast.out.phy = ev->c_phy; - qos->ucast.in.phy = ev->p_phy; + qos->ucast.out.phys = le_phy_qos(ev->c_phy); + qos->ucast.in.phys = le_phy_qos(ev->p_phy); break; } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 0e6660ddc00a..f04a90bce4a9 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2948,8 +2948,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type, if (conn) { struct bt_iso_qos *qos = &conn->iso_qos; - if (qos->bcast.in.phy & BT_ISO_PHY_1M || - qos->bcast.in.phy & BT_ISO_PHY_2M) { + if (qos->bcast.in.phys & BT_ISO_PHY_1M || + qos->bcast.in.phys & BT_ISO_PHY_2M) { cp->scanning_phys |= LE_SCAN_PHY_1M; hci_le_scan_phy_params(phy, type, interval, @@ -2958,7 +2958,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type, phy++; } - if (qos->bcast.in.phy & BT_ISO_PHY_CODED) { + if (qos->bcast.in.phys & BT_ISO_PHY_CODED) { cp->scanning_phys |= LE_SCAN_PHY_CODED; hci_le_scan_phy_params(phy, type, interval * 3, diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index e36d24a9098b..1459ab161fd2 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -361,7 +361,7 @@ static int iso_connect_bis(struct sock *sk) } /* Fail if out PHYs are marked as disabled */ - if (!iso_pi(sk)->qos.bcast.out.phy) { + if (!iso_pi(sk)->qos.bcast.out.phys) { err = -EINVAL; goto unlock; } @@ -458,7 +458,7 @@ static int iso_connect_cis(struct sock *sk) } /* Fail if either PHYs are marked as disabled */ - if (!iso_pi(sk)->qos.ucast.in.phy && !iso_pi(sk)->qos.ucast.out.phy) { + if (!iso_pi(sk)->qos.ucast.in.phys && !iso_pi(sk)->qos.ucast.out.phys) { err = -EINVAL; goto unlock; } @@ -894,7 +894,7 @@ static struct proto iso_proto = { .interval = 10000u, \ .latency = 10u, \ .sdu = 40u, \ - .phy = BT_ISO_PHY_2M, \ + .phys = BT_ISO_PHY_2M, \ .rtn = 2u, \ } @@ -1661,7 +1661,7 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, static bool check_io_qos(struct bt_iso_io_qos *qos) { /* If no PHY is enable SDU must be 0 */ - if (!qos->phy && qos->sdu) + if (!qos->phys && qos->sdu) return false; if (qos->interval && (qos->interval < 0xff || qos->interval > 0xfffff)) @@ -1670,7 +1670,7 @@ static bool check_io_qos(struct bt_iso_io_qos *qos) if (qos->latency && (qos->latency < 0x05 || qos->latency > 0xfa0)) return false; - if (qos->phy > BT_ISO_PHY_ANY) + if (qos->phys > BT_ISO_PHY_ANY) return false; return true; From 68f3769ce01631eb6710b811e2dc5d767b76c5b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:48:58 +0100 Subject: [PATCH 15/40] dt-bindings: bluetooth: qcom,qca2066-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split common part and qcom,qca2066-bt to separate bindings, so each schema will be easier to read/maintain and list only relevant properties. The existing bindings do not mention interrupts, but am335x-sancloud-bbe-extended-wifi.dts already defines such. This issue is not being fixed here. Existing binding also did not mention any supplies (which do exist as confirmed in datasheet) and Linux driver does not ask for any, thus keep this state unchanged. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,bluetooth-common.yaml | 25 ++++++++++ .../net/bluetooth/qcom,qca2066-bt.yaml | 49 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 25 +--------- MAINTAINERS | 1 + 4 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,qca2066-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml new file mode 100644 index 000000000000..c8e9c55c1afb --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,bluetooth-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Bluetooth Common Properties + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + firmware-name: + minItems: 1 + items: + - description: specify the name of nvm firmware to load + - description: specify the name of rampatch firmware to load + + qcom,local-bd-address-broken: + type: boolean + description: + boot firmware is incorrectly passing the address in big-endian order + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,qca2066-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca2066-bt.yaml new file mode 100644 index 000000000000..d4f167c9b7e1 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca2066-bt.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,qca2066-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCA2006 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,qca2066-bt + - qcom,qca6174-bt + + clocks: + items: + - description: External low-power 32.768 kHz clock input + + enable-gpios: + maxItems: 1 + +required: + - compatible + - clocks + - enable-gpios + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + serial { + bluetooth { + compatible = "qcom,qca6174-bt"; + clocks = <&divclk4>; + enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>; + firmware-name = "nvm_00440302.bin"; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 6353a336f382..85d10d94700f 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,8 +16,6 @@ description: properties: compatible: enum: - - qcom,qca2066-bt - - qcom,qca6174-bt - qcom,qca9377-bt - qcom,wcn3950-bt - qcom,wcn3988-bt @@ -122,17 +120,6 @@ additionalProperties: false allOf: - $ref: bluetooth-controller.yaml# - $ref: /schemas/serial/serial-peripheral-props.yaml# - - if: - properties: - compatible: - contains: - enum: - - qcom,qca2066-bt - - qcom,qca6174-bt - then: - required: - - enable-gpios - - clocks - if: properties: @@ -211,17 +198,6 @@ allOf: - vddrfa1p7-supply examples: - - | - #include - serial { - - bluetooth { - compatible = "qcom,qca6174-bt"; - enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>; - clocks = <&divclk4>; - firmware-name = "nvm_00440302.bin"; - }; - }; - | serial { @@ -236,6 +212,7 @@ examples: }; }; - | + #include serial { bluetooth { diff --git a/MAINTAINERS b/MAINTAINERS index c3a2a11d6dd9..5574dde1bce0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21379,6 +21379,7 @@ QUALCOMM BLUETOOTH DRIVER M: Bartosz Golaszewski L: linux-arm-msm@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/bluetooth/qcom,* F: drivers/bluetooth/btqca.[ch] F: drivers/bluetooth/btqcomsmd.c F: drivers/bluetooth/hci_qca.c From e18c153d1fe4fe8567b904fd39355e4ffae69cc3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:48:59 +0100 Subject: [PATCH 16/40] dt-bindings: bluetooth: qcom,qca9377-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,qca9377-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Existing binding has incomplete and incorrect list of supplies (e.g. there is no VDD_XO) and Linux driver does not ask for any, thus keep this state unchanged. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,qca9377-bt.yaml | 58 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 1 - 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,qca9377-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,qca9377-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca9377-bt.yaml new file mode 100644 index 000000000000..3fe9476c1d74 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca9377-bt.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,qca9377-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCA9377 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,qca9377-bt + + clocks: + items: + - description: External low-power 32.768 kHz clock input + + enable-gpios: + maxItems: 1 + + vddio-supply: + description: VDD_IO supply regulator handle + + vddxo-supply: + description: VDD_XO supply regulator handle + +required: + - compatible + - clocks + - enable-gpios + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + serial { + bluetooth { + compatible = "qcom,qca9377-bt"; + clocks = <&rk809 1>; + enable-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; + max-speed = <2000000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_enable>; + vddio-supply = <&vcc_1v8>; + vddxo-supply = <&vcc3v3_sys>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 85d10d94700f..dba867ef3d06 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,7 +16,6 @@ description: properties: compatible: enum: - - qcom,qca9377-bt - qcom,wcn3950-bt - qcom,wcn3988-bt - qcom,wcn3990-bt From 31a8753aa495d428acfd3468c73f18e1ac2cdc64 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:00 +0100 Subject: [PATCH 17/40] dt-bindings: bluetooth: qcom,qca6390-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,qca6390-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,qca6390-bt.yaml | 64 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 15 ----- 2 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,qca6390-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,qca6390-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca6390-bt.yaml new file mode 100644 index 000000000000..cffbc9e61cd6 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,qca6390-bt.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,qca6390-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCA6390 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,qca6390-bt + + vddaon-supply: + description: VDD_AON supply regulator handle + + vddbtcmx-supply: + description: VDD_BT_CMX supply regulator handle + + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + + vddrfa1p2-supply: + description: VDD_RFA_1P2 supply regulator handle + + vddrfa1p7-supply: + description: VDD_RFA_1P7 supply regulator handle + + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + +required: + - compatible + - vddaon-supply + - vddbtcmx-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p7-supply + - vddrfacmn-supply + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + serial { + bluetooth { + compatible = "qcom,qca6390-bt"; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index dba867ef3d06..ac58d6598091 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -21,7 +21,6 @@ properties: - qcom,wcn3990-bt - qcom,wcn3991-bt - qcom,wcn3998-bt - - qcom,qca6390-bt - qcom,wcn6750-bt - qcom,wcn6855-bt - qcom,wcn7850-bt @@ -181,20 +180,6 @@ allOf: - vddrfa0p8-supply - vddrfa1p2-supply - vddrfa1p8-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,qca6390-bt - then: - required: - - vddrfacmn-supply - - vddaon-supply - - vddbtcmx-supply - - vddrfa0p8-supply - - vddrfa1p2-supply - - vddrfa1p7-supply examples: - | From dcf72cd989900d7f92a23d22db0a9ec3d1cc5eb1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:01 +0100 Subject: [PATCH 18/40] dt-bindings: bluetooth: qcom,wcn3950-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,wcn3950-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,wcn3950-bt.yaml | 67 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 4 -- 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3950-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3950-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3950-bt.yaml new file mode 100644 index 000000000000..83382f3c9049 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3950-bt.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,wcn3950-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCN3950/WCN3988 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,wcn3950-bt + - qcom,wcn3988-bt + + enable-gpios: + maxItems: 1 + + swctrl-gpios: + maxItems: 1 + description: gpio specifier is used to find status + of clock supply to SoC + + vddch0-supply: + description: VDD_CH0 supply regulator handle + + vddio-supply: + description: VDD_IO supply regulator handle + + vddrf-supply: + description: VDD_RF supply regulator handle + + vddxo-supply: + description: VDD_XO supply regulator handle + +required: + - compatible + - vddch0-supply + - vddio-supply + - vddrf-supply + - vddxo-supply + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + serial { + bluetooth { + compatible = "qcom,wcn3950-bt"; + enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>; + max-speed = <3200000>; + vddch0-supply = <&pm4125_l22>; + vddio-supply = <&pm4125_l15>; + vddrf-supply = <&pm4125_l10>; + vddxo-supply = <&pm4125_l13>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index ac58d6598091..82cce508e295 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,8 +16,6 @@ description: properties: compatible: enum: - - qcom,wcn3950-bt - - qcom,wcn3988-bt - qcom,wcn3990-bt - qcom,wcn3991-bt - qcom,wcn3998-bt @@ -124,8 +122,6 @@ allOf: compatible: contains: enum: - - qcom,wcn3950-bt - - qcom,wcn3988-bt - qcom,wcn3990-bt - qcom,wcn3991-bt - qcom,wcn3998-bt From 77f1835364c86a660b7d95b69c598d6373c4f13f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:02 +0100 Subject: [PATCH 19/40] dt-bindings: bluetooth: qcom,wcn3990-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,wcn3990-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. This binding is very similar to qcom,wcn3950-bt, however devices have additional VDD_CH1 supply. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,wcn3990-bt.yaml | 66 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 47 ------------- 2 files changed, 66 insertions(+), 47 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3990-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3990-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3990-bt.yaml new file mode 100644 index 000000000000..89ceb1f7def0 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn3990-bt.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,wcn3990-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCN3990/WCN3991/WCN3998 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,wcn3990-bt + - qcom,wcn3991-bt + - qcom,wcn3998-bt + + clocks: + items: + - description: External low-power 32.768 kHz clock input + + vddch0-supply: + description: VDD_CH0 supply regulator handle + + vddch1-supply: + description: VDD_CH1 supply regulator handle + + vddio-supply: + description: VDD_IO supply regulator handle + + vddrf-supply: + description: VDD_RF supply regulator handle + + vddxo-supply: + description: VDD_XO supply regulator handle + +required: + - compatible + - vddch0-supply + - vddio-supply + - vddrf-supply + - vddxo-supply + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + serial { + bluetooth { + compatible = "qcom,wcn3990-bt"; + firmware-name = "crnv21.bin"; + max-speed = <3200000>; + vddio-supply = <&vreg_s4a_1p8>; + vddch0-supply = <&vreg_l25a_3p3>; + vddch1-supply = <&vreg_l23a_3p3>; + vddrf-supply = <&vreg_l17a_1p3>; + vddxo-supply = <&vreg_l7a_1p8>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 82cce508e295..5581e810f08e 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,9 +16,6 @@ description: properties: compatible: enum: - - qcom,wcn3990-bt - - qcom,wcn3991-bt - - qcom,wcn3998-bt - qcom,wcn6750-bt - qcom,wcn6855-bt - qcom,wcn7850-bt @@ -32,25 +29,9 @@ properties: description: gpio specifier is used to find status of clock supply to SoC - clocks: - maxItems: 1 - description: clock provided to the controller (SUSCLK_32KHZ) - vddio-supply: description: VDD_IO supply regulator handle - vddxo-supply: - description: VDD_XO supply regulator handle - - vddrf-supply: - description: VDD_RF supply regulator handle - - vddch0-supply: - description: VDD_CH0 supply regulator handle - - vddch1-supply: - description: VDD_CH1 supply regulator handle - vddaon-supply: description: VDD_AON supply regulator handle @@ -117,21 +98,6 @@ allOf: - $ref: bluetooth-controller.yaml# - $ref: /schemas/serial/serial-peripheral-props.yaml# - - if: - properties: - compatible: - contains: - enum: - - qcom,wcn3990-bt - - qcom,wcn3991-bt - - qcom,wcn3998-bt - then: - required: - - vddio-supply - - vddxo-supply - - vddrf-supply - - vddch0-supply - - if: properties: compatible: @@ -178,19 +144,6 @@ allOf: - vddrfa1p8-supply examples: - - | - serial { - - bluetooth { - compatible = "qcom,wcn3990-bt"; - vddio-supply = <&vreg_s4a_1p8>; - vddxo-supply = <&vreg_l7a_1p8>; - vddrf-supply = <&vreg_l17a_1p3>; - vddch0-supply = <&vreg_l25a_3p3>; - max-speed = <3200000>; - firmware-name = "crnv21.bin"; - }; - }; - | #include serial { From af97be93b4da4631e1e7e3a99189d7b5866f5e44 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:03 +0100 Subject: [PATCH 20/40] dt-bindings: bluetooth: qcom,wcn6750-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,wcn6750-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,wcn6750-bt.yaml | 86 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 45 ---------- 2 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml new file mode 100644 index 000000000000..f11d12c205fa --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,wcn6750-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCN6750 Bluetooth + +maintainers: + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,wcn6750-bt + + enable-gpios: + maxItems: 1 + + swctrl-gpios: + maxItems: 1 + description: gpio specifier is used to find status + of clock supply to SoC + + vddaon-supply: + description: VDD_AON supply regulator handle + + vddasd-supply: + description: VDD_ASD supply regulator handle + + vddbtcmx-supply: + description: VDD_BT_CMX supply regulator handle + + vddbtcxmx-supply: + description: VDD_BT_CXMX supply regulator handle + + vddio-supply: + description: VDD_IO supply regulator handle + + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + + vddrfa1p2-supply: + description: VDD_RFA_1P2 supply regulator handle + + vddrfa1p7-supply: + description: VDD_RFA_1P7 supply regulator handle + + vddrfa2p2-supply: + description: VDD_RFA_2P2 supply regulator handle + + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + +required: + - compatible + - vddaon-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p7-supply + - vddrfacmn-supply + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + serial { + bluetooth { + compatible = "qcom,wcn6750-bt"; + + firmware-name = "msnv11.bin"; + max-speed = <3200000>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 5581e810f08e..1ee97089e1d5 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,7 +16,6 @@ description: properties: compatible: enum: - - qcom,wcn6750-bt - qcom,wcn6855-bt - qcom,wcn7850-bt @@ -62,12 +61,6 @@ properties: vddrfa1p9-supply: description: VDD_RFA_1P9 supply regulator handle - vddrfa2p2-supply: - description: VDD_RFA_2P2 supply regulator handle - - vddasd-supply: - description: VDD_ASD supply regulator handle - vddwlcx-supply: description: VDD_WLCX supply regulator handle @@ -98,19 +91,6 @@ allOf: - $ref: bluetooth-controller.yaml# - $ref: /schemas/serial/serial-peripheral-props.yaml# - - if: - properties: - compatible: - contains: - enum: - - qcom,wcn6750-bt - then: - required: - - vddaon-supply - - vddrfacmn-supply - - vddrfa0p8-supply - - vddrfa1p7-supply - - vddrfa1p2-supply - if: properties: compatible: @@ -142,28 +122,3 @@ allOf: - vddrfa0p8-supply - vddrfa1p2-supply - vddrfa1p8-supply - -examples: - - | - #include - serial { - - bluetooth { - compatible = "qcom,wcn6750-bt"; - pinctrl-names = "default"; - pinctrl-0 = <&bt_en_default>; - enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; - swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; - vddio-supply = <&vreg_l19b_1p8>; - vddaon-supply = <&vreg_s7b_0p9>; - vddbtcxmx-supply = <&vreg_s7b_0p9>; - vddrfacmn-supply = <&vreg_s7b_0p9>; - vddrfa0p8-supply = <&vreg_s7b_0p9>; - vddrfa1p7-supply = <&vreg_s1b_1p8>; - vddrfa1p2-supply = <&vreg_s8b_1p2>; - vddrfa2p2-supply = <&vreg_s1c_2p2>; - vddasd-supply = <&vreg_l11c_2p8>; - max-speed = <3200000>; - firmware-name = "msnv11.bin"; - }; - }; From edd3240fd53ddf47873d9a3bccaf4b24d78fabb6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:04 +0100 Subject: [PATCH 21/40] dt-bindings: bluetooth: qcom,wcn6750-bt: Deprecate old supplies Commit cca4fe34979a ("dt-bindings: bluetooth: Utilize PMU abstraction for WCN6750") changed the binding to new description with a Power Management Unit (PMU), thus certain power-controller properties are considered deprecated and are part of that PMUs binding. Deprecate them to mark clearly that new PMU-based approach is preferred. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml index f11d12c205fa..8606a45ac9b9 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6750-bt.yaml @@ -17,26 +17,31 @@ properties: enable-gpios: maxItems: 1 + deprecated: true swctrl-gpios: maxItems: 1 description: gpio specifier is used to find status of clock supply to SoC + deprecated: true vddaon-supply: description: VDD_AON supply regulator handle vddasd-supply: description: VDD_ASD supply regulator handle + deprecated: true vddbtcmx-supply: description: VDD_BT_CMX supply regulator handle vddbtcxmx-supply: description: VDD_BT_CXMX supply regulator handle + deprecated: true vddio-supply: description: VDD_IO supply regulator handle + deprecated: true vddrfa0p8-supply: description: VDD_RFA_0P8 supply regulator handle From 1937250117d346e013f24b64c176c59b86bc2c06 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:05 +0100 Subject: [PATCH 22/40] dt-bindings: bluetooth: qcom,wcn6855-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,wcn6855-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../net/bluetooth/qcom,wcn6855-bt.yaml | 94 +++++++++++++++++++ .../net/bluetooth/qualcomm-bluetooth.yaml | 26 ----- 2 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml new file mode 100644 index 000000000000..a4a887a4dde1 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/qcom,wcn6855-bt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCN6855 Bluetooth + +maintainers: + - Bartosz Golaszewski + - Balakrishna Godavarthi + - Rocky Liao + +properties: + compatible: + enum: + - qcom,wcn6855-bt + + enable-gpios: + maxItems: 1 + + swctrl-gpios: + maxItems: 1 + description: gpio specifier is used to find status + of clock supply to SoC + + vddaon-supply: + description: VDD_AON supply regulator handle + + vddbtcmx-supply: + description: VDD_BT_CMX supply regulator handle + + vddbtcxmx-supply: + description: VDD_BT_CXMX supply regulator handle + + vddio-supply: + description: VDD_IO supply regulator handle + + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + + vddrfa1p2-supply: + description: VDD_RFA_1P2 supply regulator handle + + vddrfa1p7-supply: + description: VDD_RFA_1P7 supply regulator handle + + vddrfa1p8-supply: + description: VDD_RFA_1P8 supply regulator handle + + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + + vddwlcx-supply: + description: VDD_WLCX supply regulator handle + + vddwlmx-supply: + description: VDD_WLMX supply regulator handle + +required: + - compatible + - vddaon-supply + - vddbtcmx-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p8-supply + - vddrfacmn-supply + - vddwlcx-supply + - vddwlmx-supply + +allOf: + - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml + - $ref: /schemas/serial/serial-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + serial { + bluetooth { + compatible = "qcom,wcn6855-bt"; + + max-speed = <3000000>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 1ee97089e1d5..62d7cdb67a3a 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -16,7 +16,6 @@ description: properties: compatible: enum: - - qcom,wcn6855-bt - qcom,wcn7850-bt enable-gpios: @@ -37,21 +36,12 @@ properties: vdddig-supply: description: VDD_DIG supply regulator handle - vddbtcmx-supply: - description: VDD_BT_CMX supply regulator handle - - vddbtcxmx-supply: - description: VDD_BT_CXMX supply regulator handle - vddrfacmn-supply: description: VDD_RFA_CMN supply regulator handle vddrfa0p8-supply: description: VDD_RFA_0P8 supply regulator handle - vddrfa1p7-supply: - description: VDD_RFA_1P7 supply regulator handle - vddrfa1p8-supply: description: VDD_RFA_1P8 supply regulator handle @@ -91,22 +81,6 @@ allOf: - $ref: bluetooth-controller.yaml# - $ref: /schemas/serial/serial-peripheral-props.yaml# - - if: - properties: - compatible: - contains: - enum: - - qcom,wcn6855-bt - then: - required: - - vddrfacmn-supply - - vddaon-supply - - vddwlcx-supply - - vddwlmx-supply - - vddbtcmx-supply - - vddrfa0p8-supply - - vddrfa1p2-supply - - vddrfa1p8-supply - if: properties: compatible: From 6e62e4016ff58ce9f987abde572359728bae0f83 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:06 +0100 Subject: [PATCH 23/40] dt-bindings: bluetooth: qcom,wcn6855-bt: Deprecate old supplies Commit 5f4f954bba12 ("dt-bindings: bluetooth: bring the HW description closer to reality for wcn6855") changed the binding to new description with a Power Management Unit (PMU), thus certain power-controller properties are considered deprecated and are part of that PMUs binding. Deprecate them to mark clearly that new PMU-based approach is preferred. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml index a4a887a4dde1..45630067d3c8 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn6855-bt.yaml @@ -18,11 +18,13 @@ properties: enable-gpios: maxItems: 1 + deprecated: true swctrl-gpios: maxItems: 1 description: gpio specifier is used to find status of clock supply to SoC + deprecated: true vddaon-supply: description: VDD_AON supply regulator handle @@ -32,9 +34,11 @@ properties: vddbtcxmx-supply: description: VDD_BT_CXMX supply regulator handle + deprecated: true vddio-supply: description: VDD_IO supply regulator handle + deprecated: true vddrfa0p8-supply: description: VDD_RFA_0P8 supply regulator handle @@ -44,6 +48,7 @@ properties: vddrfa1p7-supply: description: VDD_RFA_1P7 supply regulator handle + deprecated: true vddrfa1p8-supply: description: VDD_RFA_1P8 supply regulator handle From 04ff82107412b28cbc67adbd5cad8d10028faef3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:07 +0100 Subject: [PATCH 24/40] dt-bindings: bluetooth: qcom,wcn7850-bt: Split to separate schema One big Qualcomm Bluetooth schema is hardly manageable: it lists all possible properties (19 supplies). Split qcom,wcn7850-bt to separate bindings, so device schema will be easier to read/maintain and list only relevant properties. Re-shuffle few properties to alphabetical order while moving them and drop redundant enable-gpios description. This makes the source qualcomm-bluetooth.yaml binding empty, thus drop it making entire change a variant of file rename. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- ...mm-bluetooth.yaml => qcom,wcn7850-bt.yaml} | 83 +++++++++---------- 1 file changed, 37 insertions(+), 46 deletions(-) rename Documentation/devicetree/bindings/net/bluetooth/{qualcomm-bluetooth.yaml => qcom,wcn7850-bt.yaml} (57%) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml similarity index 57% rename from Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml rename to Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml index 62d7cdb67a3a..bd628e48b4e1 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml @@ -1,18 +1,16 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/net/bluetooth/qualcomm-bluetooth.yaml# +$id: http://devicetree.org/schemas/net/bluetooth/qcom,wcn7850-bt.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm Bluetooth Chips +title: Qualcomm WCN7850 Bluetooth maintainers: + - Bartosz Golaszewski - Balakrishna Godavarthi - Rocky Liao -description: - This binding describes Qualcomm UART-attached bluetooth chips. - properties: compatible: enum: @@ -20,79 +18,72 @@ properties: enable-gpios: maxItems: 1 - description: gpio specifier used to enable chip swctrl-gpios: maxItems: 1 description: gpio specifier is used to find status of clock supply to SoC - vddio-supply: - description: VDD_IO supply regulator handle - vddaon-supply: description: VDD_AON supply regulator handle vdddig-supply: description: VDD_DIG supply regulator handle - vddrfacmn-supply: - description: VDD_RFA_CMN supply regulator handle + vddio-supply: + description: VDD_IO supply regulator handle vddrfa0p8-supply: description: VDD_RFA_0P8 supply regulator handle - vddrfa1p8-supply: - description: VDD_RFA_1P8 supply regulator handle - vddrfa1p2-supply: description: VDD_RFA_1P2 supply regulator handle + vddrfa1p8-supply: + description: VDD_RFA_1P8 supply regulator handle + vddrfa1p9-supply: description: VDD_RFA_1P9 supply regulator handle + vddrfacmn-supply: + description: VDD_RFA_CMN supply regulator handle + vddwlcx-supply: description: VDD_WLCX supply regulator handle vddwlmx-supply: description: VDD_WLMX supply regulator handle - max-speed: true - - firmware-name: - minItems: 1 - items: - - description: specify the name of nvm firmware to load - - description: specify the name of rampatch firmware to load - - local-bd-address: true - - qcom,local-bd-address-broken: - type: boolean - description: - boot firmware is incorrectly passing the address in big-endian order - required: - compatible - -additionalProperties: false + - vddrfacmn-supply + - vddaon-supply + - vddwlcx-supply + - vddwlmx-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p8-supply allOf: - $ref: bluetooth-controller.yaml# + - $ref: qcom,bluetooth-common.yaml - $ref: /schemas/serial/serial-peripheral-props.yaml# - - if: - properties: - compatible: - contains: - enum: - - qcom,wcn7850-bt - then: - required: - - vddrfacmn-supply - - vddaon-supply - - vddwlcx-supply - - vddwlmx-supply - - vddrfa0p8-supply - - vddrfa1p2-supply - - vddrfa1p8-supply +unevaluatedProperties: false + +examples: + - | + serial { + bluetooth { + compatible = "qcom,wcn7850-bt"; + + max-speed = <3200000>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + }; + }; From 9283a358cbc8fd93593699feda77f3ff05c77a64 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Jan 2026 16:49:08 +0100 Subject: [PATCH 25/40] dt-bindings: bluetooth: qcom,wcn7850-bt: Deprecate old supplies Commit bd3f305886ad ("dt-bindings: bluetooth: qualcomm: describe the inputs from PMU for wcn7850") changed the binding to new description with a Power Management Unit (PMU), thus certain power-controller properties are considered deprecated and are part of that PMUs binding. Deprecate them to mark clearly that new PMU-based approach is preferred. Reviewed-by: Rob Herring (Arm) Reviewed-by: Bjorn Andersson Reviewed-by: Bartosz Golaszewski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Luiz Augusto von Dentz --- .../devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml index bd628e48b4e1..8108ef83e99b 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,wcn7850-bt.yaml @@ -18,20 +18,24 @@ properties: enable-gpios: maxItems: 1 + deprecated: true swctrl-gpios: maxItems: 1 description: gpio specifier is used to find status of clock supply to SoC + deprecated: true vddaon-supply: description: VDD_AON supply regulator handle vdddig-supply: description: VDD_DIG supply regulator handle + deprecated: true vddio-supply: description: VDD_IO supply regulator handle + deprecated: true vddrfa0p8-supply: description: VDD_RFA_0P8 supply regulator handle @@ -44,6 +48,7 @@ properties: vddrfa1p9-supply: description: VDD_RFA_1P9 supply regulator handle + deprecated: true vddrfacmn-supply: description: VDD_RFA_CMN supply regulator handle From 56493c8166df7afff1da8f02bd7f6060df681f8b Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 12 Jan 2026 11:51:13 +0100 Subject: [PATCH 26/40] Bluetooth: btusb: Use pm_ptr instead of #ifdef CONFIG_PM This increases build coverage and allows to drop an #ifdef. Signed-off-by: Bastien Nocera Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index de9e484efef7..b16eb9d70dcf 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4466,7 +4466,6 @@ static void btusb_disconnect(struct usb_interface *intf) kfree(data); } -#ifdef CONFIG_PM static int btusb_suspend(struct usb_interface *intf, pm_message_t message) { struct btusb_data *data = usb_get_intfdata(intf); @@ -4620,7 +4619,6 @@ static int btusb_resume(struct usb_interface *intf) return err; } -#endif #ifdef CONFIG_DEV_COREDUMP static void btusb_coredump(struct device *dev) @@ -4637,10 +4635,8 @@ static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, .disconnect = btusb_disconnect, -#ifdef CONFIG_PM - .suspend = btusb_suspend, - .resume = btusb_resume, -#endif + .suspend = pm_ptr(btusb_suspend), + .resume = pm_ptr(btusb_resume), .id_table = btusb_table, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, From 97eb023cd1616b06584dac77a16cb9ef3abf4491 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Fri, 9 Jan 2026 10:05:37 +0800 Subject: [PATCH 27/40] Bluetooth: hci_core: Export hci_discovery_active Export hci_discovery_active() so it can be used by bluetooth drivers built as modules. Signed-off-by: Linmao Li Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8ccec73dce45..b069607b145b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -117,6 +117,7 @@ bool hci_discovery_active(struct hci_dev *hdev) return false; } } +EXPORT_SYMBOL(hci_discovery_active); void hci_discovery_set_state(struct hci_dev *hdev, int state) { From 312b09bbe9832799ff11c051060f78c9667d604a Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Fri, 9 Jan 2026 10:05:38 +0800 Subject: [PATCH 28/40] Bluetooth: btusb: Reject autosuspend if discovery is active If USB autosuspend occurs while discovery is active, the ongoing HCI operation may not complete successfully. On some devices, this can leave discovery.state stuck in DISCOVERY_FINDING. Signed-off-by: Linmao Li Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b16eb9d70dcf..1e01f8c855c9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4472,10 +4472,11 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) BT_DBG("intf %p", intf); - /* Don't auto-suspend if there are connections; external suspend calls - * shall never fail. + /* Don't auto-suspend if there are connections or discovery in + * progress; external suspend calls shall never fail. */ - if (PMSG_IS_AUTO(message) && hci_conn_count(data->hdev)) + if (PMSG_IS_AUTO(message) && + (hci_conn_count(data->hdev) || hci_discovery_active(data->hdev))) return -EBUSY; if (data->suspend_count++) From 1583ca8e85a4a96d250d9bc03d4533a326225ae8 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Fri, 16 Jan 2026 16:07:03 +0800 Subject: [PATCH 29/40] Bluetooth: btintel_pcie: Remove unnecessary check before kfree_skb() The kfree_skb() function internally checks if the skb is NULL, so an explicit check before calling it is redundant and can be removed. Signed-off-by: Chen Ni Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btintel_pcie.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 2936b535479f..3b035cb6a111 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -1190,8 +1190,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data, skb = NULL; /* skb is freed in the callee */ exit_error: - if (skb) - kfree_skb(skb); + kfree_skb(skb); if (ret) hdev->stat.err_rx++; From d9f7c39c6b7548bd70519b241b6c2d1bcc658d4b Mon Sep 17 00:00:00 2001 From: Shell Chen Date: Wed, 14 Jan 2026 15:03:35 +1100 Subject: [PATCH 30/40] Bluetooth: btusb: Add new VID/PID for RTL8852CE Add VID:PID 13d3:3612 to the quirks_table. This ID pair is found in the Realtek RTL8852CE PCIe module in an ASUS TUF A14 2025 (FA401KM) laptop. Tested on aforementioned laptop. The device info from /sys/kernel/debug/usb/devices is listed as below. T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3612 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms Signed-off-by: Shell Chen Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 1e01f8c855c9..759def260ed0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -559,6 +559,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3612), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, From 04a4c885fddf505872404f12ed9353fa4bc280c5 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 19 Jan 2026 13:34:59 +0100 Subject: [PATCH 31/40] Bluetooth: btnxpuart: Remove unneeded CONFIG_PM ifdef The functions are already disabled through the use of pm_ptr() when CONFIG_PM is disabled, and will be removed from the final linked code as not needed. This increases build coverage and allows to drop an #ifdef. Signed-off-by: Bastien Nocera Reviewed-by: Neeraj Sanjay Kale Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btnxpuart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 3b1e9224e965..e7036a48ce48 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1947,8 +1947,7 @@ static void nxp_serdev_remove(struct serdev_device *serdev) hci_free_dev(hdev); } -#ifdef CONFIG_PM_SLEEP -static int nxp_serdev_suspend(struct device *dev) +static int __maybe_unused nxp_serdev_suspend(struct device *dev) { struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev); struct ps_data *psdata = &nxpdev->psdata; @@ -1962,7 +1961,7 @@ static int nxp_serdev_suspend(struct device *dev) return 0; } -static int nxp_serdev_resume(struct device *dev) +static int __maybe_unused nxp_serdev_resume(struct device *dev) { struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev); struct ps_data *psdata = &nxpdev->psdata; @@ -1975,7 +1974,6 @@ static int nxp_serdev_resume(struct device *dev) ps_control(psdata->hdev, PS_STATE_AWAKE); return 0; } -#endif #ifdef CONFIG_DEV_COREDUMP static void nxp_serdev_coredump(struct device *dev) From 90c38d402c5c063aff23d96dbfb997defa1b1f2c Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 19 Jan 2026 13:35:00 +0100 Subject: [PATCH 32/40] Bluetooth: btintel: Remove unneeded CONFIG_PM* #ifdef's The functions are already disabled if CONFIG_PM or CONFIG_PM_SLEEP are disabled through the use of SET_SYSTEM_SLEEP_PM_OPS() and SET_RUNTIME_PM_OPS(). This increases build coverage and allows to drop a few #ifdef's. Signed-off-by: Bastien Nocera Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_intel.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 20baf2895dec..f7570c2eaa46 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -126,7 +126,6 @@ static int intel_wait_booting(struct hci_uart *hu) return err; } -#ifdef CONFIG_PM static int intel_wait_lpm_transaction(struct hci_uart *hu) { struct intel_data *intel = hu->priv; @@ -237,7 +236,6 @@ static int intel_lpm_resume(struct hci_uart *hu) return 0; } -#endif /* CONFIG_PM */ static int intel_lpm_host_wake(struct hci_uart *hu) { @@ -1066,7 +1064,6 @@ static const struct acpi_device_id intel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, intel_acpi_match); #endif -#ifdef CONFIG_PM static int intel_suspend_device(struct device *dev) { struct intel_device *idev = dev_get_drvdata(dev); @@ -1090,10 +1087,8 @@ static int intel_resume_device(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP -static int intel_suspend(struct device *dev) +static int __maybe_unused intel_suspend(struct device *dev) { struct intel_device *idev = dev_get_drvdata(dev); @@ -1103,7 +1098,7 @@ static int intel_suspend(struct device *dev) return intel_suspend_device(dev); } -static int intel_resume(struct device *dev) +static int __maybe_unused intel_resume(struct device *dev) { struct intel_device *idev = dev_get_drvdata(dev); @@ -1112,7 +1107,6 @@ static int intel_resume(struct device *dev) return intel_resume_device(dev); } -#endif static const struct dev_pm_ops intel_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) From cc6383d4f0cf6127c0552f94cae517a06ccc6b17 Mon Sep 17 00:00:00 2001 From: Jacopo Scannella Date: Tue, 20 Jan 2026 10:13:04 +0100 Subject: [PATCH 33/40] Bluetooth: btusb: Add device ID for Realtek RTL8761BU Add USB device ID 0x2c0a:0x8761 to the btusb driver fo the Realtek RTL8761BU Bluetooth adapter. Reference: https://www.startech.com/en-us/networking-io/av53c1-usb-bluetooth Signed-off-by: Jacopo Scannella Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 759def260ed0..9eea2ec775bb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -779,6 +779,7 @@ static const struct usb_device_id quirks_table[] = { /* Additional Realtek 8723BU Bluetooth devices */ { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x2c0a, 0x8761), .driver_info = BTUSB_REALTEK }, /* Additional Realtek 8723DE Bluetooth devices */ { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK }, From 890505e8effefcf21b0f2212099aa135042973d3 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Wed, 21 Jan 2026 10:52:20 +0800 Subject: [PATCH 34/40] Bluetooth: btusb: Remove duplicate entry for 0x13d3/0x3618 The USB device ID 0x13d3/0x3618 is listed twice in the device table. Remove the duplicate entry and keep the one under the correct "Realtek 8852BT/8852BE-VT Bluetooth devices" section. Signed-off-by: Linmao Li Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9eea2ec775bb..8c34a17edae5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -581,8 +581,6 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK | - BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK | From e6c0dc504e9504b4ce42632604cdbe326f961ad1 Mon Sep 17 00:00:00 2001 From: Jia-Hong Su Date: Sun, 18 Jan 2026 20:08:59 +0800 Subject: [PATCH 35/40] Bluetooth: hci_uart: fix null-ptr-deref in hci_uart_write_work hci_uart_set_proto() sets HCI_UART_PROTO_INIT before calling hci_uart_register_dev(), which calls proto->open() to initialize hu->priv. However, if a TTY write wakeup occurs during this window, hci_uart_tx_wakeup() may schedule write_work before hu->priv is initialized, leading to a NULL pointer dereference in hci_uart_write_work() when proto->dequeue() accesses hu->priv. The race condition is: CPU0 CPU1 ---- ---- hci_uart_set_proto() set_bit(HCI_UART_PROTO_INIT) hci_uart_register_dev() tty write wakeup hci_uart_tty_wakeup() hci_uart_tx_wakeup() schedule_work(&hu->write_work) proto->open(hu) // initializes hu->priv hci_uart_write_work() hci_uart_dequeue() proto->dequeue(hu) // accesses hu->priv (NULL!) Fix this by moving set_bit(HCI_UART_PROTO_INIT) after proto->open() succeeds, ensuring hu->priv is initialized before any work can be scheduled. Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") Link: https://lore.kernel.org/linux-bluetooth/6969764f.170a0220.2b9fc4.35a7@mx.google.com/ Signed-off-by: Jia-Hong Su Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_ldisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index d0adae3267b4..2b28515de92c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -685,6 +685,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) return err; } + set_bit(HCI_UART_PROTO_INIT, &hu->flags); + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) return 0; @@ -712,8 +714,6 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) hu->proto = p; - set_bit(HCI_UART_PROTO_INIT, &hu->flags); - err = hci_uart_register_dev(hu); if (err) { return err; From 4db19bfd320f2124c820d3456aeae3953095ea8e Mon Sep 17 00:00:00 2001 From: Jianpeng Chang Date: Wed, 21 Jan 2026 13:29:26 +0800 Subject: [PATCH 36/40] Bluetooth: MGMT: Fix memory leak in set_ssp_complete Fix memory leak in set_ssp_complete() where mgmt_pending_cmd structures are not freed after being removed from the pending list. Commit 302a1f674c00 ("Bluetooth: MGMT: Fix possible UAFs") replaced mgmt_pending_foreach() calls with individual command handling but missed adding mgmt_pending_free() calls in both error and success paths of set_ssp_complete(). Other completion functions like set_le_complete() were fixed correctly in the same commit. This causes a memory leak of the mgmt_pending_cmd structure and its associated parameter data for each SSP command that completes. Add the missing mgmt_pending_free(cmd) calls in both code paths to fix the memory leak. Also fix the same issue in set_advertising_complete(). Fixes: 302a1f674c00 ("Bluetooth: MGMT: Fix possible UAFs") Signed-off-by: Jianpeng Chang Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5be9b8c91949..0e46f9e08b10 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1966,6 +1966,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) } mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); + mgmt_pending_free(cmd); return; } @@ -1984,6 +1985,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) sock_put(match.sk); hci_update_eir_sync(hdev); + mgmt_pending_free(cmd); } static int set_ssp_sync(struct hci_dev *hdev, void *data) @@ -6438,6 +6440,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) hci_dev_clear_flag(hdev, HCI_ADVERTISING); settings_rsp(cmd, &match); + mgmt_pending_free(cmd); new_settings(hdev, match.sk); From 6c3ea155e5ee3e56606233acde8309afda66d483 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 21 Jan 2026 16:39:44 -0500 Subject: [PATCH 37/40] Bluetooth: L2CAP: Fix not tracking outstanding TX ident This attempts to proper track outstanding request by using struct ida and allocating from it in l2cap_get_ident using ida_alloc_range which would reuse ids as they are free, then upon completion release the id using ida_free. This fixes the qualification test case L2CAP/COS/CED/BI-29-C which attempts to check if the host stack is able to work after 256 attempts to connect which requires Ident field to use the full range of possible values in order to pass the test. Link: https://github.com/bluez/bluez/issues/1829 Signed-off-by: Luiz Augusto von Dentz Reviewed-by: Paul Menzel --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/l2cap_core.c | 46 ++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 00e182a22720..ec3af01e4db9 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -655,8 +655,7 @@ struct l2cap_conn { struct sk_buff *rx_skb; __u32 rx_len; - __u8 tx_ident; - struct mutex ident_lock; + struct ida tx_ida; struct sk_buff_head pending_rx; struct work_struct pending_rx_work; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 07b493331fd7..b628b0fa39b2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -924,26 +924,18 @@ int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator) initiator); } -static u8 l2cap_get_ident(struct l2cap_conn *conn) +static int l2cap_get_ident(struct l2cap_conn *conn) { - u8 id; + /* LE link does not support tools like l2ping so use the full range */ + if (conn->hcon->type == LE_LINK) + return ida_alloc_range(&conn->tx_ida, 1, 255, GFP_ATOMIC); /* Get next available identificator. * 1 - 128 are used by kernel. * 129 - 199 are reserved. * 200 - 254 are used by utilities like l2ping, etc. */ - - mutex_lock(&conn->ident_lock); - - if (++conn->tx_ident > 128) - conn->tx_ident = 1; - - id = conn->tx_ident; - - mutex_unlock(&conn->ident_lock); - - return id; + return ida_alloc_range(&conn->tx_ida, 1, 128, GFP_ATOMIC); } static void l2cap_send_acl(struct l2cap_conn *conn, struct sk_buff *skb, @@ -1773,6 +1765,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (work_pending(&conn->pending_rx_work)) cancel_work_sync(&conn->pending_rx_work); + ida_destroy(&conn->tx_ida); + cancel_delayed_work_sync(&conn->id_addr_timer); l2cap_unregister_all_users(conn); @@ -4782,12 +4776,34 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, return err; } +static void l2cap_put_ident(struct l2cap_conn *conn, u8 code, u8 id) +{ + switch (code) { + case L2CAP_COMMAND_REJ: + case L2CAP_CONN_RSP: + case L2CAP_CONF_RSP: + case L2CAP_DISCONN_RSP: + case L2CAP_ECHO_RSP: + case L2CAP_INFO_RSP: + case L2CAP_CONN_PARAM_UPDATE_RSP: + case L2CAP_ECRED_CONN_RSP: + case L2CAP_ECRED_RECONF_RSP: + /* First do a lookup since the remote may send bogus ids that + * would make ida_free to generate warnings. + */ + if (ida_find_first_range(&conn->tx_ida, id, id) >= 0) + ida_free(&conn->tx_ida, id); + } +} + static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) { int err = 0; + l2cap_put_ident(conn, cmd->code, cmd->ident); + switch (cmd->code) { case L2CAP_COMMAND_REJ: l2cap_command_rej(conn, cmd, cmd_len, data); @@ -5419,6 +5435,8 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, { int err = 0; + l2cap_put_ident(conn, cmd->code, cmd->ident); + switch (cmd->code) { case L2CAP_COMMAND_REJ: l2cap_le_command_rej(conn, cmd, cmd_len, data); @@ -6907,13 +6925,13 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP))) conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR; - mutex_init(&conn->ident_lock); mutex_init(&conn->lock); INIT_LIST_HEAD(&conn->chan_l); INIT_LIST_HEAD(&conn->users); INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + ida_init(&conn->tx_ida); skb_queue_head_init(&conn->pending_rx); INIT_WORK(&conn->pending_rx_work, process_pending_rx); From 6c0568b7741a346088fd6dfced2d871f7d481d06 Mon Sep 17 00:00:00 2001 From: Zenm Chen Date: Thu, 29 Jan 2026 10:28:19 +0800 Subject: [PATCH 38/40] Bluetooth: btusb: Add USB ID 7392:e611 for Edimax EW-7611UXB Add USB ID 7392:e611 for Edimax EW-7611UXB which is RTL8851BU-based Wi-Fi + Bluetooth adapter. The information in /sys/kernel/debug/usb/devices about the Bluetooth device is listed as the below: T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 6 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=7392 ProdID=e611 Rev= 0.00 S: Manufacturer=Realtek S: Product=802.11ax WLAN Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 8 Cls=ff(vend.) Sub=ff Prot=ff Driver=rtw89_8851bu_git E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=09(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0a(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0b(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=0c(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Cc: stable@vger.kernel.org # 6.6.x Signed-off-by: Zenm Chen Reviewed-by: Paul Menzel Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8c34a17edae5..fcec8e589e81 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -529,6 +529,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x2001, 0x332a), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x7392, 0xe611), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | From 22d893eec0d52fa97d25d3de248285648f26ef68 Mon Sep 17 00:00:00 2001 From: Mengshi Wu Date: Tue, 27 Jan 2026 10:54:22 +0800 Subject: [PATCH 39/40] Bluetooth: hci_qca: Refactor HFP hardware offload capability handling Replace SoC-specific check with capability-based approach for HFP hardware offload configuration. Add QCA_CAP_HFP_HW_OFFLOAD capability flag and support_hfp_hw_offload field to qca_serdev structure. Add QCA_CAP_HFP_HW_OFFLOAD capability flag to QCA2066 device data structures. Reviewed-by: Dmitry Baryshkov Signed-off-by: Mengshi Wu Acked-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index a3c217571c3c..7cd4c1078fa9 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -87,6 +87,7 @@ enum qca_flags { enum qca_capabilities { QCA_CAP_WIDEBAND_SPEECH = BIT(0), QCA_CAP_VALID_LE_STATES = BIT(1), + QCA_CAP_HFP_HW_OFFLOAD = BIT(2), }; /* HCI_IBS transmit side sleep protocol states */ @@ -229,6 +230,7 @@ struct qca_serdev { u32 init_speed; u32 oper_speed; bool bdaddr_property_broken; + bool support_hfp_hw_offload; const char *firmware_name[2]; }; @@ -1912,7 +1914,7 @@ static int qca_setup(struct hci_uart *hu) const char *rampatch_name = qca_get_rampatch_name(hu); int ret; struct qca_btsoc_version ver; - struct qca_serdev *qcadev; + struct qca_serdev *qcadev = serdev_device_get_drvdata(hu->serdev); const char *soc_name; ret = qca_check_speeds(hu); @@ -1976,7 +1978,6 @@ static int qca_setup(struct hci_uart *hu) case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - qcadev = serdev_device_get_drvdata(hu->serdev); if (qcadev->bdaddr_property_broken) hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN); @@ -2066,7 +2067,7 @@ static int qca_setup(struct hci_uart *hu) else hu->hdev->set_bdaddr = qca_set_bdaddr; - if (soc_type == QCA_QCA2066) + if (qcadev->support_hfp_hw_offload) qca_configure_hfp_offload(hdev); qca->fw_version = le16_to_cpu(ver.patch_ver); @@ -2150,7 +2151,8 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = { static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = { .soc_type = QCA_QCA2066, .num_vregs = 0, - .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES | + QCA_CAP_HFP_HW_OFFLOAD, }; static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = { @@ -2535,6 +2537,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) if (!(data->capabilities & QCA_CAP_VALID_LE_STATES)) hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_STATES); + + if (data->capabilities & QCA_CAP_HFP_HW_OFFLOAD) + qcadev->support_hfp_hw_offload = true; } return 0; From eba86d86eec8428bd743523ec76932838e0b30f7 Mon Sep 17 00:00:00 2001 From: Mengshi Wu Date: Tue, 27 Jan 2026 10:54:23 +0800 Subject: [PATCH 40/40] Bluetooth: hci_qca: Enable HFP hardware offload for WCN6855 and WCN7850 Add QCA_CAP_HFP_HW_OFFLOAD capability flag to WCN6855 and WCN7850 device data structures to enable Hands-Free Profile (HFP) hardware offload support on these Qualcomm Bluetooth chipsets. Signed-off-by: Mengshi Wu Acked-by: Bartosz Golaszewski Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/hci_qca.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 7cd4c1078fa9..51309f5b5714 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2188,7 +2188,8 @@ static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = { { "vddrfa1p2", 257000 }, }, .num_vregs = 6, - .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES | + QCA_CAP_HFP_HW_OFFLOAD, }; static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = { @@ -2202,7 +2203,8 @@ static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = { { "vddrfa1p9", 302000 }, }, .num_vregs = 6, - .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES | + QCA_CAP_HFP_HW_OFFLOAD, }; static void qca_power_shutdown(struct hci_uart *hu)