Files
Zijun Hu 3669487308 Bluetooth: btusb: Add support for Qualcomm multi-subsystem QCC2072
QCC2072 has a Peripheral (PERI) subsystem to support the BT function
unit, the transport wire is owned by PERI and carries both BT-HCI and
PERI-HCI frames, as shown below:

                 _______________________________
       USB I/F	|	   internal link	|
BTHOST --------	|---- PERI -------------- BT	|
		|_______________________________|
                (other on-chip subsystems omitted)

PERI has its own command/event/ACL traffic, memdump, and firmware
(PATCH and NVM), all different from BT's own, and BTHOST needs to
interact with PERI directly.

To support multi-subsystem controllers, add btusb_qcom.c/.h as a new
transport-specific design:

- Multi-subsystem memdump collection.
- Generic PERI event handling, and sending a PERI frame then
  syncing an event sequence.
- Downloading PERI firmware (rampatch and NVM).
- Recovery on command timeout or hardware error event.

BTW, it also supports BT-only chips.

/sys/kernel/debug/usb/devices:
T:  Bus=03 Lev=02 Prnt=02 Port=02 Cnt=01 Dev#=  5 Spd=12   MxCh= 0
D:  Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0cf3 ProdID=ea00 Rev= 0.01
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  64 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:  If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  63 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  63 Ivl=1ms
I:  If#= 1 Alt= 7 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  65 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  65 Ivl=1ms

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
2026-10-14 14:38:15 -04:00

100 lines
2.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Qualcomm Bluetooth USB transport-specific support
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __BTUSB_QCOM_H
#define __BTUSB_QCOM_H
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <net/bluetooth/hci_core.h>
#define QPERI_COMMAND_PKT 0x31
#define QPERI_ACLDATA_PKT 0x32
#define QPERI_EVENT_PKT 0x34
struct btusb_qcom {
__u16 idVendor;
__u16 idProduct;
struct usb_device *udev;
struct usb_interface *intf;
struct gpio_desc *reset_gpio;
/* serializes sending BT and vendor frames to the transport */
struct mutex tx_mutex;
void (*prepare_reset)(struct hci_dev *hdev);
int (*recv_bt_frame)(struct hci_dev *hdev, struct sk_buff *skb);
int (*send_bt_frame)(struct hci_dev *hdev, struct sk_buff *skb);
int (*send_vendor_frame)(struct hci_dev *hdev, struct sk_buff *skb);
};
#if IS_ENABLED(CONFIG_BT_HCIBTUSB_QCOM)
int btusb_qcom_hdev_priv_size(void);
struct btusb_qcom *btusb_qcom_xport_data(struct hci_dev *hdev);
int btusb_qcom_setup(struct hci_dev *hdev);
int btusb_qcom_disconnect(struct hci_dev *hdev);
int btusb_qcom_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
struct sk_buff *btusb_qcom_recv_intr(struct hci_dev *hdev, struct sk_buff *skb,
void *buffer, int count, int *err);
struct sk_buff *btusb_qcom_recv_bulk(struct hci_dev *hdev, struct sk_buff *skb,
void *buffer, int count, int *err);
#else
static inline int btusb_qcom_hdev_priv_size(void)
{
return 0;
}
static inline struct btusb_qcom *btusb_qcom_xport_data(struct hci_dev *hdev)
{
return NULL;
}
static inline int btusb_qcom_setup(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btusb_qcom_disconnect(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btusb_qcom_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
return -EOPNOTSUPP;
}
static inline struct sk_buff *btusb_qcom_recv_intr(struct hci_dev *hdev,
struct sk_buff *skb,
void *buffer, int count,
int *err)
{
*err = -EOPNOTSUPP;
return NULL;
}
static inline struct sk_buff *btusb_qcom_recv_bulk(struct hci_dev *hdev,
struct sk_buff *skb,
void *buffer, int count,
int *err)
{
*err = -EOPNOTSUPP;
return NULL;
}
#endif
#endif