ACK/Cmnt: [SRU][N][PATCH 1/1] Bluetooth: btmtk: move btusb_mtk_[setup, shutdown] to btmtk.c
Stefan Bader
stefan.bader at canonical.com
Thu Sep 3 12:08:32 UTC 2026
On 01/09/2026 03:55, AceLan Kao via kernel-team wrote:
> From: Sean Wang <sean.wang at mediatek.com>
>
> BugLink: https://bugs.launchpad.net/bugs/2165873
>
> Move btusb_mtk_[setup, shutdown] from btusb.c to btmtk.c which holds
> vendor specific stuff and would make btusb.c clean.
>
> Signed-off-by: Sean Wang <sean.wang at mediatek.com>
> Signed-off-by: Chris Lu <chris.lu at mediatek.com>
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz at intel.com>
> (backported from commit 5c5e8c52e3ca7b1e2d1cbf6a0a3ecd3aca9c5d43)
SHA1 not found but seem to match:
5c5e8c52e3cafaa6f71efd44a42a674271e5b3ad
> [acelan: three conflicts in drivers/bluetooth/btusb.c because the tree
> has d019930b0049 ("Bluetooth: btmtk: move btusb_mtk_hci_wmt_sync to
> btmtk.c") but is missing the intermediate commits that added fw_flavor
> handling and BTMTK_FIRMWARE_LOADED. The conflicting hunks are the
> btusb.c copies of btusb_mtk_func_query(), btusb_mtk_uhw_reg_*(),
> btusb_mtk_reg_read(), btusb_mtk_id_get(), btusb_mtk_reset_done(),
> btusb_mtk_subsys_reset() and the open-coded btusb_mtk_setup() body,
> all of which this commit removes, so the upstream side was taken for
> all three. Resulting btusb_mtk_setup() is identical to upstream.]
> Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao at canonical.com>
Acked-by: Stefan Bader <stefan.bader at canonical.com>> ---
This is substantial in size and cannot be reviewed efficiently. The
changes are close to the ubstream commit. Seems to apply at least for me
on top of current tip. Since this fixes a crash regression I ACK.
> drivers/bluetooth/btmtk.c | 454 +++++++++++++++++++++++++++++++++++++-
> drivers/bluetooth/btmtk.h | 23 +-
> drivers/bluetooth/btusb.c | 379 ++-----------------------------
> 3 files changed, 484 insertions(+), 372 deletions(-)
>
> diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
> index ad8753dda826b..f5c8af5845f3e 100644
> --- a/drivers/bluetooth/btmtk.c
> +++ b/drivers/bluetooth/btmtk.c
> @@ -5,6 +5,8 @@
> #include <linux/module.h>
> #include <linux/firmware.h>
> #include <linux/usb.h>
> +#include <linux/iopoll.h>
> +#include <asm/unaligned.h>
>
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> @@ -573,8 +575,8 @@ static int btmtk_usb_submit_wmt_recv_urb(struct hci_dev *hdev)
> return err;
> }
>
> -int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
> - struct btmtk_hci_wmt_params *wmt_params)
> +static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
> + struct btmtk_hci_wmt_params *wmt_params)
> {
> struct btmtk_data *data = hci_get_priv(hdev);
> struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
> @@ -700,7 +702,453 @@ int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
> kfree(wc);
> return err;
> }
> -EXPORT_SYMBOL_GPL(btmtk_usb_hci_wmt_sync);
> +
> +static int btmtk_usb_func_query(struct hci_dev *hdev)
> +{
> + struct btmtk_hci_wmt_params wmt_params;
> + int status, err;
> + u8 param = 0;
> +
> + /* Query whether the function is enabled */
> + wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> + wmt_params.flag = 4;
> + wmt_params.dlen = sizeof(param);
> + wmt_params.data = ¶m;
> + wmt_params.status = &status;
> +
> + err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to query function status (%d)", err);
> + return err;
> + }
> +
> + return status;
> +}
> +
> +static int btmtk_usb_uhw_reg_write(struct hci_dev *hdev, u32 reg, u32 val)
> +{
> + struct btmtk_data *data = hci_get_priv(hdev);
> + int pipe, err;
> + void *buf;
> +
> + buf = kzalloc(4, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + put_unaligned_le32(val, buf);
> +
> + pipe = usb_sndctrlpipe(data->udev, 0);
> + err = usb_control_msg(data->udev, pipe, 0x02,
> + 0x5E,
> + reg >> 16, reg & 0xffff,
> + buf, 4, USB_CTRL_SET_TIMEOUT);
> + if (err < 0)
> + bt_dev_err(hdev, "Failed to write uhw reg(%d)", err);
> +
> + kfree(buf);
> +
> + return err;
> +}
> +
> +static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
> +{
> + struct btmtk_data *data = hci_get_priv(hdev);
> + int pipe, err;
> + void *buf;
> +
> + buf = kzalloc(4, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + pipe = usb_rcvctrlpipe(data->udev, 0);
> + err = usb_control_msg(data->udev, pipe, 0x01,
> + 0xDE,
> + reg >> 16, reg & 0xffff,
> + buf, 4, USB_CTRL_GET_TIMEOUT);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
> + goto err_free_buf;
> + }
> +
> + *val = get_unaligned_le32(buf);
> + bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
> +
> +err_free_buf:
> + kfree(buf);
> +
> + return err;
> +}
> +
> +static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
> +{
> + struct btmtk_data *data = hci_get_priv(hdev);
> + int pipe, err, size = sizeof(u32);
> + void *buf;
> +
> + buf = kzalloc(size, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + pipe = usb_rcvctrlpipe(data->udev, 0);
> + err = usb_control_msg(data->udev, pipe, 0x63,
> + USB_TYPE_VENDOR | USB_DIR_IN,
> + reg >> 16, reg & 0xffff,
> + buf, size, USB_CTRL_GET_TIMEOUT);
> + if (err < 0)
> + goto err_free_buf;
> +
> + *val = get_unaligned_le32(buf);
> +
> +err_free_buf:
> + kfree(buf);
> +
> + return err;
> +}
> +
> +static int btmtk_usb_id_get(struct hci_dev *hdev, u32 reg, u32 *id)
> +{
> + return btmtk_usb_reg_read(hdev, reg, id);
> +}
> +
> +static u32 btmtk_usb_reset_done(struct hci_dev *hdev)
> +{
> + u32 val = 0;
> +
> + btmtk_usb_uhw_reg_read(hdev, MTK_BT_MISC, &val);
> +
> + return val & MTK_BT_RST_DONE;
> +}
> +
> +int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
> +{
> + u32 val;
> + int err;
> +
> + if (dev_id == 0x7922) {
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
> + if (err < 0)
> + return err;
> + val |= 0x00002020;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_EP_RST_OPT, 0x00010001);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
> + if (err < 0)
> + return err;
> + val |= BIT(0);
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
> + if (err < 0)
> + return err;
> + msleep(100);
> + } else if (dev_id == 0x7925) {
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
> + if (err < 0)
> + return err;
> + val |= (1 << 5);
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
> + if (err < 0)
> + return err;
> + val &= 0xFFFF00FF;
> + val |= (1 << 13);
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_EP_RST_OPT, 0x00010001);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
> + if (err < 0)
> + return err;
> + val |= (1 << 0);
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT, 0x000000FF);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
> + if (err < 0)
> + return err;
> + msleep(100);
> + } else {
> + /* It's Device EndPoint Reset Option Register */
> + bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
> + if (err < 0)
> + return err;
> + /* Reset the bluetooth chip via USB interface. */
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT, 0x000000FF);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
> + if (err < 0)
> + return err;
> + /* MT7921 need to delay 20ms between toggle reset bit */
> + msleep(20);
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 0);
> + if (err < 0)
> + return err;
> + err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
> + if (err < 0)
> + return err;
> + }
> +
> + err = readx_poll_timeout(btmtk_usb_reset_done, hdev, val,
> + val & MTK_BT_RST_DONE, 20000, 1000000);
> + if (err < 0)
> + bt_dev_err(hdev, "Reset timeout");
> +
> + if (dev_id == 0x7922) {
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT, 0x000000FF);
> + if (err < 0)
> + return err;
> + }
> +
> + err = btmtk_usb_id_get(hdev, 0x70010200, &val);
> + if (err < 0 || !val)
> + bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(btmtk_usb_subsys_reset);
> +
> +int btmtk_usb_setup(struct hci_dev *hdev)
> +{
> + struct btmtk_data *btmtk_data = hci_get_priv(hdev);
> + struct btmtk_hci_wmt_params wmt_params;
> + ktime_t calltime, delta, rettime;
> + struct btmtk_tci_sleep tci_sleep;
> + unsigned long long duration;
> + struct sk_buff *skb;
> + const char *fwname;
> + int err, status;
> + u32 dev_id = 0;
> + char fw_bin_name[64];
> + u32 fw_version = 0, fw_flavor = 0;
> + u8 param;
> +
> + calltime = ktime_get();
> +
> + err = btmtk_usb_id_get(hdev, 0x80000008, &dev_id);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to get device id (%d)", err);
> + return err;
> + }
> +
> + if (!dev_id || dev_id != 0x7663) {
> + err = btmtk_usb_id_get(hdev, 0x70010200, &dev_id);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to get device id (%d)", err);
> + return err;
> + }
> + err = btmtk_usb_id_get(hdev, 0x80021004, &fw_version);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to get fw version (%d)", err);
> + return err;
> + }
> + err = btmtk_usb_id_get(hdev, 0x70010020, &fw_flavor);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
> + return err;
> + }
> + fw_flavor = (fw_flavor & 0x00000080) >> 7;
> + }
> +
> + btmtk_data->dev_id = dev_id;
> +
> + err = btmtk_register_coredump(hdev, btmtk_data->drv_name, fw_version);
> + if (err < 0)
> + bt_dev_err(hdev, "Failed to register coredump (%d)", err);
> +
> + switch (dev_id) {
> + case 0x7663:
> + fwname = FIRMWARE_MT7663;
> + break;
> + case 0x7668:
> + fwname = FIRMWARE_MT7668;
> + break;
> + case 0x7922:
> + case 0x7961:
> + case 0x7925:
> + /* Reset the device to ensure it's in the initial state before
> + * downloading the firmware to ensure.
> + */
> +
> + if (!test_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags))
> + btmtk_usb_subsys_reset(hdev, dev_id);
> +
> + btmtk_fw_get_filename(fw_bin_name, sizeof(fw_bin_name), dev_id,
> + fw_version, fw_flavor);
> +
> + err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
> + btmtk_usb_hci_wmt_sync);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to set up firmware (%d)", err);
> + clear_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags);
> + return err;
> + }
> +
> + set_bit(BTMTK_FIRMWARE_LOADED, &btmtk_data->flags);
> +
> + /* It's Device EndPoint Reset Option Register */
> + err = btmtk_usb_uhw_reg_write(hdev, MTK_EP_RST_OPT,
> + MTK_EP_RST_IN_OUT_OPT);
> + if (err < 0)
> + return err;
> +
> + /* Enable Bluetooth protocol */
> + param = 1;
> + wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> + wmt_params.flag = 0;
> + wmt_params.dlen = sizeof(param);
> + wmt_params.data = ¶m;
> + wmt_params.status = NULL;
> +
> + err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> + return err;
> + }
> +
> + hci_set_msft_opcode(hdev, 0xFD30);
> + hci_set_aosp_capable(hdev);
> +
> + goto done;
> + default:
> + bt_dev_err(hdev, "Unsupported hardware variant (%08x)",
> + dev_id);
> + return -ENODEV;
> + }
> +
> + /* Query whether the firmware is already download */
> + wmt_params.op = BTMTK_WMT_SEMAPHORE;
> + wmt_params.flag = 1;
> + wmt_params.dlen = 0;
> + wmt_params.data = NULL;
> + wmt_params.status = &status;
> +
> + err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
> + return err;
> + }
> +
> + if (status == BTMTK_WMT_PATCH_DONE) {
> + bt_dev_info(hdev, "firmware already downloaded");
> + goto ignore_setup_fw;
> + }
> +
> + /* Setup a firmware which the device definitely requires */
> + err = btmtk_setup_firmware(hdev, fwname,
> + btmtk_usb_hci_wmt_sync);
> + if (err < 0)
> + return err;
> +
> +ignore_setup_fw:
> + err = readx_poll_timeout(btmtk_usb_func_query, hdev, status,
> + status < 0 || status != BTMTK_WMT_ON_PROGRESS,
> + 2000, 5000000);
> + /* -ETIMEDOUT happens */
> + if (err < 0)
> + return err;
> +
> + /* The other errors happen in btmtk_usb_func_query */
> + if (status < 0)
> + return status;
> +
> + if (status == BTMTK_WMT_ON_DONE) {
> + bt_dev_info(hdev, "function already on");
> + goto ignore_func_on;
> + }
> +
> + /* Enable Bluetooth protocol */
> + param = 1;
> + wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> + wmt_params.flag = 0;
> + wmt_params.dlen = sizeof(param);
> + wmt_params.data = ¶m;
> + wmt_params.status = NULL;
> +
> + err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> + return err;
> + }
> +
> +ignore_func_on:
> + /* Apply the low power environment setup */
> + tci_sleep.mode = 0x5;
> + tci_sleep.duration = cpu_to_le16(0x640);
> + tci_sleep.host_duration = cpu_to_le16(0x640);
> + tci_sleep.host_wakeup_pin = 0;
> + tci_sleep.time_compensation = 0;
> +
> + skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
> + HCI_INIT_TIMEOUT);
> + if (IS_ERR(skb)) {
> + err = PTR_ERR(skb);
> + bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
> + return err;
> + }
> + kfree_skb(skb);
> +
> +done:
> + rettime = ktime_get();
> + delta = ktime_sub(rettime, calltime);
> + duration = (unsigned long long)ktime_to_ns(delta) >> 10;
> +
> + bt_dev_info(hdev, "Device setup in %llu usecs", duration);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(btmtk_usb_setup);
> +
> +int btmtk_usb_shutdown(struct hci_dev *hdev)
> +{
> + struct btmtk_hci_wmt_params wmt_params;
> + u8 param = 0;
> + int err;
> +
> + /* Disable the device */
> + wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> + wmt_params.flag = 0;
> + wmt_params.dlen = sizeof(param);
> + wmt_params.data = ¶m;
> + wmt_params.status = NULL;
> +
> + err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> + if (err < 0) {
> + bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> + return err;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(btmtk_usb_shutdown);
>
> MODULE_AUTHOR("Sean Wang <sean.wang at mediatek.com>");
> MODULE_AUTHOR("Mark Chen <mark-yw.chen at mediatek.com>");
> diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
> index 3055b9728ae25..fe41528ae509b 100644
> --- a/drivers/bluetooth/btmtk.h
> +++ b/drivers/bluetooth/btmtk.h
> @@ -140,6 +140,8 @@ struct btmtk_hci_wmt_params {
>
> enum {
> BTMTK_TX_WAIT_VND_EVT,
> + BTMTK_FIRMWARE_LOADED,
> + BTMTK_HW_RESET_ACTIVE,
> };
>
> typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
> @@ -152,6 +154,7 @@ struct btmtk_coredump_info {
> };
>
> struct btmtk_data {
> + const char *drv_name;
> unsigned long flags;
> u32 dev_id;
> btmtk_reset_sync_func_t reset_sync;
> @@ -186,8 +189,11 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
> void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
> u32 fw_flavor);
>
> -int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
> - struct btmtk_hci_wmt_params *wmt_params);
> +int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id);
> +
> +int btmtk_usb_setup(struct hci_dev *hdev);
> +
> +int btmtk_usb_shutdown(struct hci_dev *hdev);
> #else
>
> static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
> @@ -228,8 +234,17 @@ static void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id,
> {
> }
>
> -static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
> - struct btmtk_hci_wmt_params *wmt_params)
> +static int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static int btmtk_usb_setup(struct hci_dev *hdev)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static int btmtk_usb_shutdown(struct hci_dev *hdev)
> {
> return -EOPNOTSUPP;
> }
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index b311a04f7c6f1..11d24a566fc8d 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -2736,178 +2736,6 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
> return hci_recv_frame(hdev, skb);
> }
>
> -static int btusb_mtk_func_query(struct hci_dev *hdev)
> -{
> - struct btmtk_hci_wmt_params wmt_params;
> - int status, err;
> - u8 param = 0;
> -
> - /* Query whether the function is enabled */
> - wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> - wmt_params.flag = 4;
> - wmt_params.dlen = sizeof(param);
> - wmt_params.data = ¶m;
> - wmt_params.status = &status;
> -
> - err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to query function status (%d)", err);
> - return err;
> - }
> -
> - return status;
> -}
> -
> -static int btusb_mtk_uhw_reg_write(struct btusb_data *data, u32 reg, u32 val)
> -{
> - struct hci_dev *hdev = data->hdev;
> - int pipe, err;
> - void *buf;
> -
> - buf = kzalloc(4, GFP_KERNEL);
> - if (!buf)
> - return -ENOMEM;
> -
> - put_unaligned_le32(val, buf);
> -
> - pipe = usb_sndctrlpipe(data->udev, 0);
> - err = usb_control_msg(data->udev, pipe, 0x02,
> - 0x5E,
> - reg >> 16, reg & 0xffff,
> - buf, 4, USB_CTRL_SET_TIMEOUT);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to write uhw reg(%d)", err);
> - goto err_free_buf;
> - }
> -
> -err_free_buf:
> - kfree(buf);
> -
> - return err;
> -}
> -
> -static int btusb_mtk_uhw_reg_read(struct btusb_data *data, u32 reg, u32 *val)
> -{
> - struct hci_dev *hdev = data->hdev;
> - int pipe, err;
> - void *buf;
> -
> - buf = kzalloc(4, GFP_KERNEL);
> - if (!buf)
> - return -ENOMEM;
> -
> - pipe = usb_rcvctrlpipe(data->udev, 0);
> - err = usb_control_msg(data->udev, pipe, 0x01,
> - 0xDE,
> - reg >> 16, reg & 0xffff,
> - buf, 4, USB_CTRL_SET_TIMEOUT);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
> - goto err_free_buf;
> - }
> -
> - *val = get_unaligned_le32(buf);
> - bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
> -
> -err_free_buf:
> - kfree(buf);
> -
> - return err;
> -}
> -
> -static int btusb_mtk_reg_read(struct btusb_data *data, u32 reg, u32 *val)
> -{
> - int pipe, err, size = sizeof(u32);
> - void *buf;
> -
> - buf = kzalloc(size, GFP_KERNEL);
> - if (!buf)
> - return -ENOMEM;
> -
> - pipe = usb_rcvctrlpipe(data->udev, 0);
> - err = usb_control_msg(data->udev, pipe, 0x63,
> - USB_TYPE_VENDOR | USB_DIR_IN,
> - reg >> 16, reg & 0xffff,
> - buf, size, USB_CTRL_SET_TIMEOUT);
> - if (err < 0)
> - goto err_free_buf;
> -
> - *val = get_unaligned_le32(buf);
> -
> -err_free_buf:
> - kfree(buf);
> -
> - return err;
> -}
> -
> -static int btusb_mtk_id_get(struct btusb_data *data, u32 reg, u32 *id)
> -{
> - return btusb_mtk_reg_read(data, reg, id);
> -}
> -
> -static u32 btusb_mtk_reset_done(struct hci_dev *hdev)
> -{
> - struct btusb_data *data = hci_get_drvdata(hdev);
> - u32 val = 0;
> -
> - btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
> -
> - return val & MTK_BT_RST_DONE;
> -}
> -
> -static int btusb_mtk_subsys_reset(struct hci_dev *hdev, u32 dev_id)
> -{
> - struct btusb_data *data = hci_get_drvdata(hdev);
> - u32 val;
> - int err;
> -
> - if (dev_id == 0x7925) {
> - btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
> - val |= (1 << 5);
> - btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
> - btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
> - val &= 0xFFFF00FF;
> - val |= (1 << 13);
> - btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
> - btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001);
> - btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
> - val |= (1 << 0);
> - btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
> - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
> - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
> - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
> - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
> - msleep(100);
> - } else {
> - /* It's Device EndPoint Reset Option Register */
> - bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
> - btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
> - btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
> -
> - /* Reset the bluetooth chip via USB interface. */
> - btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
> - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
> - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
> - btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
> - btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
> - /* MT7921 need to delay 20ms between toggle reset bit */
> - msleep(20);
> - btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
> - btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
> - }
> -
> - err = readx_poll_timeout(btusb_mtk_reset_done, hdev, val,
> - val & MTK_BT_RST_DONE, 20000, 1000000);
> - if (err < 0)
> - bt_dev_err(hdev, "Reset timeout");
> -
> - btusb_mtk_id_get(data, 0x70010200, &val);
> - if (!val)
> - bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
> -
> - return err;
> -}
> -
> static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
> {
> struct btusb_data *data = hci_get_drvdata(hdev);
> @@ -2915,7 +2743,7 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
> int err;
>
> /* It's MediaTek specific bluetooth reset mechanism via USB */
> - if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
> + if (test_and_set_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags)) {
> bt_dev_err(hdev, "last reset failed? Not resetting again");
> return -EBUSY;
> }
> @@ -2927,10 +2755,10 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
> btusb_stop_traffic(data);
> usb_kill_anchored_urbs(&data->tx_anchor);
>
> - err = btusb_mtk_subsys_reset(hdev, btmtk_data->dev_id);
> + err = btmtk_usb_subsys_reset(hdev, btmtk_data->dev_id);
>
> usb_queue_reset_device(data->intf);
> - clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
> + clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
>
> return err;
> }
> @@ -2938,202 +2766,23 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
> static int btusb_mtk_setup(struct hci_dev *hdev)
> {
> struct btusb_data *data = hci_get_drvdata(hdev);
> - struct btmtk_hci_wmt_params wmt_params;
> - ktime_t calltime, delta, rettime;
> - struct btmtk_tci_sleep tci_sleep;
> - unsigned long long duration;
> - struct sk_buff *skb;
> - const char *fwname;
> - int err, status;
> - u32 dev_id = 0;
> - char fw_bin_name[64];
> - u32 fw_version = 0;
> - u8 param;
> - struct btmtk_data *mediatek;
> -
> - calltime = ktime_get();
> -
> - err = btusb_mtk_id_get(data, 0x80000008, &dev_id);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to get device id (%d)", err);
> - return err;
> - }
> -
> - if (!dev_id || dev_id != 0x7663) {
> - err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to get device id (%d)", err);
> - return err;
> - }
> - err = btusb_mtk_id_get(data, 0x80021004, &fw_version);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to get fw version (%d)", err);
> - return err;
> - }
> - }
> -
> - mediatek = hci_get_priv(hdev);
> - mediatek->dev_id = dev_id;
> - mediatek->reset_sync = btusb_mtk_reset;
> -
> - err = btmtk_register_coredump(hdev, btusb_driver.name, fw_version);
> - if (err < 0)
> - bt_dev_err(hdev, "Failed to register coredump (%d)", err);
> -
> - switch (dev_id) {
> - case 0x7663:
> - fwname = FIRMWARE_MT7663;
> - break;
> - case 0x7668:
> - fwname = FIRMWARE_MT7668;
> - break;
> - case 0x7922:
> - case 0x7961:
> - case 0x7925:
> - if (dev_id == 0x7925)
> - snprintf(fw_bin_name, sizeof(fw_bin_name),
> - "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
> - dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
> - else
> - snprintf(fw_bin_name, sizeof(fw_bin_name),
> - "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
> - dev_id & 0xffff, (fw_version & 0xff) + 1);
> -
> - err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
> - btmtk_usb_hci_wmt_sync);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to set up firmware (%d)", err);
> - return err;
> - }
> -
> - /* It's Device EndPoint Reset Option Register */
> - btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
> -
> - /* Enable Bluetooth protocol */
> - param = 1;
> - wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> - wmt_params.flag = 0;
> - wmt_params.dlen = sizeof(param);
> - wmt_params.data = ¶m;
> - wmt_params.status = NULL;
> -
> - err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> - return err;
> - }
> -
> - hci_set_msft_opcode(hdev, 0xFD30);
> - hci_set_aosp_capable(hdev);
> - goto done;
> - default:
> - bt_dev_err(hdev, "Unsupported hardware variant (%08x)",
> - dev_id);
> - return -ENODEV;
> - }
> -
> - /* Query whether the firmware is already download */
> - wmt_params.op = BTMTK_WMT_SEMAPHORE;
> - wmt_params.flag = 1;
> - wmt_params.dlen = 0;
> - wmt_params.data = NULL;
> - wmt_params.status = &status;
> -
> - err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
> - return err;
> - }
> -
> - if (status == BTMTK_WMT_PATCH_DONE) {
> - bt_dev_info(hdev, "firmware already downloaded");
> - goto ignore_setup_fw;
> - }
> -
> - /* Setup a firmware which the device definitely requires */
> - err = btmtk_setup_firmware(hdev, fwname,
> - btmtk_usb_hci_wmt_sync);
> - if (err < 0)
> - return err;
> -
> -ignore_setup_fw:
> - err = readx_poll_timeout(btusb_mtk_func_query, hdev, status,
> - status < 0 || status != BTMTK_WMT_ON_PROGRESS,
> - 2000, 5000000);
> - /* -ETIMEDOUT happens */
> - if (err < 0)
> - return err;
> -
> - /* The other errors happen in btusb_mtk_func_query */
> - if (status < 0)
> - return status;
> -
> - if (status == BTMTK_WMT_ON_DONE) {
> - bt_dev_info(hdev, "function already on");
> - goto ignore_func_on;
> - }
> -
> - /* Enable Bluetooth protocol */
> - param = 1;
> - wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> - wmt_params.flag = 0;
> - wmt_params.dlen = sizeof(param);
> - wmt_params.data = ¶m;
> - wmt_params.status = NULL;
> -
> - err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> - return err;
> - }
> -
> -ignore_func_on:
> - /* Apply the low power environment setup */
> - tci_sleep.mode = 0x5;
> - tci_sleep.duration = cpu_to_le16(0x640);
> - tci_sleep.host_duration = cpu_to_le16(0x640);
> - tci_sleep.host_wakeup_pin = 0;
> - tci_sleep.time_compensation = 0;
> -
> - skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
> - HCI_INIT_TIMEOUT);
> - if (IS_ERR(skb)) {
> - err = PTR_ERR(skb);
> - bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
> - return err;
> - }
> - kfree_skb(skb);
> -
> -done:
> - rettime = ktime_get();
> - delta = ktime_sub(rettime, calltime);
> - duration = (unsigned long long)ktime_to_ns(delta) >> 10;
> + struct btmtk_data *btmtk_data = hci_get_priv(hdev);
>
> - bt_dev_info(hdev, "Device setup in %llu usecs", duration);
> + /* MediaTek WMT vendor cmd requiring below USB resources to
> + * complete the handshake.
> + */
> + btmtk_data->drv_name = btusb_driver.name;
> + btmtk_data->intf = data->intf;
> + btmtk_data->udev = data->udev;
> + btmtk_data->ctrl_anchor = &data->ctrl_anchor;
> + btmtk_data->reset_sync = btusb_mtk_reset;
>
> - return 0;
> + return btmtk_usb_setup(hdev);
> }
>
> static int btusb_mtk_shutdown(struct hci_dev *hdev)
> {
> - struct btmtk_hci_wmt_params wmt_params;
> - u8 param = 0;
> - int err;
> -
> - /* Disable the device */
> - wmt_params.op = BTMTK_WMT_FUNC_CTRL;
> - wmt_params.flag = 0;
> - wmt_params.dlen = sizeof(param);
> - wmt_params.data = ¶m;
> - wmt_params.status = NULL;
> -
> - err = btmtk_usb_hci_wmt_sync(hdev, &wmt_params);
> - if (err < 0) {
> - bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
> - return err;
> - }
> -
> - return 0;
> + return btmtk_usb_shutdown(hdev);
> }
>
> static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20260903/4c8c3639/attachment-0001.sig>
More information about the kernel-team
mailing list