Re: [PATCH 2/4] Bluetooth: qca: add QCC2072 support

From: Bartosz Golaszewski

Date: Mon Jun 01 2026 - 04:28:41 EST


On Fri, 29 May 2026 19:58:22 +0200, Yepuri Siddu
<yepuri.siddu@xxxxxxxxxxxxxxxx> said:
> QCC2072 is a BT/WiFi combo SoC that uses different firmware
> filenames and requires no external voltage regulators, so add
> it as a new SoC type.
>
> The chip supports the wideband speech and valid LE states
> capabilities. Its firmware is named using the "orn" prefix and
> follows the standard rom-version-based scheme:
> - qca/ornbtfw<ver>.tlv
> - qca/ornnv<ver>.bin
>
> These firmware files are already present in the linux-firmware
> repository.
>
> Signed-off-by: Yepuri Siddu <yepuri.siddu@xxxxxxxxxxxxxxxx>
> ---
> drivers/bluetooth/btqca.c | 9 +++++++++
> drivers/bluetooth/btqca.h | 1 +
> drivers/bluetooth/hci_qca.c | 24 ++++++++++++++++++++++++
> 3 files changed, 34 insertions(+)
>
> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
> index dda76365726f..0ef7546e7c7a 100644
> --- a/drivers/bluetooth/btqca.c
> +++ b/drivers/bluetooth/btqca.c
> @@ -843,6 +843,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> snprintf(config.fwname, sizeof(config.fwname),
> "qca/hmtbtfw%02x.tlv", rom_ver);
> break;
> + case QCA_QCC2072:
> + snprintf(config.fwname, sizeof(config.fwname),
> + "qca/ornbtfw%02x.tlv", rom_ver);
> + break;
> default:
> snprintf(config.fwname, sizeof(config.fwname),
> "qca/rampatch_%08x.bin", soc_ver);
> @@ -937,6 +941,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
> "hmtnv", soc_type, ver, rom_ver, boardid);
> break;
> + case QCA_QCC2072:
> + snprintf(config.fwname, sizeof(config.fwname),
> + "qca/ornnv%02x.bin", rom_ver);
> + break;
> default:
> snprintf(config.fwname, sizeof(config.fwname),
> "qca/nvm_%08x.bin", soc_ver);
> @@ -999,6 +1007,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> /* get fw build info */
> err = qca_read_fw_build_info(hdev);
> if (err < 0)
> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> index 8f3c1b1c77b3..a175ac31e7b2 100644
> --- a/drivers/bluetooth/btqca.h
> +++ b/drivers/bluetooth/btqca.h
> @@ -158,6 +158,7 @@ enum qca_btsoc_type {
> QCA_WCN6750,
> QCA_WCN6855,
> QCA_WCN7850,
> + QCA_QCC2072,
> };
>
> #if IS_ENABLED(CONFIG_BT_QCA)
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index ed280399bf47..fc67ba0e4984 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1372,6 +1372,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
>
> /* Give the controller time to process the request */
> switch (qca_soc_type(hu)) {
> + case QCA_QCC2072:
> case QCA_WCN3950:
> case QCA_WCN3988:
> case QCA_WCN3990:
> @@ -1459,6 +1460,7 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
> static int qca_check_speeds(struct hci_uart *hu)
> {
> switch (qca_soc_type(hu)) {
> + case QCA_QCC2072:
> case QCA_WCN3950:
> case QCA_WCN3988:
> case QCA_WCN3990:
> @@ -1510,6 +1512,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> hci_uart_set_flow_control(hu, true);
> break;
>
> @@ -1545,6 +1548,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> hci_uart_set_flow_control(hu, false);
> break;
>
> @@ -1861,6 +1865,7 @@ static int qca_power_on(struct hci_dev *hdev)
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> ret = qca_regulator_init(hu);
> break;
>
> @@ -1957,6 +1962,10 @@ static int qca_setup(struct hci_uart *hu)
> soc_name = "wcn7850";
> break;
>
> + case QCA_QCC2072:
> + soc_name = "qcc2072";
> + break;
> +
> default:
> soc_name = "ROME/QCA6390";
> }
> @@ -1980,6 +1989,7 @@ static int qca_setup(struct hci_uart *hu)
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> if (qcadev->bdaddr_property_broken)
> hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN);
>
> @@ -2013,6 +2023,7 @@ static int qca_setup(struct hci_uart *hu)
> case QCA_WCN6750:
> case QCA_WCN6855:
> case QCA_WCN7850:
> + case QCA_QCC2072:
> break;
>
> default:
> @@ -2166,6 +2177,12 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
> .num_vregs = 4,
> };
>
> +static const struct qca_device_data qca_soc_data_qcc2072 __maybe_unused = {
> + .soc_type = QCA_QCC2072,
> + .num_vregs = 0,
> + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
> +};
> +
> static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
> .soc_type = QCA_WCN6750,
> .vregs = (struct qca_vreg []) {
> @@ -2268,6 +2285,7 @@ static void qca_power_off(struct hci_uart *hu)
>
> case QCA_WCN6750:
> case QCA_WCN6855:
> + case QCA_QCC2072:
> gpiod_set_value_cansleep(qcadev->bt_en, 0);
> msleep(100);
> qca_regulator_disable(qcadev);
> @@ -2414,6 +2432,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> qcadev->btsoc_type = QCA_ROME;
>
> switch (qcadev->btsoc_type) {
> + case QCA_QCC2072:
> case QCA_QCA6390:
> case QCA_WCN3950:
> case QCA_WCN3988:
> @@ -2434,6 +2453,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> }
>
> switch (qcadev->btsoc_type) {
> + case QCA_QCC2072:
> case QCA_WCN3950:
> case QCA_WCN3988:
> case QCA_WCN3990:
> @@ -2484,6 +2504,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> if (!qcadev->bt_en &&
> (data->soc_type == QCA_WCN6750 ||
> data->soc_type == QCA_WCN6855 ||
> + data->soc_type == QCA_QCC2072 ||

Looking at the bindings: this chip cannot have an enable GPIO, so it probably
should have its own if branch that unconditionally sets power_ctrl_enabled to
false?

> data->soc_type == QCA_WCN7850))
> power_ctrl_enabled = false;
>
> @@ -2492,6 +2513,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> if (IS_ERR(qcadev->sw_ctrl) &&
> (data->soc_type == QCA_WCN6750 ||
> data->soc_type == QCA_WCN6855 ||
> + data->soc_type == QCA_QCC2072 ||

Same here.

Bart

> data->soc_type == QCA_WCN7850)) {
> dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
> return PTR_ERR(qcadev->sw_ctrl);
> @@ -2570,6 +2592,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
> struct qca_power *power = qcadev->bt_power;
>
> switch (qcadev->btsoc_type) {
> + case QCA_QCC2072:
> case QCA_WCN3988:
> case QCA_WCN3990:
> case QCA_WCN3991:
> @@ -2779,6 +2802,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
> { .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
> { .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
> { .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
> + { .compatible = "qcom,qcc2072-bt", .data = &qca_soc_data_qcc2072},
> { /* sentinel */ }
> };
> MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
> --
> 2.34.1
>
>