Skip to content

Commit 0e58d0c

Browse files
dlechholtmann
authored andcommitted
Bluetooth: hci_ll: Add optional nvmem BD address source
This adds an optional nvmem consumer to get a BD address from an external source. The BD address is then set in the Bluetooth chip after the firmware has been loaded. This has been tested working with a TI CC2560A chip (in a LEGO MINDSTORMS EV3). Signed-off-by: David Lechner <david@lechnology.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
1 parent 00644f9 commit 0e58d0c

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

drivers/bluetooth/hci_ll.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include <net/bluetooth/bluetooth.h>
5454
#include <net/bluetooth/hci_core.h>
5555
#include <linux/gpio/consumer.h>
56+
#include <linux/nvmem-consumer.h>
5657

5758
#include "hci_uart.h"
5859

@@ -90,6 +91,7 @@ struct ll_device {
9091
struct serdev_device *serdev;
9192
struct gpio_desc *enable_gpio;
9293
struct clk *ext_clk;
94+
bdaddr_t bdaddr;
9395
};
9496

9597
struct ll_struct {
@@ -719,6 +721,18 @@ static int ll_setup(struct hci_uart *hu)
719721
if (err)
720722
return err;
721723

724+
/* Set BD address if one was specified at probe */
725+
if (!bacmp(&lldev->bdaddr, BDADDR_NONE)) {
726+
/* This means that there was an error getting the BD address
727+
* during probe, so mark the device as having a bad address.
728+
*/
729+
set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
730+
} else if (bacmp(&lldev->bdaddr, BDADDR_ANY)) {
731+
err = ll_set_bdaddr(hu->hdev, &lldev->bdaddr);
732+
if (err)
733+
set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
734+
}
735+
722736
/* Operational speed if any */
723737
if (hu->oper_speed)
724738
speed = hu->oper_speed;
@@ -749,6 +763,7 @@ static int hci_ti_probe(struct serdev_device *serdev)
749763
{
750764
struct hci_uart *hu;
751765
struct ll_device *lldev;
766+
struct nvmem_cell *bdaddr_cell;
752767
u32 max_speed = 3000000;
753768

754769
lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL);
@@ -770,6 +785,52 @@ static int hci_ti_probe(struct serdev_device *serdev)
770785
of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed);
771786
hci_uart_set_speeds(hu, 115200, max_speed);
772787

788+
/* optional BD address from nvram */
789+
bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address");
790+
if (IS_ERR(bdaddr_cell)) {
791+
int err = PTR_ERR(bdaddr_cell);
792+
793+
if (err == -EPROBE_DEFER)
794+
return err;
795+
796+
/* ENOENT means there is no matching nvmem cell and ENOSYS
797+
* means that nvmem is not enabled in the kernel configuration.
798+
*/
799+
if (err != -ENOENT && err != -ENOSYS) {
800+
/* If there was some other error, give userspace a
801+
* chance to fix the problem instead of failing to load
802+
* the driver. Using BDADDR_NONE as a flag that is
803+
* tested later in the setup function.
804+
*/
805+
dev_warn(&serdev->dev,
806+
"Failed to get \"bd-address\" nvmem cell (%d)\n",
807+
err);
808+
bacpy(&lldev->bdaddr, BDADDR_NONE);
809+
}
810+
} else {
811+
bdaddr_t *bdaddr;
812+
size_t len;
813+
814+
bdaddr = nvmem_cell_read(bdaddr_cell, &len);
815+
nvmem_cell_put(bdaddr_cell);
816+
if (IS_ERR(bdaddr)) {
817+
dev_err(&serdev->dev, "Failed to read nvmem bd-address\n");
818+
return PTR_ERR(bdaddr);
819+
}
820+
if (len != sizeof(bdaddr_t)) {
821+
dev_err(&serdev->dev, "Invalid nvmem bd-address length\n");
822+
kfree(bdaddr);
823+
return -EINVAL;
824+
}
825+
826+
/* As per the device tree bindings, the value from nvmem is
827+
* expected to be MSB first, but in the kernel it is expected
828+
* that bdaddr_t is LSB first.
829+
*/
830+
baswap(&lldev->bdaddr, bdaddr);
831+
kfree(bdaddr);
832+
}
833+
773834
return hci_uart_register_device(hu, &llp);
774835
}
775836

0 commit comments

Comments
 (0)