[RFC PATCH 0/4] Bluetooth: hci_intel: support the CcP controller (X1 Fold Gen1)

From: Cai Yu

Date: Fri Sep 25 2026 - 19:41:00 EST


This series makes hci_intel work with the Intel CcP controller as it is wired
on the ThinkPad X1 Fold Gen1 (Lakefield, ACPI INT33E4). That controller is
described as a serdev child of an LPSS UART, so the line discipline path of
the driver can never be used for it and nothing binds to it with the current
kernel.

1/4 fix four unconditional hu->tty dereferences in the LPM paths and in
the baudrate helper, so the driver survives a tty-less controller.
Independent of the rest, and a crash on any serdev-attached
controller.
2/4 accept the CcP hardware variant (0x14). btintel.c already knows it
(btintel_get_fw_name()), but hci_intel.c duplicates that lookup and
rejects the controller before the firmware is requested.
3/4 add the serdev driver: ACPI INT33E4 match, reset GPIO power cycle,
boot delay and flow control handling.
4/4 download the firmware at 921.6 kbaud instead of the operating speed.

On the X1 Fold Gen1 (20RKA000CD) the controller comes up as hci0, the Intel
firmware is downloaded on every boot, and both the HOG keyboard and audio
over Bluetooth work; without these changes the controller is not bound at all
and no hci0 device exists. The reset pulse, boot delay and download speed
used here are the values measured on that machine.

The version posted here is the same change reorganized for mainline (a second
hci_uart_proto instead of module parameters, with those values hardcoded). It
applies to and builds against master with no new warnings; I have not booted
this exact revision.

RFC note: 1/4 and 2/4 are plain fixes and I believe them to be correct on
their own. 3/4 adds a second hci_uart_proto and 4/4 hardcodes a download speed
for one bootloader revision; the series is marked RFC mainly to get feedback on
the shape of those two. I am happy to rework 3/4 into a per-device flag in
hci_serdev.c or to drop 4/4 entirely, and 1/4 and 2/4 can be applied without the
rest.

Points I am not sure about and would appreciate feedback on:

- 3/4 uses a second struct hci_uart_proto with oper_speed = 0 for the serdev
path. The generic baudrate change in hci_serdev.c runs before ->setup(),
i.e. while the controller is still in bootloader mode. It only answers at
init_speed at that point (and right after the reset pulse it does not
answer at all yet), so switching the host to oper_speed makes the setup
fail with a -110 timeout on the version read. A per-device "no early set
baudrate" flag in hci_serdev.c (hci_bcm.c has that concept as
no_early_set_baudrate) would work as well - I am happy to rework it that
way if that is preferred.

- 4/4 is a rate quirk of one bootloader: it stops acknowledging firmware
fragments above 1 Mbaud (measurements in the commit message). If a quirk
table, a max-speed device property or a DMI match is preferred over
hardcoding 921.6 kbaud for CcP, I can respin that patch.

- I could not find a way for the platform driver and the serdev driver to
share one probe: the platform device is an ACPI device for which the
driver looks up the reset GPIO and the LPM/wakeup resources, while a
serdev controller owns its reset GPIO itself. hci_bcm supports both kinds
with two probes as well.

Cai Yu (4):
Bluetooth: hci_intel: fix tty-only assumptions in the LPM paths
Bluetooth: hci_intel: add the CcP controller (hardware variant 0x14)
Bluetooth: hci_intel: add serdev support for the CcP controller
Bluetooth: hci_intel: download the CcP firmware at 921.6 kbaud

drivers/bluetooth/hci_intel.c | 184 ++++++++++++++++++++++++++++++++--
1 file changed, 177 insertions(+), 7 deletions(-)