Re: [PATCH v2 3/4] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq

From: Manivannan Sadhasivam

Date: Thu Jul 02 2026 - 10:25:39 EST


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@xxxxxxxxxxxxxxxx>
> > ---
> > 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

--
மணிவண்ணன் சதாசிவம்