Skip to content

Commit 9148ac0

Browse files
NeerajSanjayKaleVudentz
authored andcommitted
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>
1 parent b13b6d6 commit 9148ac0

1 file changed

Lines changed: 54 additions & 5 deletions

File tree

drivers/bluetooth/btnxpuart.c

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22
/*
33
* NXP Bluetooth driver
4-
* Copyright 2023 NXP
4+
* Copyright 2023-2025 NXP
55
*/
66

77
#include <linux/module.h>
@@ -99,13 +99,16 @@
9999
#define PS_STATE_AWAKE 0
100100
#define PS_STATE_SLEEP 1
101101

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 */
103106
#define HCI_NXP_AUTO_SLEEP_MODE 0xfc23
104-
/* Bluetooth vendor command : Wakeup method */
107+
/* Set Wakeup method */
105108
#define HCI_NXP_WAKEUP_METHOD 0xfc53
106-
/* Bluetooth vendor command : Set operational baudrate */
109+
/* Set operational baudrate */
107110
#define HCI_NXP_SET_OPER_SPEED 0xfc09
108-
/* Bluetooth vendor command: Independent Reset */
111+
/* Independent Reset (Soft Reset) */
109112
#define HCI_NXP_IND_RESET 0xfcfc
110113
/* Bluetooth vendor command: Trigger FW dump */
111114
#define HCI_NXP_TRIGGER_DUMP 0xfe91
@@ -323,6 +326,15 @@ struct nxp_fw_dump_hdr {
323326
__le16 buf_len;
324327
};
325328

329+
union nxp_set_bd_addr_payload {
330+
struct {
331+
u8 param_id;
332+
u8 param_len;
333+
u8 param[6];
334+
} __packed data;
335+
u8 buf[8];
336+
};
337+
326338
static u8 crc8_table[CRC8_TABLE_SIZE];
327339

328340
/* Default configurations */
@@ -1294,6 +1306,35 @@ static int nxp_recv_acl_pkt(struct hci_dev *hdev, struct sk_buff *skb)
12941306
return hci_recv_frame(hdev, skb);
12951307
}
12961308

1309+
static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
1310+
{
1311+
union nxp_set_bd_addr_payload pcmd;
1312+
int err;
1313+
1314+
pcmd.data.param_id = 0xfe;
1315+
pcmd.data.param_len = 6;
1316+
memcpy(pcmd.data.param, bdaddr, 6);
1317+
1318+
/* BD address can be assigned only after first reset command. */
1319+
err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
1320+
HCI_INIT_TIMEOUT);
1321+
if (err) {
1322+
bt_dev_err(hdev,
1323+
"Reset before setting local-bd-addr failed (%d)",
1324+
err);
1325+
return err;
1326+
}
1327+
1328+
err = __hci_cmd_sync_status(hdev, HCI_NXP_SET_BD_ADDR, sizeof(pcmd),
1329+
pcmd.buf, HCI_CMD_TIMEOUT);
1330+
if (err) {
1331+
bt_dev_err(hdev, "Changing device address failed (%d)", err);
1332+
return err;
1333+
}
1334+
1335+
return 0;
1336+
}
1337+
12971338
/* NXP protocol */
12981339
static int nxp_setup(struct hci_dev *hdev)
12991340
{
@@ -1631,6 +1672,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
16311672
{
16321673
struct hci_dev *hdev;
16331674
struct btnxpuart_dev *nxpdev;
1675+
bdaddr_t ba = {0};
16341676

16351677
nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL);
16361678
if (!nxpdev)
@@ -1681,8 +1723,15 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
16811723
hdev->shutdown = nxp_shutdown;
16821724
hdev->wakeup = nxp_wakeup;
16831725
hdev->reset = nxp_reset;
1726+
hdev->set_bdaddr = nxp_set_bdaddr;
16841727
SET_HCIDEV_DEV(hdev, &serdev->dev);
16851728

1729+
device_property_read_u8_array(&nxpdev->serdev->dev,
1730+
"local-bd-address",
1731+
(u8 *)&ba, sizeof(ba));
1732+
if (bacmp(&ba, BDADDR_ANY))
1733+
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
1734+
16861735
if (hci_register_dev(hdev) < 0) {
16871736
dev_err(&serdev->dev, "Can't register HCI device\n");
16881737
goto probe_fail;

0 commit comments

Comments
 (0)