* [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver
@ 2026-04-22 11:24 Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable Manivannan Sadhasivam via B4 Relay
` (11 more replies)
0 siblings, 12 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
Bartosz Golaszewski, stable+noautosel
Hi,
This series has several key improvements and fixes to the M.2 power sequencing
driver and also the BT HCI_QCA driver. Notably, this series allows the M.2 power
sequencing driver to work with more M.2 cards, not just WCN7850. It also allows
the BT HCI_QCA driver to detect whether it can control BT_EN (or W_DISABLE2#)
signal on the connector and set the HCI_QUIRK_NON_PERSISTENT_SETUP quirk.
Testing
=======
This series was tested on Lenovo Thinkpad T14s together with the below DTS
patches:
https://github.com/Mani-Sadhasivam/linux/commit/29534d15307551b2355eb254601dec511169f0aa
https://github.com/Mani-Sadhasivam/linux/commit/f4eaacfe647674be200847092b43cdef2194fc55
Merge Strategy
==============
Since the BT HCI_QCA changes depend on the pwrseq changes, it would be good to
merge the whole series through pwrseq tree or through an immutable branch.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
Manivannan Sadhasivam (12):
power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable
power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target
power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target
power: sequencing: pcie-m2: Fix inconsistent function prefixes
power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
power: sequencing: pcie-m2: Improve PCI device ID check
power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not
Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices
drivers/bluetooth/hci_qca.c | 40 +++--
drivers/power/sequencing/core.c | 33 ++++
drivers/power/sequencing/pwrseq-pcie-m2.c | 242 ++++++++++++++++++++++-------
drivers/power/sequencing/pwrseq-qcom-wcn.c | 9 ++
include/linux/pwrseq/consumer.h | 6 +
include/linux/pwrseq/provider.h | 2 +
6 files changed, 262 insertions(+), 70 deletions(-)
---
base-commit: 6596a02b207886e9e00bb0161c7fd59fea53c081
change-id: 20260422-pwrseq-m2-bt-abdaa71094eb
Best regards,
--
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:39 ` Fixes/improvements for the PCI M.2 power sequencing driver bluez.test.bot
2026-04-22 11:24 ` [PATCH 02/12] power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target Manivannan Sadhasivam via B4 Relay
` (10 subsequent siblings)
11 siblings, 1 reply; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Introduce an API pwrseq_is_fixed() so that the consumers can check whether
the given power sequencer is fixed or controllable. This will come handy
in situations where the consumers need to know whether the specific power
sequencer like 'Bluetooth' can be controllable using properties like BT_EN.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/core.c | 33 +++++++++++++++++++++++++++++++++
include/linux/pwrseq/consumer.h | 6 ++++++
include/linux/pwrseq/provider.h | 2 ++
3 files changed, 41 insertions(+)
diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
index 4dff71be11b6..20af9643f1ac 100644
--- a/drivers/power/sequencing/core.c
+++ b/drivers/power/sequencing/core.c
@@ -182,12 +182,14 @@ static void pwrseq_unit_release(struct kref *ref)
* the state lock has been released. It's useful for implementing
* boot-up delays without blocking other users from powering up
* using the same power sequencer.
+ * @is_fixed: Check whether this target is fixed or not.
*/
struct pwrseq_target {
struct list_head list;
const char *name;
struct pwrseq_unit *unit;
pwrseq_power_state_func post_enable;
+ bool (*is_fixed)(struct pwrseq_device *pwrseq);
};
static struct pwrseq_target *
@@ -206,6 +208,7 @@ pwrseq_target_new(const struct pwrseq_target_data *data)
}
target->post_enable = data->post_enable;
+ target->is_fixed = data->is_fixed;
return target;
}
@@ -965,6 +968,36 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
}
EXPORT_SYMBOL_GPL(pwrseq_power_off);
+/**
+ * pwrseq_is_fixed() - Check whether the power sequencer is fixed or
+ * controllable.
+ * @desc: Descriptor referencing the power sequencer.
+ *
+ * This API can be used to check whether a specific power sequencer like
+ * 'Bluetooth' is fixed or controllable through properties like 'BT_EN' GPIO.
+ *
+ * Returns: true if fixed, false if controllable.
+ */
+bool pwrseq_is_fixed(struct pwrseq_desc *desc)
+{
+ /*
+ * If there is no power sequencer, then the consumer cannot control
+ * the power, so it is effectively fixed.
+ */
+ if (!desc)
+ return true;
+
+ /*
+ * If the provider hasn't implemented the callback, assume it acts
+ * like a controllable power sequencer (for backward compatibility).
+ */
+ if (!desc->target->is_fixed)
+ return false;
+
+ return desc->target->is_fixed(desc->pwrseq);
+}
+EXPORT_SYMBOL_GPL(pwrseq_is_fixed);
+
#if IS_ENABLED(CONFIG_DEBUG_FS)
struct pwrseq_debugfs_count_ctx {
diff --git a/include/linux/pwrseq/consumer.h b/include/linux/pwrseq/consumer.h
index 7d583b4f266e..7c24958880d7 100644
--- a/include/linux/pwrseq/consumer.h
+++ b/include/linux/pwrseq/consumer.h
@@ -22,6 +22,7 @@ devm_pwrseq_get(struct device *dev, const char *target);
int pwrseq_power_on(struct pwrseq_desc *desc);
int pwrseq_power_off(struct pwrseq_desc *desc);
+bool pwrseq_is_fixed(struct pwrseq_desc *desc);
#else /* CONFIG_POWER_SEQUENCING */
@@ -51,6 +52,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
return -ENOSYS;
}
+static inline bool pwrseq_is_fixed(struct pwrseq_desc *desc)
+{
+ return true;
+}
+
#endif /* CONFIG_POWER_SEQUENCING */
#endif /* __POWER_SEQUENCING_CONSUMER_H__ */
diff --git a/include/linux/pwrseq/provider.h b/include/linux/pwrseq/provider.h
index 33b3d2c2e39d..11165e98cde0 100644
--- a/include/linux/pwrseq/provider.h
+++ b/include/linux/pwrseq/provider.h
@@ -43,11 +43,13 @@ struct pwrseq_unit_data {
* the state lock has been released. It's useful for implementing
* boot-up delays without blocking other users from powering up
* using the same power sequencer.
+ * @is_fixed: Callback to check whether this power sequencer is fixed or not.
*/
struct pwrseq_target_data {
const char *name;
const struct pwrseq_unit_data *unit;
pwrseq_power_state_func post_enable;
+ bool (*is_fixed)(struct pwrseq_device *pwrseq);
};
/**
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/12] power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 03/12] power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target Manivannan Sadhasivam via B4 Relay
` (9 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Add support for 'is_fixed()' callback to tell the consumers whether this
power sequencer target 'uart' is fixed or controllable. This is decided
based on the availability of the 'W_DISABLE2#' GPIO in DT.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index ef69ae268059..2b79f2e34079 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -121,10 +121,18 @@ static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
return 0;
}
+static bool pwrseq_pcie_m2_e_uart_is_fixed(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return !ctx->w_disable2_gpio;
+}
+
static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
.name = "uart",
.unit = &pwrseq_pcie_m2_e_uart_unit_data,
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
+ .is_fixed = pwrseq_pcie_m2_e_uart_is_fixed,
};
static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/12] power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 02/12] power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 04/12] power: sequencing: pcie-m2: Fix inconsistent function prefixes Manivannan Sadhasivam via B4 Relay
` (8 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Add support for 'is_fixed()' callback to indicate the consumers whether
this power sequencer target 'bluetooth' is fixed or controllable. This is
decided based on the availability of the 'bt-enable' GPIO in DT.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-qcom-wcn.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c
index b55b4317e21b..50ac5973b8e7 100644
--- a/drivers/power/sequencing/pwrseq-qcom-wcn.c
+++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c
@@ -254,10 +254,18 @@ static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq)
return pwrseq_qcom_wcn_pwup_delay(pwrseq);
}
+static bool pwrseq_qcom_wcn_bt_is_fixed(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return !ctx->bt_gpio;
+}
+
static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = {
.name = "bluetooth",
.unit = &pwrseq_qcom_wcn_bt_unit_data,
.post_enable = pwrseq_qcom_wcn_pwup_delay,
+ .is_fixed = pwrseq_qcom_wcn_bt_is_fixed,
};
static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
@@ -281,6 +289,7 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
.name = "bluetooth",
.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
+ .is_fixed = pwrseq_qcom_wcn_bt_is_fixed,
};
static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = {
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/12] power: sequencing: pcie-m2: Fix inconsistent function prefixes
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (2 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 03/12] power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 05/12] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices Manivannan Sadhasivam via B4 Relay
` (7 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
All functions in this driver follow 'pwrseq_pcie_m2' prefix except a few.
Fix them to avoid inconsistency.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 2b79f2e34079..49c326a6e445 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -185,7 +185,7 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
return PWRSEQ_NO_MATCH;
}
-static int pwrseq_m2_pcie_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
struct device_node *parent)
{
struct device *dev = ctx->dev;
@@ -262,7 +262,7 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
goto err_put_ctrl;
}
- ret = pwrseq_m2_pcie_create_bt_node(ctx, serdev_parent);
+ ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
if (ret)
goto err_free_serdev;
@@ -307,7 +307,7 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
}
}
-static int pwrseq_m2_pcie_notify(struct notifier_block *nb, unsigned long action,
+static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
struct pwrseq_pcie_m2_ctx *ctx = container_of(nb, struct pwrseq_pcie_m2_ctx, nb);
@@ -372,7 +372,7 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
ctx->dev = dev;
- ctx->nb.notifier_call = pwrseq_m2_pcie_notify;
+ ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
if (ret)
return dev_err_probe(dev, ret,
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/12] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (3 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 04/12] power: sequencing: pcie-m2: Fix inconsistent function prefixes Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check Manivannan Sadhasivam via B4 Relay
` (6 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Current code makes it possible to create serdev for only one PCI device.
But for scaling this driver, it is necessary to allow creating serdev for
multiple PCI devices.
Hence, add provision for it by creating 'struct pwrseq_pci_dev' for each
PCI device that requires serdev and add them to
'pwrseq_pcie_m2_ctx::pci_devices' list.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 127 +++++++++++++++++++++---------
1 file changed, 88 insertions(+), 39 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 49c326a6e445..d4d246a30a97 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -19,6 +20,13 @@
#include <linux/serdev.h>
#include <linux/slab.h>
+struct pwrseq_pci_dev {
+ struct serdev_device *serdev;
+ struct of_changeset *ocs;
+ struct pci_dev *pdev;
+ struct list_head list;
+};
+
struct pwrseq_pcie_m2_pdata {
const struct pwrseq_target_data **targets;
};
@@ -32,9 +40,9 @@ struct pwrseq_pcie_m2_ctx {
struct notifier_block nb;
struct gpio_desc *w_disable1_gpio;
struct gpio_desc *w_disable2_gpio;
- struct serdev_device *serdev;
- struct of_changeset *ocs;
struct device *dev;
+ struct list_head pci_devices;
+ struct mutex list_lock;
};
static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
@@ -186,38 +194,39 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
}
static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pwrseq_pci_dev *pci_dev,
struct device_node *parent)
{
struct device *dev = ctx->dev;
struct device_node *np;
int ret;
- ctx->ocs = kzalloc_obj(*ctx->ocs);
- if (!ctx->ocs)
+ pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
+ if (!pci_dev->ocs)
return -ENOMEM;
- of_changeset_init(ctx->ocs);
+ of_changeset_init(pci_dev->ocs);
- np = of_changeset_create_node(ctx->ocs, parent, "bluetooth");
+ np = of_changeset_create_node(pci_dev->ocs, parent, "bluetooth");
if (!np) {
dev_err(dev, "Failed to create bluetooth node\n");
ret = -ENODEV;
goto err_destroy_changeset;
}
- ret = of_changeset_add_prop_string(ctx->ocs, np, "compatible", "qcom,wcn7850-bt");
+ ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
if (ret) {
dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
goto err_destroy_changeset;
}
- ret = of_changeset_apply(ctx->ocs);
+ ret = of_changeset_apply(pci_dev->ocs);
if (ret) {
dev_err(dev, "Failed to apply changeset: %d\n", ret);
goto err_destroy_changeset;
}
- ret = device_add_of_node(&ctx->serdev->dev, np);
+ ret = device_add_of_node(&pci_dev->serdev->dev, np);
if (ret) {
dev_err(dev, "Failed to add OF node: %d\n", ret);
goto err_revert_changeset;
@@ -226,19 +235,21 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
return 0;
err_revert_changeset:
- of_changeset_revert(ctx->ocs);
+ of_changeset_revert(pci_dev->ocs);
err_destroy_changeset:
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
+ pci_dev->ocs = NULL;
return ret;
}
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pci_dev *pdev)
{
struct serdev_controller *serdev_ctrl;
struct device *dev = ctx->dev;
+ struct pwrseq_pci_dev *pci_dev;
int ret;
struct device_node *serdev_parent __free(device_node) =
@@ -256,17 +267,23 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
return 0;
}
- ctx->serdev = serdev_device_alloc(serdev_ctrl);
- if (!ctx->serdev) {
+ pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
+ if (!pci_dev) {
ret = -ENOMEM;
goto err_put_ctrl;
}
- ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
+ pci_dev->serdev = serdev_device_alloc(serdev_ctrl);
+ if (!pci_dev->serdev) {
+ ret = -ENOMEM;
+ goto err_free_pci_dev;
+ }
+
+ ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
if (ret)
goto err_free_serdev;
- ret = serdev_device_add(ctx->serdev);
+ ret = serdev_device_add(pci_dev->serdev);
if (ret) {
dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
goto err_free_dt_node;
@@ -274,37 +291,64 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
serdev_controller_put(serdev_ctrl);
+ pci_dev->pdev = pci_dev_get(pdev);
+
+ mutex_lock(&ctx->list_lock);
+ list_add_tail(&pci_dev->list, &ctx->pci_devices);
+ mutex_unlock(&ctx->list_lock);
+
return 0;
err_free_dt_node:
- device_remove_of_node(&ctx->serdev->dev);
- of_changeset_revert(ctx->ocs);
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ device_remove_of_node(&pci_dev->serdev->dev);
+ of_changeset_revert(pci_dev->ocs);
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
+ pci_dev->ocs = NULL;
err_free_serdev:
- serdev_device_put(ctx->serdev);
- ctx->serdev = NULL;
+ serdev_device_put(pci_dev->serdev);
+ pci_dev->serdev = NULL;
+err_free_pci_dev:
+ kfree(pci_dev);
err_put_ctrl:
serdev_controller_put(serdev_ctrl);
return ret;
}
-static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static void __pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pwrseq_pci_dev *pci_dev)
{
- if (ctx->serdev) {
- device_remove_of_node(&ctx->serdev->dev);
- serdev_device_remove(ctx->serdev);
- ctx->serdev = NULL;
+ if (pci_dev->serdev) {
+ device_remove_of_node(&pci_dev->serdev->dev);
+ serdev_device_remove(pci_dev->serdev);
}
- if (ctx->ocs) {
- of_changeset_revert(ctx->ocs);
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ if (pci_dev->ocs) {
+ of_changeset_revert(pci_dev->ocs);
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
}
+
+ pci_dev_put(pci_dev->pdev);
+ list_del(&pci_dev->list);
+ kfree(pci_dev);
+}
+
+static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pci_dev *pdev)
+{
+ struct pwrseq_pci_dev *pci_dev, *tmp;
+
+ mutex_lock(&ctx->list_lock);
+ list_for_each_entry_safe(pci_dev, tmp, &ctx->pci_devices, list) {
+ if (!pdev || pci_dev->pdev == pdev) {
+ __pwrseq_pcie_m2_remove_serdev(ctx, pci_dev);
+ if (pdev)
+ break;
+ }
+ }
+ mutex_unlock(&ctx->list_lock);
}
static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
@@ -328,7 +372,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_ADD_DEVICE:
/* Create serdev device for WCN7850 */
if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
- ret = pwrseq_pcie_m2_create_serdev(ctx);
+ ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
if (ret)
return notifier_from_errno(ret);
}
@@ -336,7 +380,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_REMOVED_DEVICE:
/* Destroy serdev device for WCN7850 */
if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
- pwrseq_pcie_m2_remove_serdev(ctx);
+ pwrseq_pcie_m2_remove_serdev(ctx, pdev);
break;
}
@@ -440,16 +484,20 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
goto err_free_regulators;
}
+ mutex_init(&ctx->list_lock);
+ INIT_LIST_HEAD(&ctx->pci_devices);
/*
* Register a notifier for creating protocol devices for
* non-discoverable busses like UART.
*/
ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
if (ret)
- goto err_free_regulators;
+ goto err_destroy_mutex;
return 0;
+err_destroy_mutex:
+ mutex_destroy(&ctx->list_lock);
err_free_regulators:
regulator_bulk_free(ctx->num_vregs, ctx->regs);
@@ -461,7 +509,8 @@ static void pwrseq_pcie_m2_remove(struct platform_device *pdev)
struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev);
bus_unregister_notifier(&pci_bus_type, &ctx->nb);
- pwrseq_pcie_m2_remove_serdev(ctx);
+ pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+ mutex_destroy(&ctx->list_lock);
regulator_bulk_free(ctx->num_vregs, ctx->regs);
}
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (4 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 05/12] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 12:17 ` Konrad Dybcio
2026-04-22 11:24 ` [PATCH 07/12] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe Manivannan Sadhasivam via B4 Relay
` (5 subsequent siblings)
11 siblings, 1 reply; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Instead of hardcoding the PCI device check, use pci_match_id() to check for
the known IDs using the pwrseq_m2_pci_ids[] array.
This makes adding support for new devices easier.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index d4d246a30a97..bdc4391c87c9 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -351,6 +351,11 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
mutex_unlock(&ctx->list_lock);
}
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
+ { } /* Sentinel */
+};
+
static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
@@ -370,16 +375,14 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
- /* Create serdev device for WCN7850 */
- if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
+ if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
if (ret)
return notifier_from_errno(ret);
}
break;
case BUS_NOTIFY_REMOVED_DEVICE:
- /* Destroy serdev device for WCN7850 */
- if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
+ if (pci_match_id(pwrseq_m2_pci_ids, pdev))
pwrseq_pcie_m2_remove_serdev(ctx, pdev);
break;
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/12] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (5 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 08/12] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table Manivannan Sadhasivam via B4 Relay
` (4 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
So far, the driver is registering a notifier to create serdev for the PCI
devices that are going to be attached after probe. But it doesn't handle
the devices present before probe. Due to this, serdev is not getting
created for those existing devices.
Hence, create serdev for PCI devices available before probe as well.
Note that the serdev for available devices are created before
registering the notifier. There is a small window where a device could
appear after pwrseq_pcie_m2_create_serdev(), before notifier registration.
But since M.2 cards are fixed to a slot, they are mostly added either
before booting the host or after using hotplug. So this window is mostly
theoretical.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 83 ++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 13 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index bdc4391c87c9..b21fcc089580 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -244,7 +244,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
return ret;
}
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+static int __pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
struct pci_dev *pdev)
{
struct serdev_controller *serdev_ctrl;
@@ -267,6 +267,16 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
return 0;
}
+ /* Bail out if the serdev device was already created for the PCI dev */
+ mutex_lock(&ctx->list_lock);
+ list_for_each_entry(pci_dev, &ctx->pci_devices, list) {
+ if (pci_dev->pdev == pdev) {
+ mutex_unlock(&ctx->list_lock);
+ return 0;
+ }
+ }
+ mutex_unlock(&ctx->list_lock);
+
pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
if (!pci_dev) {
ret = -ENOMEM;
@@ -376,7 +386,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
- ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
+ ret = __pwrseq_pcie_m2_create_serdev(ctx, pdev);
if (ret)
return notifier_from_errno(ret);
}
@@ -408,7 +418,7 @@ static bool pwrseq_pcie_m2_check_remote_node(struct device *dev, u8 port, u8 end
* protocol device needs to be created manually with the help of the notifier
* of the discoverable bus like PCIe.
*/
-static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, struct device *dev)
+static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx)
{
int ret;
@@ -416,18 +426,56 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
* Register a PCI notifier for Key E connector that has PCIe as Port
* 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface.
*/
- if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
- if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
- ctx->dev = dev;
- ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
- ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to register notifier for serdev\n");
+ if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+ !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+ return 0;
+
+ ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
+ ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
+ if (ret)
+ return dev_err_probe(ctx->dev, ret,
+ "Failed to register notifier for serdev\n");
+ return 0;
+}
+
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+{
+ struct pci_dev *pdev = NULL;
+ int ret;
+
+ if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+ !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+ return 0;
+
+ struct device_node *pci_parent __free(device_node) =
+ of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
+ if (!pci_parent)
+ return 0;
+
+ /* Create serdev for existing PCI devices if required */
+ for_each_pci_dev(pdev) {
+ if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node)
+ continue;
+
+ if (!pci_match_id(pwrseq_m2_pci_ids, pdev))
+ continue;
+
+ ret = __pwrseq_pcie_m2_create_serdev(ctx, pdev);
+ if (ret) {
+ dev_err_probe(ctx->dev, ret,
+ "Failed to create serdev for PCI device (%s)\n",
+ pci_name(pdev));
+ pci_dev_put(pdev);
+ goto err_remove_serdev;
}
}
return 0;
+
+err_remove_serdev:
+ pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+
+ return ret;
}
static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
@@ -489,16 +537,25 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
mutex_init(&ctx->list_lock);
INIT_LIST_HEAD(&ctx->pci_devices);
+ ctx->dev = dev;
+
+ /* Create serdev for available PCI devices (if required) */
+ ret = pwrseq_pcie_m2_create_serdev(ctx);
+ if (ret)
+ goto err_destroy_mutex;
+
/*
* Register a notifier for creating protocol devices for
* non-discoverable busses like UART.
*/
- ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
+ ret = pwrseq_pcie_m2_register_notifier(ctx);
if (ret)
- goto err_destroy_mutex;
+ goto err_remove_serdev;
return 0;
+err_remove_serdev:
+ pwrseq_pcie_m2_remove_serdev(ctx, NULL);
err_destroy_mutex:
mutex_destroy(&ctx->list_lock);
err_free_regulators:
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/12] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (6 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 07/12] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 09/12] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq Manivannan Sadhasivam via B4 Relay
` (3 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Currently, pwrseq_pcie_m2_create_bt_node() hardcodes the BT compatible for
creating the devicetree node. But to allow adding support for more devices
in the future, create the BT node based on the pci_device_id[] table. The
BT compatible is passed using 'driver_data'.
Co-developed-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index b21fcc089580..23dc91e2b128 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -193,14 +193,29 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
return PWRSEQ_NO_MATCH;
}
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
+ .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
+ { } /* Sentinel */
+};
+
static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
struct pwrseq_pci_dev *pci_dev,
- struct device_node *parent)
+ struct device_node *parent,
+ struct pci_dev *pdev)
{
+ const struct pci_device_id *id;
struct device *dev = ctx->dev;
+ const char *compatible;
struct device_node *np;
int ret;
+ id = pci_match_id(pwrseq_m2_pci_ids, pdev);
+ if (WARN_ON_ONCE(!id)) /* Shouldn't happen */
+ return -ENODEV;
+
+ compatible = (const char *)id->driver_data;
+
pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
if (!pci_dev->ocs)
return -ENOMEM;
@@ -214,7 +229,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
goto err_destroy_changeset;
}
- ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
+ ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", compatible);
if (ret) {
dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
goto err_destroy_changeset;
@@ -289,13 +304,14 @@ static int __pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
goto err_free_pci_dev;
}
- ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
+ ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent, pdev);
if (ret)
goto err_free_serdev;
ret = serdev_device_add(pci_dev->serdev);
if (ret) {
- dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
+ dev_err(dev, "Failed to add serdev for PCI device (%s): %d\n",
+ pci_name(pdev), ret);
goto err_free_dt_node;
}
@@ -361,11 +377,6 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
mutex_unlock(&ctx->list_lock);
}
-static const struct pci_device_id pwrseq_m2_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
- { } /* Sentinel */
-};
-
static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/12] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (7 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 08/12] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 10/12] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available' Manivannan Sadhasivam via B4 Relay
` (2 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
Bartosz Golaszewski
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
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.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@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 cd1834246b47..c83fe72bc549 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -26,6 +26,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/pwrseq/consumer.h>
@@ -2443,6 +2444,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
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/12] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (8 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 09/12] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 11/12] Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices Manivannan Sadhasivam via B4 Relay
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
'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.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@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 c83fe72bc549..3e71a72ea7c7 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2391,7 +2391,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)
@@ -2499,7 +2499,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);
@@ -2537,7 +2537,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);
@@ -2555,7 +2555,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;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 11/12] Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (9 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 10/12] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available' Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices Manivannan Sadhasivam via B4 Relay
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
In the M.2 connector, the UART interface is controlled through the
W_DISABLE2# signal. But the BT driver cannot know directly whether this
signal is available or not.
Hence, use the new pwrseq API 'pwrseq_is_fixed()' to check whether the UART
interface on the M.2 connector is fixed or controllable and set the
'bt_en_available' flag accordingly.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 3e71a72ea7c7..27e52b08ec47 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2453,6 +2453,10 @@ static int qca_serdev_probe(struct serdev_device *serdev)
"uart");
if (IS_ERR(qcadev->bt_power->pwrseq))
return PTR_ERR(qcadev->bt_power->pwrseq);
+
+ if (pwrseq_is_fixed(qcadev->bt_power->pwrseq))
+ bt_en_available = false;
+
break;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
` (10 preceding siblings ...)
2026-04-22 11:24 ` [PATCH 11/12] Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:24 ` Manivannan Sadhasivam via B4 Relay
11 siblings, 0 replies; 15+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
stable+noautosel
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Commit 'db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT
driver")' tried to check the presence of the BT_EN GPIO in Qcom WCN devices
to indicate the HCI layer whether this BT device can be power controlled or
not.
But it was broken for two reasons:
1. Assumes that when devm_pwrseq_get() API returns an error, BT_EN is not
controllable. This is no way true as the API can fail for various reasons
and also the pwrseq-qcom-wcn driver treats the BT_EN GPIO as optional. So
even if the GPIO is not present, it will not fail the probe and this API
will not fail.
2. By skipping the error return, probe deferral is completely broken as the
API may return -EPROBE_DEFER to indicate the caller that the pwrseq driver
is not yet probed. Skipping the return value means, this driver is not
going to depend on pwrseq driver probing again and it just assumes that
the pwrseq is not available.
So to fix these issues, fail the probe if devm_pwrseq_get() returns an
error and if it succeeds, use the newly introduced pwrseq_is_fixed() API to
check whether the power sequencer is fixed or not (i.e., whether the
Bluetooth interface on the Qcom WCN device is controllable using BT_EN GPIO
or not) and set the 'bt_en_available' flag accordingly.
Cc: <stable+noautosel@kernel.org> # Depends on pwrseq change
Fixes: db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 27e52b08ec47..dd1d93cbb3d8 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2470,16 +2470,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
"bluetooth");
- /*
- * Some modules have BT_EN enabled via a hardware pull-up,
- * meaning it is not defined in the DTS and is not controlled
- * through the power sequence. In such cases, fall through
- * to follow the legacy flow.
- */
if (IS_ERR(qcadev->bt_power->pwrseq))
- qcadev->bt_power->pwrseq = NULL;
- else
- break;
+ return PTR_ERR(qcadev->bt_power->pwrseq);
+
+ if (pwrseq_is_fixed(qcadev->bt_power->pwrseq))
+ bt_en_available = false;
+
+ break;
}
qcadev->bt_power->dev = &serdev->dev;
--
2.51.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* RE: Fixes/improvements for the PCI M.2 power sequencing driver
2026-04-22 11:24 ` [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 11:39 ` bluez.test.bot
0 siblings, 0 replies; 15+ messages in thread
From: bluez.test.bot @ 2026-04-22 11:39 UTC (permalink / raw)
To: linux-bluetooth, manivannan.sadhasivam
[-- Attachment #1: Type: text/plain, Size: 584 bytes --]
This is an automated email and please do not reply to this email.
Dear Submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.
----- Output -----
error: patch failed: drivers/power/sequencing/pwrseq-pcie-m2.c:121
error: drivers/power/sequencing/pwrseq-pcie-m2.c: patch does not apply
hint: Use 'git am --show-current-patch' to see the failed patch
Please resolve the issue and submit the patches again.
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check
2026-04-22 11:24 ` [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check Manivannan Sadhasivam via B4 Relay
@ 2026-04-22 12:17 ` Konrad Dybcio
0 siblings, 0 replies; 15+ messages in thread
From: Konrad Dybcio @ 2026-04-22 12:17 UTC (permalink / raw)
To: manivannan.sadhasivam, Bartosz Golaszewski, Manivannan Sadhasivam,
Marcel Holtmann, Luiz Augusto von Dentz, Shuai Zhang
Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
Wei Deng, Luiz Augusto von Dentz
On 4/22/26 1:24 PM, Manivannan Sadhasivam via B4 Relay wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> Instead of hardcoding the PCI device check, use pci_match_id() to check for
> the known IDs using the pwrseq_m2_pci_ids[] array.
>
> This makes adding support for new devices easier.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-04-22 12:17 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-22 11:24 [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable Manivannan Sadhasivam via B4 Relay
2026-04-22 11:39 ` Fixes/improvements for the PCI M.2 power sequencing driver bluez.test.bot
2026-04-22 11:24 ` [PATCH 02/12] power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 03/12] power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 04/12] power: sequencing: pcie-m2: Fix inconsistent function prefixes Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 05/12] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check Manivannan Sadhasivam via B4 Relay
2026-04-22 12:17 ` Konrad Dybcio
2026-04-22 11:24 ` [PATCH 07/12] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 08/12] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 09/12] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 10/12] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available' Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 11/12] Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not Manivannan Sadhasivam via B4 Relay
2026-04-22 11:24 ` [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices Manivannan Sadhasivam via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox