summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSherry Sun <sherry.sun@nxp.com>2026-07-21 11:04:58 +0800
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-08-07 15:40:27 -0400
commite48e332d84d8df9bc615530beaa3ece9240da2d6 (patch)
tree98f696e38df5bebab63d5bc14a58018d6407de3a
parent414b365ecea6c30357adee6b8a7c5edc03a03575 (diff)
Bluetooth: btnxpuart: Add M.2 Bluetooth device support using pwrseq
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, pwrseq_power_on() is called to power up the M.2 Bluetooth card. The power sequencer descriptor is obtained via pwrseq_get() with the UART controller device (serdev->ctrl->dev), since the OF graph link is defined on the UART controller node. Also add the explicit pwrseq_put() call in all exit paths, pwrseq_put() already calls pwrseq_power_off() internally, so no separate pwrseq_power_off() call is needed. Signed-off-by: Sherry Sun <sherry.sun@nxp.com> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-rw-r--r--drivers/bluetooth/btnxpuart.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 993c48b5f593..81cdd8da5636 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;
};
@@ -1860,11 +1863,26 @@ 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 = pwrseq_get(&serdev->ctrl->dev, "uart");
+ if (IS_ERR(pwrseq))
+ return dev_err_probe(&serdev->dev, PTR_ERR(pwrseq),
+ "failed to get pwrseq\n");
+
+ nxpdev->pwrseq = pwrseq;
+ err = pwrseq_power_on(pwrseq);
+ if (err)
+ goto err_pwrseq_put;
+ }
+
/* 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_put;
}
reset_control_deassert(nxpdev->pdn);
@@ -1895,13 +1913,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
if (bacmp(&ba, BDADDR_ANY))
hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
- if (hci_register_dev(hdev) < 0) {
+ err = hci_register_dev(hdev);
+ if (err < 0) {
dev_err(&serdev->dev, "Can't register HCI device\n");
goto probe_fail;
}
- if (ps_setup(hdev))
+ if (ps_setup(hdev)) {
+ err = -ENODEV;
goto probe_fail_unregister;
+ }
hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
nxp_coredump_notify);
@@ -1913,7 +1934,10 @@ probe_fail_unregister:
probe_fail:
reset_control_assert(nxpdev->pdn);
hci_free_dev(hdev);
- return -ENODEV;
+err_pwrseq_put:
+ if (nxpdev->pwrseq)
+ pwrseq_put(nxpdev->pwrseq);
+ return err;
}
static void nxp_serdev_remove(struct serdev_device *serdev)
@@ -1940,6 +1964,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_put(nxpdev->pwrseq);
hci_free_dev(hdev);
}