Re: [PATCH 2/3] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
From: Loic Poulain
Date: Fri May 22 2026 - 12:26:18 EST
On Wed, May 20, 2026 at 2:33 PM Dmitry Baryshkov
<dmitry.baryshkov@xxxxxxxxxxxxxxxx> wrote:
>
> On Wed, May 20, 2026 at 01:01:43PM +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@xxxxxxxxxxxxxxxx>
> > ---
> > drivers/bluetooth/hci_qca.c | 33 +++++++++++++--------------------
> > 1 file changed, 13 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > index b5439b9956cfb0497e6ba6ccd9ed61224d23a9dd..de5cba7b7f44e280a48dad5d670fa2758d3268d0 100644
> > --- a/drivers/bluetooth/hci_qca.c
> > +++ b/drivers/bluetooth/hci_qca.c
> > @@ -1873,6 +1873,9 @@ static int qca_power_on(struct hci_dev *hdev)
> > /* Controller needs time to bootup. */
> > msleep(150);
> > }
> > +
> > + if (qcadev->bt_power && qcadev->bt_power->pwrseq)
> > + pwrseq_power_on(qcadev->bt_power->pwrseq);
> > }
> >
> > clear_bit(QCA_BT_OFF, &qca->flags);
> > @@ -2415,25 +2418,9 @@ 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;
>
> This builds bt_power for all devices even though it wasn't the case
> beforehand. As such, you can drop all further `if (qcadev->bt_power)`
> checks in the driver. But, you also need to check that this won't break
> support for other (older) chips.
Ok, I will do, and double check.
>
> >
> > switch (qcadev->btsoc_type) {
> > case QCA_WCN3950:
> > @@ -2543,7 +2530,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> > return PTR_ERR(qcadev->bt_en);
> > }
> >
> > - if (!qcadev->bt_en)
> > + if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
>
> And this breaks support for pwrseq for non-M.2 BT devices. There is no
> OF graph in such a case.
Not sure why, here we handle OF graph as an optional pwrseq provider,
but still support legacy enablement.
>
> > + 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);
> > + }
> > +
> > + if (!qcadev->bt_en && !qcadev->bt_power->pwrseq)
> > bt_en_available = false;
> >
> > qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
> >
> > --
> > 2.34.1
> >
>
> --
> With best wishes
> Dmitry