* [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible
2026-07-02 10:46 [PATCH v2 0/4] arm64: dts: monaco-arduino-monza: Add support for LGA WiFi/BT module Loic Poulain
@ 2026-07-02 10:46 ` Loic Poulain
2026-07-02 13:17 ` Manivannan Sadhasivam
2026-07-03 7:11 ` Krzysztof Kozlowski
2026-07-02 10:46 ` [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID Loic Poulain
` (2 subsequent siblings)
3 siblings, 2 replies; 18+ messages in thread
From: Loic Poulain @ 2026-07-02 10:46 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Loic Poulain
Some modules (e.g. the Qualcomm QCA2066/QCNFA765) expose the same M.2
Key E interface signals but are physically soldered as an LGA package
rather than plugged into a real M.2 Key E connector socket. Such designs
are not actual M.2 Key E connectors, so describe them with a dedicated
vendor-specific compatible while keeping "pcie-m2-e-connector" as a
fallback for the shared signal semantics.
Add "qcom,pcie-m2-1418-lga-connector" for the M.2 LGA 1418 module.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../devicetree/bindings/connector/pcie-m2-e-connector.yaml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml b/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
index f7859aa9b63469cb43919c0b5719c18694c5364d..0282c6ee9272446064a99ec6314a5ceb1721e0c4 100644
--- a/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
+++ b/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
@@ -17,7 +17,12 @@ description:
properties:
compatible:
- const: pcie-m2-e-connector
+ oneOf:
+ - const: pcie-m2-e-connector
+ - items:
+ - enum:
+ - qcom,pcie-m2-1418-lga-connector
+ - const: pcie-m2-e-connector
vpcie3v3-supply:
description: A phandle to the regulator for 3.3v supply.
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible
2026-07-02 10:46 ` [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible Loic Poulain
@ 2026-07-02 13:17 ` Manivannan Sadhasivam
2026-07-03 7:11 ` Krzysztof Kozlowski
1 sibling, 0 replies; 18+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-02 13:17 UTC (permalink / raw)
To: Loic Poulain
Cc: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-pci, linux-pm, linux-kernel, linux-arm-msm,
linux-bluetooth, devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 12:46:13PM +0200, Loic Poulain wrote:
> Some modules (e.g. the Qualcomm QCA2066/QCNFA765) expose the same M.2
> Key E interface signals but are physically soldered as an LGA package
> rather than plugged into a real M.2 Key E connector socket. Such designs
> are not actual M.2 Key E connectors, so describe them with a dedicated
> vendor-specific compatible while keeping "pcie-m2-e-connector" as a
> fallback for the shared signal semantics.
>
> Add "qcom,pcie-m2-1418-lga-connector" for the M.2 LGA 1418 module.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
- Mani
> ---
> .../devicetree/bindings/connector/pcie-m2-e-connector.yaml | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml b/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
> index f7859aa9b63469cb43919c0b5719c18694c5364d..0282c6ee9272446064a99ec6314a5ceb1721e0c4 100644
> --- a/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
> +++ b/Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
> @@ -17,7 +17,12 @@ description:
>
> properties:
> compatible:
> - const: pcie-m2-e-connector
> + oneOf:
> + - const: pcie-m2-e-connector
> + - items:
> + - enum:
> + - qcom,pcie-m2-1418-lga-connector
> + - const: pcie-m2-e-connector
>
> vpcie3v3-supply:
> description: A phandle to the regulator for 3.3v supply.
>
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible
2026-07-02 10:46 ` [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible Loic Poulain
2026-07-02 13:17 ` Manivannan Sadhasivam
@ 2026-07-03 7:11 ` Krzysztof Kozlowski
2026-07-03 8:41 ` Loic Poulain
1 sibling, 1 reply; 18+ messages in thread
From: Krzysztof Kozlowski @ 2026-07-03 7:11 UTC (permalink / raw)
To: Loic Poulain
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 12:46:13PM +0200, Loic Poulain wrote:
> Some modules (e.g. the Qualcomm QCA2066/QCNFA765) expose the same M.2
> Key E interface signals but are physically soldered as an LGA package
Why do we need device nodes for soldered connectors? Soldered stuff is
afixed one, not connectable connector, thus it has no point in DT
representation.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible
2026-07-03 7:11 ` Krzysztof Kozlowski
@ 2026-07-03 8:41 ` Loic Poulain
0 siblings, 0 replies; 18+ messages in thread
From: Loic Poulain @ 2026-07-03 8:41 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Fri, Jul 3, 2026 at 9:11 AM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On Thu, Jul 02, 2026 at 12:46:13PM +0200, Loic Poulain wrote:
> > Some modules (e.g. the Qualcomm QCA2066/QCNFA765) expose the same M.2
> > Key E interface signals but are physically soldered as an LGA package
>
> Why do we need device nodes for soldered connectors? Soldered stuff is
> afixed one, not connectable connector, thus it has no point in DT
> representation.
The LGA module is soldered, yes, but the node here isn't really
modeling a mateable/removable connector, it's the DT description of
the M.2 Key E electrical interface that the module exposes: the
W_DISABLE1 and #/W_DISABLE2# enable signals, the shared PCIe/UART
regulators, and the graph routing PCIe->WiFi and UART->BT. The
pwrseq-pcie-m2 driver and the graph binding rely on exactly this
description to sequence PCIe and UART bring-up, and that's independent
of whether the module is socketed or soldered.
Electrically the QCA2066 LGA on that part is an M.2 Key E design,
only the physical attachment differs. That's what the vendor-specific
qcom,pcie-m2-1418-lga-connector compatible is meant to capture, the
soldered/LGA variant of that interface. So reusing the connector
binding is a pragmatic way to model and drive it.
It also keeps the enumerable-slot semantics: since M.2 devices are
discovered via PCIe IDs, a board variant with a different chipset
soldered to the same LGA grid would be handled automatically, without
DT changes, exactly as it would be for a physical M.2 slot.
If the concern is purely the "connector" naming for a soldered part, I
can reframe the binding.
Regards,
Loic
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID
2026-07-02 10:46 [PATCH v2 0/4] arm64: dts: monaco-arduino-monza: Add support for LGA WiFi/BT module Loic Poulain
2026-07-02 10:46 ` [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible Loic Poulain
@ 2026-07-02 10:46 ` Loic Poulain
2026-07-02 11:57 ` Dmitry Baryshkov
2026-07-03 8:30 ` (subset) " Bartosz Golaszewski
2026-07-02 10:46 ` [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq Loic Poulain
2026-07-02 10:46 ` [PATCH v2 4/4] arm64: dts: qcom: monaco-arduino-monza: Add QCA2066 M.2 WiFi/BT support Loic Poulain
3 siblings, 2 replies; 18+ messages in thread
From: Loic Poulain @ 2026-07-02 10:46 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Loic Poulain
Add PCI IDs for Qualcomm QCA2066/QCNFA765 to the M.2 serdev ID table,
mapping it to the qcom,qca2066-bt compatible string.
The Subsystem Vendor ID (SVID) 0x0108 distinguishes the QCA2066 from
the WCN6855.
This allows the pwrseq-pcie-m2 driver to automatically create the
Bluetooth serdev device when a QCA2066-based M.2 card is enumerated.
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index e3ba9169144dabbf0c553c0a4302c3b511fcaaa1..7cb455569d8eb5da12e46606d9f25bdaeb8a128c 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -190,6 +190,8 @@ static const struct pci_device_id pwrseq_m2_pci_ids[] = {
.driver_data = (kernel_ulong_t)"nxp,88w8987-bt" },
{ PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, 0x3003),
.driver_data = (kernel_ulong_t)"nxp,88w8987-bt" },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x1103, PCI_VENDOR_ID_QCOM, 0x0108),
+ .driver_data = (kernel_ulong_t)"qcom,qca2066-bt" },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1103),
.driver_data = (kernel_ulong_t)"qcom,wcn6855-bt" },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID
2026-07-02 10:46 ` [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID Loic Poulain
@ 2026-07-02 11:57 ` Dmitry Baryshkov
2026-07-03 8:30 ` (subset) " Bartosz Golaszewski
1 sibling, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-07-02 11:57 UTC (permalink / raw)
To: Loic Poulain
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 12:46:14PM +0200, Loic Poulain wrote:
> Add PCI IDs for Qualcomm QCA2066/QCNFA765 to the M.2 serdev ID table,
> mapping it to the qcom,qca2066-bt compatible string.
>
> The Subsystem Vendor ID (SVID) 0x0108 distinguishes the QCA2066 from
> the WCN6855.
>
> This allows the pwrseq-pcie-m2 driver to automatically create the
> Bluetooth serdev device when a QCA2066-based M.2 card is enumerated.
>
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> drivers/power/sequencing/pwrseq-pcie-m2.c | 2 ++
> 1 file changed, 2 insertions(+)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: (subset) [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID
2026-07-02 10:46 ` [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID Loic Poulain
2026-07-02 11:57 ` Dmitry Baryshkov
@ 2026-07-03 8:30 ` Bartosz Golaszewski
1 sibling, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2026-07-03 8:30 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Loic Poulain
Cc: Bartosz Golaszewski, linux-pci, linux-pm, linux-kernel,
linux-arm-msm, linux-bluetooth, devicetree, Manivannan Sadhasivam
On Thu, 02 Jul 2026 12:46:14 +0200, Loic Poulain wrote:
> Add PCI IDs for Qualcomm QCA2066/QCNFA765 to the M.2 serdev ID table,
> mapping it to the qcom,qca2066-bt compatible string.
>
> The Subsystem Vendor ID (SVID) 0x0108 distinguishes the QCA2066 from
> the WCN6855.
>
> This allows the pwrseq-pcie-m2 driver to automatically create the
> Bluetooth serdev device when a QCA2066-based M.2 card is enumerated.
>
> [...]
Applied, thanks!
[2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID
https://git.kernel.org/brgl/c/1656f4f2eb45d9f18515ac00657a2494719fa065
Best regards,
--
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 10:46 [PATCH v2 0/4] arm64: dts: monaco-arduino-monza: Add support for LGA WiFi/BT module Loic Poulain
2026-07-02 10:46 ` [PATCH v2 1/4] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible Loic Poulain
2026-07-02 10:46 ` [PATCH v2 2/4] power: sequencing: pcie-m2: Add QCA2066 (QCNFA765) BT serdev ID Loic Poulain
@ 2026-07-02 10:46 ` Loic Poulain
2026-07-02 12:14 ` Dmitry Baryshkov
2026-07-02 14:20 ` Manivannan Sadhasivam
2026-07-02 10:46 ` [PATCH v2 4/4] arm64: dts: qcom: monaco-arduino-monza: Add QCA2066 M.2 WiFi/BT support Loic Poulain
3 siblings, 2 replies; 18+ messages in thread
From: Loic Poulain @ 2026-07-02 10:46 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Loic Poulain
For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
sequencer rather than a dedicated BT enable GPIO.
When the serdev controller has an OF graph (indicating it is connected
to an M.2 connector), acquire the 'uart' pwrseq target from the
connector's power sequencer and use it to control BT power instead of
the bt-enable GPIO.
Also allocate bt_power unconditionally for all SOC types since the
pwrseq path is independent of the SOC type switch.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
1 file changed, 43 insertions(+), 38 deletions(-)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
/* Controller needs time to bootup. */
msleep(150);
}
+
+ if (qcadev->bt_power->pwrseq)
+ pwrseq_power_on(qcadev->bt_power->pwrseq);
}
clear_bit(QCA_BT_OFF, &qca->flags);
@@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
break;
}
- if (power && power->pwrseq) {
+ if (power->pwrseq) {
pwrseq_power_off(power->pwrseq);
set_bit(QCA_BT_OFF, &qca->flags);
return;
@@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
return 0;
}
+/*
+ * Acquire the M.2 connector power sequencer.
+ *
+ * An OF graph link on the serdev controller is only present when the BT
+ * device is attached through an M.2 Key E connector. In that case the UART
+ * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
+ * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
+ *
+ * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
+ * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
+ */
+static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
+{
+ struct serdev_device *serdev = qcadev->serdev_hu.serdev;
+ struct device *dev;
+
+ if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
+ return 0;
+
+ 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);
+ *bt_en_available = device_property_present(dev, "w-disable2-gpios");
+
+ return 0;
+}
+
static int qca_serdev_probe(struct serdev_device *serdev)
{
struct qca_serdev *qcadev;
@@ -2417,25 +2449,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
else
qcadev->btsoc_type = QCA_ROME;
- switch (qcadev->btsoc_type) {
- case QCA_QCA6390:
- case QCA_WCN3950:
- case QCA_WCN3988:
- case QCA_WCN3990:
- case QCA_WCN3991:
- case QCA_WCN3998:
- case QCA_WCN6750:
- case QCA_WCN6855:
- case QCA_WCN7850:
- qcadev->bt_power = devm_kzalloc(&serdev->dev,
- sizeof(struct qca_power),
- GFP_KERNEL);
- if (!qcadev->bt_power)
- return -ENOMEM;
- break;
- default:
- break;
- }
+ qcadev->bt_power = devm_kzalloc(&serdev->dev, sizeof(struct qca_power), GFP_KERNEL);
+ if (!qcadev->bt_power)
+ return -ENOMEM;
+
+ err = qca_serdev_get_m2_pwrseq(qcadev, &bt_en_available);
+ if (err)
+ return err;
switch (qcadev->btsoc_type) {
case QCA_WCN3950:
@@ -2446,24 +2466,9 @@ 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))) {
- 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;
-
+ /* M.2 connector modules are powered by the pwrseq acquired above. */
+ if (qcadev->bt_power->pwrseq)
break;
- }
if (!device_property_present(&serdev->dev, "enable-gpios")) {
/*
@@ -2545,7 +2550,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
return PTR_ERR(qcadev->bt_en);
}
- if (!qcadev->bt_en)
+ if (!qcadev->bt_en && !qcadev->bt_power->pwrseq)
bt_en_available = false;
qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 10:46 ` [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq Loic Poulain
@ 2026-07-02 12:14 ` Dmitry Baryshkov
2026-07-02 14:17 ` Manivannan Sadhasivam
2026-07-02 14:20 ` Manivannan Sadhasivam
1 sibling, 1 reply; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-07-02 12:14 UTC (permalink / raw)
To: Loic Poulain
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> sequencer rather than a dedicated BT enable GPIO.
>
> When the serdev controller has an OF graph (indicating it is connected
> to an M.2 connector), acquire the 'uart' pwrseq target from the
> connector's power sequencer and use it to control BT power instead of
> the bt-enable GPIO.
>
> Also allocate bt_power unconditionally for all SOC types since the
Can we just fold it into the main struct?
> pwrseq path is independent of the SOC type switch.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> 1 file changed, 43 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> /* Controller needs time to bootup. */
> msleep(150);
> }
> +
> + if (qcadev->bt_power->pwrseq)
> + pwrseq_power_on(qcadev->bt_power->pwrseq);
> }
>
> clear_bit(QCA_BT_OFF, &qca->flags);
> @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> break;
> }
>
> - if (power && power->pwrseq) {
> + if (power->pwrseq) {
> pwrseq_power_off(power->pwrseq);
> set_bit(QCA_BT_OFF, &qca->flags);
> return;
> @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> return 0;
> }
>
> +/*
> + * Acquire the M.2 connector power sequencer.
> + *
> + * An OF graph link on the serdev controller is only present when the BT
> + * device is attached through an M.2 Key E connector. In that case the UART
> + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> + *
> + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> + */
> +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> +{
> + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> + struct device *dev;
> +
> + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> + return 0;
> +
> + 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);
> + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
I think here you are looking into the exact details of the other of the
graph. There might be other devices on that side, while the code now
assumes M.2. Or, consider having an M.2 controller which handles
W_DISABLE2# internally rather than through the GPIO.
> +
> + return 0;
> +}
> +
> static int qca_serdev_probe(struct serdev_device *serdev)
> {
> struct qca_serdev *qcadev;
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 12:14 ` Dmitry Baryshkov
@ 2026-07-02 14:17 ` Manivannan Sadhasivam
2026-07-02 14:34 ` Dmitry Baryshkov
0 siblings, 1 reply; 18+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-02 14:17 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Loic Poulain, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 03:14:49PM +0300, Dmitry Baryshkov wrote:
> On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> > For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> > is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> > sequencer rather than a dedicated BT enable GPIO.
> >
> > When the serdev controller has an OF graph (indicating it is connected
> > to an M.2 connector), acquire the 'uart' pwrseq target from the
> > connector's power sequencer and use it to control BT power instead of
> > the bt-enable GPIO.
> >
> > Also allocate bt_power unconditionally for all SOC types since the
>
> Can we just fold it into the main struct?
>
> > pwrseq path is independent of the SOC type switch.
> >
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
> > drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> > 1 file changed, 43 insertions(+), 38 deletions(-)
> >
> > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> > --- a/drivers/bluetooth/hci_qca.c
> > +++ b/drivers/bluetooth/hci_qca.c
> > @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> > /* Controller needs time to bootup. */
> > msleep(150);
> > }
> > +
> > + if (qcadev->bt_power->pwrseq)
> > + pwrseq_power_on(qcadev->bt_power->pwrseq);
> > }
> >
> > clear_bit(QCA_BT_OFF, &qca->flags);
> > @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> > break;
> > }
> >
> > - if (power && power->pwrseq) {
> > + if (power->pwrseq) {
> > pwrseq_power_off(power->pwrseq);
> > set_bit(QCA_BT_OFF, &qca->flags);
> > return;
> > @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> > return 0;
> > }
> >
> > +/*
> > + * Acquire the M.2 connector power sequencer.
> > + *
> > + * An OF graph link on the serdev controller is only present when the BT
> > + * device is attached through an M.2 Key E connector. In that case the UART
> > + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> > + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> > + *
> > + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> > + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> > + */
> > +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> > +{
> > + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> > + struct device *dev;
> > +
> > + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> > + return 0;
> > +
> > + 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);
> > + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
>
> I think here you are looking into the exact details of the other of the
> graph. There might be other devices on that side, while the code now
> assumes M.2. Or, consider having an M.2 controller which handles
> W_DISABLE2# internally rather than through the GPIO.
>
This code only deals with M.2 connector in specific, so I'm not sure why we need
to worry about *other* kind of devices. Let's worry about them when they show up
(with graph interface ofc).
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 14:17 ` Manivannan Sadhasivam
@ 2026-07-02 14:34 ` Dmitry Baryshkov
2026-07-02 15:08 ` Manivannan Sadhasivam
0 siblings, 1 reply; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-07-02 14:34 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Loic Poulain, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 04:17:43PM +0200, Manivannan Sadhasivam wrote:
> On Thu, Jul 02, 2026 at 03:14:49PM +0300, Dmitry Baryshkov wrote:
> > On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> > > For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> > > is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> > > sequencer rather than a dedicated BT enable GPIO.
> > >
> > > When the serdev controller has an OF graph (indicating it is connected
> > > to an M.2 connector), acquire the 'uart' pwrseq target from the
> > > connector's power sequencer and use it to control BT power instead of
> > > the bt-enable GPIO.
> > >
> > > Also allocate bt_power unconditionally for all SOC types since the
> >
> > Can we just fold it into the main struct?
> >
> > > pwrseq path is independent of the SOC type switch.
> > >
> > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > > ---
> > > drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> > > 1 file changed, 43 insertions(+), 38 deletions(-)
> > >
> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> > > --- a/drivers/bluetooth/hci_qca.c
> > > +++ b/drivers/bluetooth/hci_qca.c
> > > @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> > > /* Controller needs time to bootup. */
> > > msleep(150);
> > > }
> > > +
> > > + if (qcadev->bt_power->pwrseq)
> > > + pwrseq_power_on(qcadev->bt_power->pwrseq);
> > > }
> > >
> > > clear_bit(QCA_BT_OFF, &qca->flags);
> > > @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> > > break;
> > > }
> > >
> > > - if (power && power->pwrseq) {
> > > + if (power->pwrseq) {
> > > pwrseq_power_off(power->pwrseq);
> > > set_bit(QCA_BT_OFF, &qca->flags);
> > > return;
> > > @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> > > return 0;
> > > }
> > >
> > > +/*
> > > + * Acquire the M.2 connector power sequencer.
> > > + *
> > > + * An OF graph link on the serdev controller is only present when the BT
> > > + * device is attached through an M.2 Key E connector. In that case the UART
> > > + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> > > + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> > > + *
> > > + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> > > + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> > > + */
> > > +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> > > +{
> > > + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> > > + struct device *dev;
> > > +
> > > + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> > > + return 0;
> > > +
> > > + 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);
> > > + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
> >
> > I think here you are looking into the exact details of the other of the
> > graph. There might be other devices on that side, while the code now
> > assumes M.2. Or, consider having an M.2 controller which handles
> > W_DISABLE2# internally rather than through the GPIO.
> >
>
> This code only deals with M.2 connector in specific, so I'm not sure why we need
> to worry about *other* kind of devices. Let's worry about them when they show up
> (with graph interface ofc).
I don't think we want to go through the drivers using M.2 connectors in
such a case. In the end, the contract should be that there is a power
sequencer on the other side of the graph, but the specifics of the
connector should be abstracted out. Do you know, if in the x86 world the
W_DISABLE2# is a GPIO or is controleed by the hub.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 14:34 ` Dmitry Baryshkov
@ 2026-07-02 15:08 ` Manivannan Sadhasivam
2026-07-03 8:14 ` Loic Poulain
2026-07-04 0:11 ` Dmitry Baryshkov
0 siblings, 2 replies; 18+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-02 15:08 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Loic Poulain, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 05:34:31PM +0300, Dmitry Baryshkov wrote:
> On Thu, Jul 02, 2026 at 04:17:43PM +0200, Manivannan Sadhasivam wrote:
> > On Thu, Jul 02, 2026 at 03:14:49PM +0300, Dmitry Baryshkov wrote:
> > > On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> > > > For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> > > > is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> > > > sequencer rather than a dedicated BT enable GPIO.
> > > >
> > > > When the serdev controller has an OF graph (indicating it is connected
> > > > to an M.2 connector), acquire the 'uart' pwrseq target from the
> > > > connector's power sequencer and use it to control BT power instead of
> > > > the bt-enable GPIO.
> > > >
> > > > Also allocate bt_power unconditionally for all SOC types since the
> > >
> > > Can we just fold it into the main struct?
> > >
> > > > pwrseq path is independent of the SOC type switch.
> > > >
> > > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > > > ---
> > > > drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> > > > 1 file changed, 43 insertions(+), 38 deletions(-)
> > > >
> > > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > > index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> > > > --- a/drivers/bluetooth/hci_qca.c
> > > > +++ b/drivers/bluetooth/hci_qca.c
> > > > @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> > > > /* Controller needs time to bootup. */
> > > > msleep(150);
> > > > }
> > > > +
> > > > + if (qcadev->bt_power->pwrseq)
> > > > + pwrseq_power_on(qcadev->bt_power->pwrseq);
> > > > }
> > > >
> > > > clear_bit(QCA_BT_OFF, &qca->flags);
> > > > @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> > > > break;
> > > > }
> > > >
> > > > - if (power && power->pwrseq) {
> > > > + if (power->pwrseq) {
> > > > pwrseq_power_off(power->pwrseq);
> > > > set_bit(QCA_BT_OFF, &qca->flags);
> > > > return;
> > > > @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> > > > return 0;
> > > > }
> > > >
> > > > +/*
> > > > + * Acquire the M.2 connector power sequencer.
> > > > + *
> > > > + * An OF graph link on the serdev controller is only present when the BT
> > > > + * device is attached through an M.2 Key E connector. In that case the UART
> > > > + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> > > > + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> > > > + *
> > > > + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> > > > + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> > > > + */
> > > > +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> > > > +{
> > > > + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> > > > + struct device *dev;
> > > > +
> > > > + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> > > > + return 0;
> > > > +
> > > > + 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);
> > > > + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
> > >
> > > I think here you are looking into the exact details of the other of the
> > > graph. There might be other devices on that side, while the code now
> > > assumes M.2. Or, consider having an M.2 controller which handles
> > > W_DISABLE2# internally rather than through the GPIO.
> > >
> >
> > This code only deals with M.2 connector in specific, so I'm not sure why we need
> > to worry about *other* kind of devices. Let's worry about them when they show up
> > (with graph interface ofc).
>
> I don't think we want to go through the drivers using M.2 connectors in
> such a case. In the end, the contract should be that there is a power
> sequencer on the other side of the graph, but the specifics of the
> connector should be abstracted out. Do you know, if in the x86 world the
> W_DISABLE2# is a GPIO or is controleed by the hub.
>
I tried to abstract out, but Bartosz didn't want pwrctrl APIs to do that level
of abstraction as pwrctrl APIs should be generic and should not be bind to a
specific connector and exposing its internals.
That's why we ended up having pwrctrl core exposing the 'struct dev' using
pwrseq_to_device() and letting the consumer extracting whatever information it
needs.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 15:08 ` Manivannan Sadhasivam
@ 2026-07-03 8:14 ` Loic Poulain
2026-07-04 0:11 ` Dmitry Baryshkov
1 sibling, 0 replies; 18+ messages in thread
From: Loic Poulain @ 2026-07-03 8:14 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Dmitry Baryshkov, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 2, 2026 at 5:09 PM Manivannan Sadhasivam <mani@kernel.org> wrote:
>
> On Thu, Jul 02, 2026 at 05:34:31PM +0300, Dmitry Baryshkov wrote:
> > On Thu, Jul 02, 2026 at 04:17:43PM +0200, Manivannan Sadhasivam wrote:
> > > On Thu, Jul 02, 2026 at 03:14:49PM +0300, Dmitry Baryshkov wrote:
> > > > On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> > > > > For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> > > > > is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> > > > > sequencer rather than a dedicated BT enable GPIO.
> > > > >
> > > > > When the serdev controller has an OF graph (indicating it is connected
> > > > > to an M.2 connector), acquire the 'uart' pwrseq target from the
> > > > > connector's power sequencer and use it to control BT power instead of
> > > > > the bt-enable GPIO.
> > > > >
> > > > > Also allocate bt_power unconditionally for all SOC types since the
> > > >
> > > > Can we just fold it into the main struct?
Yes.
> > > >
> > > > > pwrseq path is independent of the SOC type switch.
> > > > >
> > > > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > > > > ---
> > > > > drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> > > > > 1 file changed, 43 insertions(+), 38 deletions(-)
> > > > >
> > > > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > > > index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> > > > > --- a/drivers/bluetooth/hci_qca.c
> > > > > +++ b/drivers/bluetooth/hci_qca.c
> > > > > @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> > > > > /* Controller needs time to bootup. */
> > > > > msleep(150);
> > > > > }
> > > > > +
> > > > > + if (qcadev->bt_power->pwrseq)
> > > > > + pwrseq_power_on(qcadev->bt_power->pwrseq);
> > > > > }
> > > > >
> > > > > clear_bit(QCA_BT_OFF, &qca->flags);
> > > > > @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> > > > > break;
> > > > > }
> > > > >
> > > > > - if (power && power->pwrseq) {
> > > > > + if (power->pwrseq) {
> > > > > pwrseq_power_off(power->pwrseq);
> > > > > set_bit(QCA_BT_OFF, &qca->flags);
> > > > > return;
> > > > > @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> > > > > return 0;
> > > > > }
> > > > >
> > > > > +/*
> > > > > + * Acquire the M.2 connector power sequencer.
> > > > > + *
> > > > > + * An OF graph link on the serdev controller is only present when the BT
> > > > > + * device is attached through an M.2 Key E connector. In that case the UART
> > > > > + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> > > > > + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> > > > > + *
> > > > > + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> > > > > + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> > > > > + */
> > > > > +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> > > > > +{
> > > > > + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> > > > > + struct device *dev;
> > > > > +
> > > > > + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> > > > > + return 0;
> > > > > +
> > > > > + 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);
> > > > > + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
> > > >
> > > > I think here you are looking into the exact details of the other of the
> > > > graph. There might be other devices on that side, while the code now
> > > > assumes M.2. Or, consider having an M.2 controller which handles
> > > > W_DISABLE2# internally rather than through the GPIO.
> > > >
> > >
> > > This code only deals with M.2 connector in specific, so I'm not sure why we need
> > > to worry about *other* kind of devices. Let's worry about them when they show up
> > > (with graph interface ofc).
> >
> > I don't think we want to go through the drivers using M.2 connectors in
> > such a case. In the end, the contract should be that there is a power
> > sequencer on the other side of the graph, but the specifics of the
> > connector should be abstracted out. Do you know, if in the x86 world the
> > W_DISABLE2# is a GPIO or is controleed by the hub.
> >
>
> I tried to abstract out, but Bartosz didn't want pwrctrl APIs to do that level
> of abstraction as pwrctrl APIs should be generic and should not be bind to a
> specific connector and exposing its internals.
>
> That's why we ended up having pwrctrl core exposing the 'struct dev' using
> pwrseq_to_device() and letting the consumer extracting whatever information it
> needs.
Well, I'm not a fan of this solution either. I think we could imagine
a generic pwrseq_target_provides_enable() helper to query whether a
specific target (here uart/BT) is autonomously controllable, instead
of peeking at w-disable2-gpios. But that's significant work I'd rather
discuss and address in a separate series: it needs a new capability in
the pwrseq framework and changes in the pcie-m2 provider, since today
the uart enable callback is registered whether or not the GPIO is
present.
Regards,
Loic
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 15:08 ` Manivannan Sadhasivam
2026-07-03 8:14 ` Loic Poulain
@ 2026-07-04 0:11 ` Dmitry Baryshkov
1 sibling, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-07-04 0:11 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Loic Poulain, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 05:08:56PM +0200, Manivannan Sadhasivam wrote:
> On Thu, Jul 02, 2026 at 05:34:31PM +0300, Dmitry Baryshkov wrote:
> > On Thu, Jul 02, 2026 at 04:17:43PM +0200, Manivannan Sadhasivam wrote:
> > > On Thu, Jul 02, 2026 at 03:14:49PM +0300, Dmitry Baryshkov wrote:
> > > > On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> > > > > For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> > > > > is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> > > > > sequencer rather than a dedicated BT enable GPIO.
> > > > >
> > > > > When the serdev controller has an OF graph (indicating it is connected
> > > > > to an M.2 connector), acquire the 'uart' pwrseq target from the
> > > > > connector's power sequencer and use it to control BT power instead of
> > > > > the bt-enable GPIO.
> > > > >
> > > > > Also allocate bt_power unconditionally for all SOC types since the
> > > >
> > > > Can we just fold it into the main struct?
> > > >
> > > > > pwrseq path is independent of the SOC type switch.
> > > > >
> > > > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > > > > ---
> > > > > drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> > > > > 1 file changed, 43 insertions(+), 38 deletions(-)
> > > > > @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> > > > > return 0;
> > > > > }
> > > > >
> > > > > +/*
> > > > > + * Acquire the M.2 connector power sequencer.
> > > > > + *
> > > > > + * An OF graph link on the serdev controller is only present when the BT
> > > > > + * device is attached through an M.2 Key E connector. In that case the UART
> > > > > + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> > > > > + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> > > > > + *
> > > > > + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> > > > > + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> > > > > + */
> > > > > +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> > > > > +{
> > > > > + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> > > > > + struct device *dev;
> > > > > +
> > > > > + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> > > > > + return 0;
> > > > > +
> > > > > + 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);
> > > > > + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
> > > >
> > > > I think here you are looking into the exact details of the other of the
> > > > graph. There might be other devices on that side, while the code now
> > > > assumes M.2. Or, consider having an M.2 controller which handles
> > > > W_DISABLE2# internally rather than through the GPIO.
> > > >
> > >
> > > This code only deals with M.2 connector in specific, so I'm not sure why we need
> > > to worry about *other* kind of devices. Let's worry about them when they show up
> > > (with graph interface ofc).
> >
> > I don't think we want to go through the drivers using M.2 connectors in
> > such a case. In the end, the contract should be that there is a power
> > sequencer on the other side of the graph, but the specifics of the
> > connector should be abstracted out. Do you know, if in the x86 world the
> > W_DISABLE2# is a GPIO or is controleed by the hub.
> >
>
> I tried to abstract out, but Bartosz didn't want pwrctrl APIs to do that level
> of abstraction as pwrctrl APIs should be generic and should not be bind to a
> specific connector and exposing its internals.
>
> That's why we ended up having pwrctrl core exposing the 'struct dev' using
> pwrseq_to_device() and letting the consumer extracting whatever information it
> needs.
Do we have other ways to control M.2? For example on the x86 systems,
are those signals controlled via GPIOs (or GPIO-like registers) or are
they controlled separately by something like M.2 controller? Or do you
have an idea about other non-x86 systems?
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
2026-07-02 10:46 ` [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq Loic Poulain
2026-07-02 12:14 ` Dmitry Baryshkov
@ 2026-07-02 14:20 ` Manivannan Sadhasivam
1 sibling, 0 replies; 18+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-02 14:20 UTC (permalink / raw)
To: Loic Poulain
Cc: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, linux-pci, linux-pm, linux-kernel, linux-arm-msm,
linux-bluetooth, devicetree, Manivannan Sadhasivam
On Thu, Jul 02, 2026 at 12:46:15PM +0200, Loic Poulain wrote:
> For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable
> is controlled by the W_DISABLE2# signal managed by the pcie-m2 power
> sequencer rather than a dedicated BT enable GPIO.
>
> When the serdev controller has an OF graph (indicating it is connected
> to an M.2 connector), acquire the 'uart' pwrseq target from the
> connector's power sequencer and use it to control BT power instead of
> the bt-enable GPIO.
>
> Also allocate bt_power unconditionally for all SOC types since the
> pwrseq path is independent of the SOC type switch.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
- Mani
> ---
> drivers/bluetooth/hci_qca.c | 81 ++++++++++++++++++++++++---------------------
> 1 file changed, 43 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index e09debdb00a1b8e74ccd5de6147e240e533b4594..b04593a96e14ac9e87ae76fa00eda308e81dea25 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> /* Controller needs time to bootup. */
> msleep(150);
> }
> +
> + if (qcadev->bt_power->pwrseq)
> + pwrseq_power_on(qcadev->bt_power->pwrseq);
> }
>
> clear_bit(QCA_BT_OFF, &qca->flags);
> @@ -2256,7 +2259,7 @@ static void qca_power_off(struct hci_uart *hu)
> break;
> }
>
> - if (power && power->pwrseq) {
> + if (power->pwrseq) {
> pwrseq_power_off(power->pwrseq);
> set_bit(QCA_BT_OFF, &qca->flags);
> return;
> @@ -2387,6 +2390,35 @@ static int qca_init_regulators(struct qca_power *qca,
> return 0;
> }
>
> +/*
> + * Acquire the M.2 connector power sequencer.
> + *
> + * An OF graph link on the serdev controller is only present when the BT
> + * device is attached through an M.2 Key E connector. In that case the UART
> + * enable (W_DISABLE2#) is driven by the pcie-m2 power sequencer instead of a
> + * dedicated BT enable GPIO, so grab the "uart" pwrseq target from it.
> + *
> + * Returns 0 if no M.2 connector is present (nothing to do), a negative errno
> + * on error, otherwise 0 with qcadev->bt_power->pwrseq populated.
> + */
> +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev, bool *bt_en_available)
> +{
> + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> + struct device *dev;
> +
> + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> + return 0;
> +
> + 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);
> + *bt_en_available = device_property_present(dev, "w-disable2-gpios");
> +
> + return 0;
> +}
> +
> static int qca_serdev_probe(struct serdev_device *serdev)
> {
> struct qca_serdev *qcadev;
> @@ -2417,25 +2449,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> else
> qcadev->btsoc_type = QCA_ROME;
>
> - switch (qcadev->btsoc_type) {
> - case QCA_QCA6390:
> - case QCA_WCN3950:
> - case QCA_WCN3988:
> - case QCA_WCN3990:
> - case QCA_WCN3991:
> - case QCA_WCN3998:
> - case QCA_WCN6750:
> - case QCA_WCN6855:
> - case QCA_WCN7850:
> - qcadev->bt_power = devm_kzalloc(&serdev->dev,
> - sizeof(struct qca_power),
> - GFP_KERNEL);
> - if (!qcadev->bt_power)
> - return -ENOMEM;
> - break;
> - default:
> - break;
> - }
> + qcadev->bt_power = devm_kzalloc(&serdev->dev, sizeof(struct qca_power), GFP_KERNEL);
> + if (!qcadev->bt_power)
> + return -ENOMEM;
> +
> + err = qca_serdev_get_m2_pwrseq(qcadev, &bt_en_available);
> + if (err)
> + return err;
>
> switch (qcadev->btsoc_type) {
> case QCA_WCN3950:
> @@ -2446,24 +2466,9 @@ 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))) {
> - 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;
> -
> + /* M.2 connector modules are powered by the pwrseq acquired above. */
> + if (qcadev->bt_power->pwrseq)
> break;
> - }
>
> if (!device_property_present(&serdev->dev, "enable-gpios")) {
> /*
> @@ -2545,7 +2550,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> return PTR_ERR(qcadev->bt_en);
> }
>
> - if (!qcadev->bt_en)
> + if (!qcadev->bt_en && !qcadev->bt_power->pwrseq)
> bt_en_available = false;
>
> qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
>
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 4/4] arm64: dts: qcom: monaco-arduino-monza: Add QCA2066 M.2 WiFi/BT support
2026-07-02 10:46 [PATCH v2 0/4] arm64: dts: monaco-arduino-monza: Add support for LGA WiFi/BT module Loic Poulain
` (2 preceding siblings ...)
2026-07-02 10:46 ` [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq Loic Poulain
@ 2026-07-02 10:46 ` Loic Poulain
2026-07-02 12:15 ` Dmitry Baryshkov
3 siblings, 1 reply; 18+ messages in thread
From: Loic Poulain @ 2026-07-02 10:46 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Loic Poulain, Konrad Dybcio
Add support for the QCA2066 (QCNFA765) WiFi/Bluetooth module on the
Arduino VENTUNO Q board. The module is interfaced via LGA and is
compatible with the M.2 Key E.
Add wireless-lga-connector node using pcie-m2-e-connector binding,
connecting PCIe port 0 to the WiFi interface and UART10 port 3 to
the Bluetooth interface.
Add pcie@1,0 downstream port node with pciclass,0604 compatible so
the pci-pwrctrl driver can acquire the power sequencer and enable
the M.2 slot before PCIe enumeration.
Add nfa725b_default_state pinctrl for the W_DISABLE1/2 GPIOs
(gpio56/gpio55) used by the power sequencer.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts | 64 +++++++++++++++++++++--
1 file changed, 60 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts b/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
index f67a554adf956696aeac2348e478dbd0b74f0e62..e3d3d68932efff494f3c7ab96d75869be24c4a94 100644
--- a/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
+++ b/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
@@ -155,6 +155,40 @@ vreg_nvme: regulator-3p3-m2 {
enable-active-high;
startup-delay-us = <20000>;
};
+
+ wireless-lga-connector {
+ compatible = "qcom,pcie-m2-1418-lga-connector",
+ "pcie-m2-e-connector";
+ vpcie3v3-supply = <&vdc_3v3>;
+ vpcie1v8-supply = <&vdc_1v8>;
+ w-disable1-gpios = <&tlmm 56 GPIO_ACTIVE_LOW>;
+ w-disable2-gpios = <&tlmm 55 GPIO_ACTIVE_LOW>;
+ pinctrl-0 = <&nfa725b_default_state>;
+ pinctrl-names = "default";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* WiFi/PCIe */
+ port@0 {
+ reg = <0>;
+
+ lga_pcie_ep: endpoint {
+ remote-endpoint = <&pcie_bridge_ep>;
+ };
+ };
+
+ /* Bluetooth/UART */
+ port@3 {
+ reg = <3>;
+
+ lga_uart_ep: endpoint {
+ remote-endpoint = <&uart10_ep>;
+ };
+ };
+ };
+ };
};
&cci1 {
@@ -409,6 +443,22 @@ pci@0,0 {
ranges;
reg = <0x010000 0x00 0x00 0x00 0x00>;
+ pcie@1,0 {
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ compatible = "pciclass,0604";
+ bus-range = <0x00 0xff>;
+ ranges;
+ reg = <0x020800 0x00 0x00 0x00 0x00>;
+
+ port {
+ pcie_bridge_ep: endpoint {
+ remote-endpoint = <&lga_pcie_ep>;
+ };
+ };
+ };
+
pci@2,0 {
#address-cells = <3>;
#size-cells = <2>;
@@ -501,6 +551,12 @@ max98091_default: max98091-default-state {
bias-pull-up;
};
+ nfa725b_default_state: nfa725b-default-state {
+ pins = "gpio55", "gpio56";
+ function = "gpio";
+ bias-disable;
+ };
+
pcie1_default_state: pcie1-default-state {
wake-pins {
pins = "gpio21";
@@ -544,10 +600,10 @@ &uart7 {
&uart10 {
status = "okay";
- bluetooth: bluetooth {
- compatible = "qcom,qca2066-bt";
- enable-gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>;
- clocks = <&sleep_clk>;
+ port {
+ uart10_ep: endpoint {
+ remote-endpoint = <&lga_uart_ep>;
+ };
};
};
--
2.34.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 4/4] arm64: dts: qcom: monaco-arduino-monza: Add QCA2066 M.2 WiFi/BT support
2026-07-02 10:46 ` [PATCH v2 4/4] arm64: dts: qcom: monaco-arduino-monza: Add QCA2066 M.2 WiFi/BT support Loic Poulain
@ 2026-07-02 12:15 ` Dmitry Baryshkov
0 siblings, 0 replies; 18+ messages in thread
From: Dmitry Baryshkov @ 2026-07-02 12:15 UTC (permalink / raw)
To: Loic Poulain
Cc: Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-pci,
linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Konrad Dybcio
On Thu, Jul 02, 2026 at 12:46:16PM +0200, Loic Poulain wrote:
> Add support for the QCA2066 (QCNFA765) WiFi/Bluetooth module on the
> Arduino VENTUNO Q board. The module is interfaced via LGA and is
> compatible with the M.2 Key E.
>
> Add wireless-lga-connector node using pcie-m2-e-connector binding,
> connecting PCIe port 0 to the WiFi interface and UART10 port 3 to
> the Bluetooth interface.
>
> Add pcie@1,0 downstream port node with pciclass,0604 compatible so
> the pci-pwrctrl driver can acquire the power sequencer and enable
> the M.2 slot before PCIe enumeration.
>
> Add nfa725b_default_state pinctrl for the W_DISABLE1/2 GPIOs
> (gpio56/gpio55) used by the power sequencer.
>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts | 64 +++++++++++++++++++++--
> 1 file changed, 60 insertions(+), 4 deletions(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 18+ messages in thread