Re: [PATCH v6 2/2] Bluetooth: btnxpuart: Add support to set BD address

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Neeraj,

On Fri, Feb 28, 2025 at 10:27 AM Neeraj Sanjay Kale
<neeraj.sanjaykale@xxxxxxx> wrote:
>
> 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@xxxxxxxxxx>
> Signed-off-by: Johan Korsnes <johan.korsnes@xxxxxxxxxxxxx>
> Signed-off-by: Kristian Krohn <kristian.krohn@xxxxxxxxxxxxx>
> Tested-by: Neeraj Sanjay Kale <neeraj.sanjaykale@xxxxxxx>
> Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@xxxxxxx>
> ---
> v4: hci0 interface shows RAW mode if 'local-bd-address' not defined and
>     HCI_QUIRK_USE_BDADDR_PROPERTY is set. Add Quirk only if device tree
>     property 'local-bd-address' found. (Neeraj)
> v5: Initialize local variable ba, update Copywrite year. (Kristian)
> v6: Elaborate commit message, add User Manual reference. (Paul Menzel)
> ---
>  drivers/bluetooth/btnxpuart.c | 63 ++++++++++++++++++++++++++++++++---
>  1 file changed, 58 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
> index 1230045d78a5..2eb14b9beb70 100644
> --- a/drivers/bluetooth/btnxpuart.c
> +++ b/drivers/bluetooth/btnxpuart.c
> @@ -1,7 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0-or-later
>  /*
>   *  NXP Bluetooth driver
> - *  Copyright 2023 NXP
> + *  Copyright 2023-2025 NXP
>   */
>
>  #include <linux/module.h>
> @@ -98,13 +98,16 @@
>  #define PS_STATE_AWAKE          0
>  #define PS_STATE_SLEEP          1
>
> -/* Bluetooth vendor command : Sleep mode */
> +/* NXP Vendor Commands. Refer user manual UM11628 on nxp.com */
> +/* Set custom BD Address */
> +#define HCI_NXP_SET_BD_ADDR    0xfc22
> +/* Set Auto-Sleep mode */
>  #define HCI_NXP_AUTO_SLEEP_MODE        0xfc23
> -/* Bluetooth vendor command : Wakeup method */
> +/* Set Wakeup method */
>  #define HCI_NXP_WAKEUP_METHOD  0xfc53
> -/* Bluetooth vendor command : Set operational baudrate */
> +/* Set operational baudrate */
>  #define HCI_NXP_SET_OPER_SPEED 0xfc09
> -/* Bluetooth vendor command: Independent Reset */
> +/* Independent Reset (Soft Reset) */
>  #define HCI_NXP_IND_RESET      0xfcfc
>
>  /* Bluetooth Power State : Vendor cmd params */
> @@ -310,6 +313,15 @@ union nxp_v3_rx_timeout_nak_u {
>         u8 buf[6];
>  };
>
> +union nxp_set_bd_addr_payload {
> +       struct {
> +               u8 param_id;
> +               u8 param_len;
> +               u8 param[6];
> +       } __packed data;
> +       u8 buf[8];
> +};
> +
>  static u8 crc8_table[CRC8_TABLE_SIZE];
>
>  /* Default configurations */
> @@ -1197,6 +1209,38 @@ static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
>         return hci_recv_frame(hdev, skb);
>  }
>
> +static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
> +{
> +       union nxp_set_bd_addr_payload pcmd;
> +       struct sk_buff *skb;
> +       int err;
> +
> +       pcmd.data.param_id = 0xfe;
> +       pcmd.data.param_len = 6;
> +       memcpy(pcmd.data.param, bdaddr, 6);
> +
> +       /* BD address can be assigned only after first reset command. */
> +       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
> +       if (IS_ERR(skb)) {
> +               err = PTR_ERR(skb);
> +               bt_dev_err(hdev, "Reset before setting local-bd-addr failed (%ld)",
> +                          PTR_ERR(skb));
> +               return err;
> +       }
> +       kfree_skb(skb);

If you don't care about the response, just the status, it is probably
better to use __hci_cmd_sync_status, also since the hdev->set_bdaddr
comes after hdev->setup doesn't the later do perform a reset anyway?
If you end up with 2 resets in a row it problems means you don't need
to reset again.

> +
> +       skb = __hci_cmd_sync(hdev, HCI_NXP_SET_BD_ADDR, sizeof(pcmd),
> +                            pcmd.buf, HCI_CMD_TIMEOUT);

Ditto.

> +       if (IS_ERR(skb)) {
> +               err = PTR_ERR(skb);
> +               bt_dev_err(hdev, "Changing device address failed (%d)", err);
> +               return err;
> +       }
> +       kfree_skb(skb);
> +
> +       return 0;
> +}
> +
>  /* NXP protocol */
>  static int nxp_setup(struct hci_dev *hdev)
>  {
> @@ -1500,6 +1544,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
>  {
>         struct hci_dev *hdev;
>         struct btnxpuart_dev *nxpdev;
> +       bdaddr_t ba = {0};
>
>         nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL);
>         if (!nxpdev)
> @@ -1547,8 +1592,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
>         hdev->send  = nxp_enqueue;
>         hdev->hw_error = nxp_hw_err;
>         hdev->shutdown = nxp_shutdown;
> +       hdev->set_bdaddr = nxp_set_bdaddr;
> +
>         SET_HCIDEV_DEV(hdev, &serdev->dev);
>
> +       device_property_read_u8_array(&nxpdev->serdev->dev,
> +                                     "local-bd-address",
> +                                     (u8 *)&ba, sizeof(ba));
> +       if (bacmp(&ba, BDADDR_ANY))
> +               set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
> +
>         if (hci_register_dev(hdev) < 0) {
>                 dev_err(&serdev->dev, "Can't register HCI device\n");
>                 goto probe_fail;
> --
> 2.25.1
>


-- 
Luiz Augusto von Dentz





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux