Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: btnxpuart: Add support to set BD address

This adds support for setting BD address during hci registration. NXP
FW does not allow vendor commands unless it receives a reset command
after FW download and initialization done.

As a workaround, the .set_bdaddr callback function will first send the
HCI reset command, followed by the actual vendor command to set BD
address.

The driver checks for the local-bd-address property in device tree, and
if preset, it sets the HCI_QUIRK_USE_BDADDR_PROPERTY quirk.

With this quirk set, the driver's set_bdaddr callback function is called
after FW download is complete and before HCI initialization, which sends
the hci reset and 3f 22 commands. During initialization, kernel reads
the newly set BD address from the controller.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Signed-off-by: Johan Korsnes <johan.korsnes@remarkable.no>
Signed-off-by: Kristian Krohn <kristian.krohn@remarkable.no>
Tested-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Neeraj Sanjay Kale and committed by
Luiz Augusto von Dentz
9148ac0a b13b6d66

+54 -5
+54 -5
drivers/bluetooth/btnxpuart.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 3 * NXP Bluetooth driver 4 - * Copyright 2023 NXP 4 + * Copyright 2023-2025 NXP 5 5 */ 6 6 7 7 #include <linux/module.h> ··· 99 99 #define PS_STATE_AWAKE 0 100 100 #define PS_STATE_SLEEP 1 101 101 102 - /* Bluetooth vendor command : Sleep mode */ 102 + /* NXP Vendor Commands. Refer user manual UM11628 on nxp.com */ 103 + /* Set custom BD Address */ 104 + #define HCI_NXP_SET_BD_ADDR 0xfc22 105 + /* Set Auto-Sleep mode */ 103 106 #define HCI_NXP_AUTO_SLEEP_MODE 0xfc23 104 - /* Bluetooth vendor command : Wakeup method */ 107 + /* Set Wakeup method */ 105 108 #define HCI_NXP_WAKEUP_METHOD 0xfc53 106 - /* Bluetooth vendor command : Set operational baudrate */ 109 + /* Set operational baudrate */ 107 110 #define HCI_NXP_SET_OPER_SPEED 0xfc09 108 - /* Bluetooth vendor command: Independent Reset */ 111 + /* Independent Reset (Soft Reset) */ 109 112 #define HCI_NXP_IND_RESET 0xfcfc 110 113 /* Bluetooth vendor command: Trigger FW dump */ 111 114 #define HCI_NXP_TRIGGER_DUMP 0xfe91 ··· 324 321 __le16 reserved; 325 322 __le16 buf_type; 326 323 __le16 buf_len; 324 + }; 325 + 326 + union nxp_set_bd_addr_payload { 327 + struct { 328 + u8 param_id; 329 + u8 param_len; 330 + u8 param[6]; 331 + } __packed data; 332 + u8 buf[8]; 327 333 }; 328 334 329 335 static u8 crc8_table[CRC8_TABLE_SIZE]; ··· 1306 1294 return hci_recv_frame(hdev, skb); 1307 1295 } 1308 1296 1297 + static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 1298 + { 1299 + union nxp_set_bd_addr_payload pcmd; 1300 + int err; 1301 + 1302 + pcmd.data.param_id = 0xfe; 1303 + pcmd.data.param_len = 6; 1304 + memcpy(pcmd.data.param, bdaddr, 6); 1305 + 1306 + /* BD address can be assigned only after first reset command. */ 1307 + err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL, 1308 + HCI_INIT_TIMEOUT); 1309 + if (err) { 1310 + bt_dev_err(hdev, 1311 + "Reset before setting local-bd-addr failed (%d)", 1312 + err); 1313 + return err; 1314 + } 1315 + 1316 + err = __hci_cmd_sync_status(hdev, HCI_NXP_SET_BD_ADDR, sizeof(pcmd), 1317 + pcmd.buf, HCI_CMD_TIMEOUT); 1318 + if (err) { 1319 + bt_dev_err(hdev, "Changing device address failed (%d)", err); 1320 + return err; 1321 + } 1322 + 1323 + return 0; 1324 + } 1325 + 1309 1326 /* NXP protocol */ 1310 1327 static int nxp_setup(struct hci_dev *hdev) 1311 1328 { ··· 1672 1631 { 1673 1632 struct hci_dev *hdev; 1674 1633 struct btnxpuart_dev *nxpdev; 1634 + bdaddr_t ba = {0}; 1675 1635 1676 1636 nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); 1677 1637 if (!nxpdev) ··· 1723 1681 hdev->shutdown = nxp_shutdown; 1724 1682 hdev->wakeup = nxp_wakeup; 1725 1683 hdev->reset = nxp_reset; 1684 + hdev->set_bdaddr = nxp_set_bdaddr; 1726 1685 SET_HCIDEV_DEV(hdev, &serdev->dev); 1686 + 1687 + device_property_read_u8_array(&nxpdev->serdev->dev, 1688 + "local-bd-address", 1689 + (u8 *)&ba, sizeof(ba)); 1690 + if (bacmp(&ba, BDADDR_ANY)) 1691 + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); 1727 1692 1728 1693 if (hci_register_dev(hdev) < 0) { 1729 1694 dev_err(&serdev->dev, "Can't register HCI device\n");