From c098e4a97f3e3c1a821bdad9a4a2e0a81c75dc48 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 19 May 2026 14:26:02 +0530 Subject: [PATCH 1/3] FROMLIST: Bluetooth: hci_qca: 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, the existing pwrseq APIs can be used to control the power supplies of the M.2 card. Tested-by: Wei Deng Reviewed-by: Bartosz Golaszewski Reviewed-by: Dmitry Baryshkov Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com --- drivers/bluetooth/hci_qca.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index ed280399bf474..a75264ed1bb65 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2442,6 +2443,18 @@ static int qca_serdev_probe(struct serdev_device *serdev) case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: + /* + * OF graph link is only present for BT devices attached through + * the M.2 Key E connector. + */ + if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) { + qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->ctrl->dev, + "uart"); + if (IS_ERR(qcadev->bt_power->pwrseq)) + return PTR_ERR(qcadev->bt_power->pwrseq); + break; + } + if (!device_property_present(&serdev->dev, "enable-gpios")) { /* * Backward compatibility with old DT sources. If the From a99ce0e9925755f0f04d72180e53519e395f0648 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 19 May 2026 14:26:03 +0530 Subject: [PATCH 2/3] FROMLIST: Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available' 'power_ctrl_enabled' flag is used to indicate the availability of the BT_EN GPIO in devicetree. But the naming causes confusion with the new pwrctrl framework. So rename it to 'bt_en_available' to make it clear and explicit. Tested-by: Wei Deng Reviewed-by: Dmitry Baryshkov Reviewed-by: Bartosz Golaszewski Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com --- drivers/bluetooth/hci_qca.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index a75264ed1bb65..ced2b0984a166 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2390,7 +2390,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) struct hci_dev *hdev; const struct qca_device_data *data; int err; - bool power_ctrl_enabled = true; + bool bt_en_available = true; qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL); if (!qcadev) @@ -2498,7 +2498,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) (data->soc_type == QCA_WCN6750 || data->soc_type == QCA_WCN6855 || data->soc_type == QCA_WCN7850)) - power_ctrl_enabled = false; + bt_en_available = false; qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", GPIOD_IN); @@ -2536,7 +2536,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) } if (!qcadev->bt_en) - power_ctrl_enabled = false; + bt_en_available = false; qcadev->susclk = devm_clk_get_optional_enabled_with_rate( &serdev->dev, NULL, SUSCLK_RATE_32KHZ); @@ -2554,7 +2554,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) hdev = qcadev->serdev_hu.hdev; - if (power_ctrl_enabled) { + if (bt_en_available) { hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP); hdev->shutdown = qca_hci_shutdown; } From 94266f4677696877139e3faa7f2c8813b10707b5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 19 May 2026 14:26:04 +0530 Subject: [PATCH 3/3] FROMLIST: Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector Check if the M.2 connector supports the W_DISABLE2# property or not by querying the pwrseq provider's DT node. If not available, then set 'bt_en_available' flag to 'false'. This flag is used to set the HCI_QUIRK_NON_PERSISTENT_SETUP HCI quirk, which informs the HCI layer whether the shutdown() callback for the device can be triggered or not. Tested-by: Wei Deng Reviewed-by: Bartosz Golaszewski Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20260519-pwrseq-m2-bt-v3-0-b39dc2ae3966@oss.qualcomm.com --- drivers/bluetooth/hci_qca.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index ced2b0984a166..00e60a0dfc0b4 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2448,10 +2448,17 @@ static int qca_serdev_probe(struct serdev_device *serdev) * the M.2 Key E connector. */ if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) { + struct device *dev; + qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->ctrl->dev, "uart"); if (IS_ERR(qcadev->bt_power->pwrseq)) return PTR_ERR(qcadev->bt_power->pwrseq); + + dev = pwrseq_to_device(qcadev->bt_power->pwrseq); + if (!device_property_present(dev, "w-disable2-gpios")) + bt_en_available = false; + break; }