[PATCH RFC 3/5] Bluetooth: hci_qca: Support BD address from an nvmem cell
Abel Vesa
abel.vesa at oss.qualcomm.com
Wed Oct 14 06:02:41 PDT 2026
Read an optional Bluetooth device address from an nvmem cell named
"bd-address" (as already supported by hci_ll), and program it into the
controller during setup. This lets QCA controllers source their BD_ADDR
from firmware-provisioned storage such as a UEFI variable exposed via
nvmem. An all-zero value is ignored, so unprovisioned storage leaves
the controller default address untouched.
Assisted-by: LLM
Signed-off-by: Abel Vesa <abel.vesa at oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 48 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 7089e9b639b2..b704f4c3e1a4 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -25,6 +25,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/nvmem-consumer.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/pwrseq/consumer.h>
@@ -230,6 +231,8 @@ struct qca_serdev {
bool bdaddr_property_broken;
bool support_hfp_hw_offload;
const char *firmware_name[2];
+ bdaddr_t bdaddr;
+ bool bdaddr_valid;
};
static int qca_regulator_enable(struct qca_serdev *qcadev);
@@ -2079,6 +2082,16 @@ static int qca_setup(struct hci_uart *hu)
else
hu->hdev->set_bdaddr = qca_set_bdaddr;
+ /* Program a BD address sourced from an nvmem cell, if provided. */
+ if (qcadev && qcadev->bdaddr_valid) {
+ int berr = hu->hdev->set_bdaddr(hdev, &qcadev->bdaddr);
+
+ if (berr)
+ bt_dev_warn(hdev, "Failed to set nvmem bd-address: %d", berr);
+ else
+ bt_dev_info(hdev, "Set bd-address %pMR from nvmem", &qcadev->bdaddr);
+ }
+
if (qcadev && qcadev->support_hfp_hw_offload)
qca_configure_hfp_offload(hdev);
@@ -2420,6 +2433,41 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bdaddr_property_broken = device_property_read_bool(&serdev->dev,
"qcom,local-bd-address-broken");
+ /* Optional BD address from an nvmem cell (e.g. a UEFI variable). */
+ {
+ struct nvmem_cell *cell;
+
+ cell = nvmem_cell_get(&serdev->dev, "bd-address");
+ if (IS_ERR(cell)) {
+ err = PTR_ERR(cell);
+ if (err == -EPROBE_DEFER)
+ return err;
+ /* -ENOENT/-ENOSYS: no cell configured, ignore. */
+ } else {
+ size_t clen;
+ void *cdata = nvmem_cell_read(cell, &clen);
+
+ nvmem_cell_put(cell);
+ if (!IS_ERR(cdata)) {
+ /*
+ * Ignore an all-zero address: the backing
+ * storage has not been provisioned.
+ */
+ if (clen == sizeof(bdaddr_t) &&
+ bacmp(cdata, BDADDR_ANY)) {
+ /*
+ * Per the device tree bindings the nvmem
+ * value is MSB first, while bdaddr_t is
+ * LSB first.
+ */
+ baswap(&qcadev->bdaddr, cdata);
+ qcadev->bdaddr_valid = true;
+ }
+ kfree(cdata);
+ }
+ }
+ }
+
if (data)
qcadev->btsoc_type = data->soc_type;
else
--
2.54.0
More information about the ath12k
mailing list