[PATCH 3/8] Bluetooth: btnxpuart: Add M.2 Bluetooth device support using pwrseq

From: Sherry Sun (OSS)

Date: Thu Jun 18 2026 - 06:10:15 EST


From: Sherry Sun <sherry.sun@xxxxxxx>

Power supply to the M.2 Bluetooth device attached to the host using M.2
connector is controlled using the 'uart' pwrseq device. So add support for
getting the pwrseq device if the OF graph link is present. Once obtained,
the existing pwrseq APIs can be used to control the power supplies of the
M.2 card.

Signed-off-by: Sherry Sun <sherry.sun@xxxxxxx>
---
drivers/bluetooth/btnxpuart.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index e7036a48ce48..1aa8972f0dab 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -9,6 +9,8 @@

#include <linux/serdev.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/skbuff.h>
#include <linux/unaligned.h>
#include <linux/firmware.h>
@@ -211,6 +213,7 @@ struct btnxpuart_dev {

struct ps_data psdata;
struct btnxpuart_data *nxp_data;
+ struct pwrseq_desc *pwrseq;
struct reset_control *pdn;
struct hci_uart hu;
};
@@ -1866,11 +1869,27 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
return err;
}

+ if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
+ struct pwrseq_desc *pwrseq;
+
+ pwrseq = devm_pwrseq_get(&serdev->ctrl->dev, "uart");
+ if (IS_ERR(pwrseq))
+ return PTR_ERR(pwrseq);
+
+ nxpdev->pwrseq = pwrseq;
+ err = pwrseq_power_on(pwrseq);
+ if (err) {
+ dev_err(&serdev->dev, "Failed to power on pwrseq\n");
+ return err;
+ }
+ }
+
/* Initialize and register HCI device */
hdev = hci_alloc_dev();
if (!hdev) {
dev_err(&serdev->dev, "Can't allocate HCI device\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_pwrseq_power_off;
}

reset_control_deassert(nxpdev->pdn);
@@ -1903,11 +1922,14 @@ static int nxp_serdev_probe(struct serdev_device *serdev)

if (hci_register_dev(hdev) < 0) {
dev_err(&serdev->dev, "Can't register HCI device\n");
+ err = -ENODEV;
goto probe_fail;
}

- if (ps_setup(hdev))
+ if (ps_setup(hdev)) {
+ err = -ENODEV;
goto probe_fail;
+ }

hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
nxp_coredump_notify);
@@ -1917,7 +1939,10 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
probe_fail:
reset_control_assert(nxpdev->pdn);
hci_free_dev(hdev);
- return -ENODEV;
+err_pwrseq_power_off:
+ if (nxpdev->pwrseq)
+ pwrseq_power_off(nxpdev->pwrseq);
+ return err;
}

static void nxp_serdev_remove(struct serdev_device *serdev)
@@ -1944,6 +1969,8 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
ps_cleanup(nxpdev);
hci_unregister_dev(hdev);
reset_control_assert(nxpdev->pdn);
+ if (nxpdev->pwrseq)
+ pwrseq_power_off(nxpdev->pwrseq);
hci_free_dev(hdev);
}

--
2.50.1