diff options
author | Sean Wang <sean.wang@mediatek.com> | 2019-06-01 20:02:48 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2019-07-06 15:44:25 -0400 |
commit | a1c49c434e15050b5dafe3b6f5cc732d4f02d657 (patch) | |
tree | 72b39d7c3eb772897782e0fd554f0bed3e7ccc86 /drivers/bluetooth | |
parent | 688d94fd0d10d9ebe611a445d85811894f8cf6c4 (diff) |
Bluetooth: btusb: Add protocol support for MediaTek MT7668U USB devices
This adds the support of enabling MT7668U Bluetooth function running
on the top of btusb driver.
The information in /sys/kernel/debug/usb/devices about the Bluetooth
device is listed as the below.
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=5000 MxCh= 0
D: Ver= 3.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS= 9 #Cfgs= 1
P: Vendor=0e8d ProdID=7668 Rev= 1.00
S: Manufacturer=MediaTek Inc.
S: Product=Wireless_Device
S: SerialNumber=000000000
C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr=160mA
A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us
E: Ad=82(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS=1024 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
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 11 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 576 |
2 files changed, 587 insertions, 0 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index a3fafd781aa1..aae665a3a254 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig | |||
@@ -52,6 +52,17 @@ config BT_HCIBTUSB_BCM | |||
52 | 52 | ||
53 | Say Y here to compile support for Broadcom protocol. | 53 | Say Y here to compile support for Broadcom protocol. |
54 | 54 | ||
55 | config BT_HCIBTUSB_MTK | ||
56 | bool "MediaTek protocol support" | ||
57 | depends on BT_HCIBTUSB | ||
58 | default n | ||
59 | help | ||
60 | The MediaTek protocol support enables firmware download | ||
61 | support and chip initialization for MediaTek Bluetooth | ||
62 | USB controllers. | ||
63 | |||
64 | Say Y here to compile support for MediaTek protocol. | ||
65 | |||
55 | config BT_HCIBTUSB_RTL | 66 | config BT_HCIBTUSB_RTL |
56 | bool "Realtek protocol support" | 67 | bool "Realtek protocol support" |
57 | depends on BT_HCIBTUSB | 68 | depends on BT_HCIBTUSB |
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c550a8e7c336..0c58fd1a5b0f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/usb.h> | 11 | #include <linux/usb.h> |
12 | #include <linux/usb/quirks.h> | 12 | #include <linux/usb/quirks.h> |
13 | #include <linux/firmware.h> | 13 | #include <linux/firmware.h> |
14 | #include <linux/iopoll.h> | ||
14 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
15 | #include <linux/of_irq.h> | 16 | #include <linux/of_irq.h> |
16 | #include <linux/suspend.h> | 17 | #include <linux/suspend.h> |
@@ -55,6 +56,7 @@ static struct usb_driver btusb_driver; | |||
55 | #define BTUSB_BCM2045 0x40000 | 56 | #define BTUSB_BCM2045 0x40000 |
56 | #define BTUSB_IFNUM_2 0x80000 | 57 | #define BTUSB_IFNUM_2 0x80000 |
57 | #define BTUSB_CW6622 0x100000 | 58 | #define BTUSB_CW6622 0x100000 |
59 | #define BTUSB_MEDIATEK 0x200000 | ||
58 | 60 | ||
59 | static const struct usb_device_id btusb_table[] = { | 61 | static const struct usb_device_id btusb_table[] = { |
60 | /* Generic Bluetooth USB device */ | 62 | /* Generic Bluetooth USB device */ |
@@ -348,6 +350,10 @@ static const struct usb_device_id blacklist_table[] = { | |||
348 | { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), | 350 | { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), |
349 | .driver_info = BTUSB_REALTEK }, | 351 | .driver_info = BTUSB_REALTEK }, |
350 | 352 | ||
353 | /* MediaTek Bluetooth devices */ | ||
354 | { USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01), | ||
355 | .driver_info = BTUSB_MEDIATEK }, | ||
356 | |||
351 | /* Additional Realtek 8723AE Bluetooth devices */ | 357 | /* Additional Realtek 8723AE Bluetooth devices */ |
352 | { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, | 358 | { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, |
353 | { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK }, | 359 | { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK }, |
@@ -428,6 +434,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { | |||
428 | #define BTUSB_DIAG_RUNNING 10 | 434 | #define BTUSB_DIAG_RUNNING 10 |
429 | #define BTUSB_OOB_WAKE_ENABLED 11 | 435 | #define BTUSB_OOB_WAKE_ENABLED 11 |
430 | #define BTUSB_HW_RESET_ACTIVE 12 | 436 | #define BTUSB_HW_RESET_ACTIVE 12 |
437 | #define BTUSB_TX_WAIT_VND_EVT 13 | ||
431 | 438 | ||
432 | struct btusb_data { | 439 | struct btusb_data { |
433 | struct hci_dev *hdev; | 440 | struct hci_dev *hdev; |
@@ -451,6 +458,7 @@ struct btusb_data { | |||
451 | struct usb_anchor bulk_anchor; | 458 | struct usb_anchor bulk_anchor; |
452 | struct usb_anchor isoc_anchor; | 459 | struct usb_anchor isoc_anchor; |
453 | struct usb_anchor diag_anchor; | 460 | struct usb_anchor diag_anchor; |
461 | struct usb_anchor ctrl_anchor; | ||
454 | spinlock_t rxlock; | 462 | spinlock_t rxlock; |
455 | 463 | ||
456 | struct sk_buff *evt_skb; | 464 | struct sk_buff *evt_skb; |
@@ -1204,6 +1212,7 @@ static void btusb_stop_traffic(struct btusb_data *data) | |||
1204 | usb_kill_anchored_urbs(&data->bulk_anchor); | 1212 | usb_kill_anchored_urbs(&data->bulk_anchor); |
1205 | usb_kill_anchored_urbs(&data->isoc_anchor); | 1213 | usb_kill_anchored_urbs(&data->isoc_anchor); |
1206 | usb_kill_anchored_urbs(&data->diag_anchor); | 1214 | usb_kill_anchored_urbs(&data->diag_anchor); |
1215 | usb_kill_anchored_urbs(&data->ctrl_anchor); | ||
1207 | } | 1216 | } |
1208 | 1217 | ||
1209 | static int btusb_close(struct hci_dev *hdev) | 1218 | static int btusb_close(struct hci_dev *hdev) |
@@ -2439,6 +2448,563 @@ static int btusb_shutdown_intel_new(struct hci_dev *hdev) | |||
2439 | return 0; | 2448 | return 0; |
2440 | } | 2449 | } |
2441 | 2450 | ||
2451 | #ifdef CONFIG_BT_HCIBTUSB_MTK | ||
2452 | |||
2453 | #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" | ||
2454 | |||
2455 | #define HCI_WMT_MAX_EVENT_SIZE 64 | ||
2456 | |||
2457 | enum { | ||
2458 | BTMTK_WMT_PATCH_DWNLD = 0x1, | ||
2459 | BTMTK_WMT_FUNC_CTRL = 0x6, | ||
2460 | BTMTK_WMT_RST = 0x7, | ||
2461 | BTMTK_WMT_SEMAPHORE = 0x17, | ||
2462 | }; | ||
2463 | |||
2464 | enum { | ||
2465 | BTMTK_WMT_INVALID, | ||
2466 | BTMTK_WMT_PATCH_UNDONE, | ||
2467 | BTMTK_WMT_PATCH_DONE, | ||
2468 | BTMTK_WMT_ON_UNDONE, | ||
2469 | BTMTK_WMT_ON_DONE, | ||
2470 | BTMTK_WMT_ON_PROGRESS, | ||
2471 | }; | ||
2472 | |||
2473 | struct btmtk_wmt_hdr { | ||
2474 | u8 dir; | ||
2475 | u8 op; | ||
2476 | __le16 dlen; | ||
2477 | u8 flag; | ||
2478 | } __packed; | ||
2479 | |||
2480 | struct btmtk_hci_wmt_cmd { | ||
2481 | struct btmtk_wmt_hdr hdr; | ||
2482 | u8 data[256]; | ||
2483 | } __packed; | ||
2484 | |||
2485 | struct btmtk_hci_wmt_evt { | ||
2486 | struct hci_event_hdr hhdr; | ||
2487 | struct btmtk_wmt_hdr whdr; | ||
2488 | } __packed; | ||
2489 | |||
2490 | struct btmtk_hci_wmt_evt_funcc { | ||
2491 | struct btmtk_hci_wmt_evt hwhdr; | ||
2492 | __be16 status; | ||
2493 | } __packed; | ||
2494 | |||
2495 | struct btmtk_tci_sleep { | ||
2496 | u8 mode; | ||
2497 | __le16 duration; | ||
2498 | __le16 host_duration; | ||
2499 | u8 host_wakeup_pin; | ||
2500 | u8 time_compensation; | ||
2501 | } __packed; | ||
2502 | |||
2503 | struct btmtk_hci_wmt_params { | ||
2504 | u8 op; | ||
2505 | u8 flag; | ||
2506 | u16 dlen; | ||
2507 | const void *data; | ||
2508 | u32 *status; | ||
2509 | }; | ||
2510 | |||
2511 | static void btusb_mtk_wmt_recv(struct urb *urb) | ||
2512 | { | ||
2513 | struct hci_dev *hdev = urb->context; | ||
2514 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
2515 | struct hci_event_hdr *hdr; | ||
2516 | struct sk_buff *skb; | ||
2517 | int err; | ||
2518 | |||
2519 | if (urb->status == 0 && urb->actual_length > 0) { | ||
2520 | hdev->stat.byte_rx += urb->actual_length; | ||
2521 | |||
2522 | /* WMT event shouldn't be fragmented and the size should be | ||
2523 | * less than HCI_WMT_MAX_EVENT_SIZE. | ||
2524 | */ | ||
2525 | skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC); | ||
2526 | if (!skb) { | ||
2527 | hdev->stat.err_rx++; | ||
2528 | goto err_out; | ||
2529 | } | ||
2530 | |||
2531 | hci_skb_pkt_type(skb) = HCI_EVENT_PKT; | ||
2532 | skb_put_data(skb, urb->transfer_buffer, urb->actual_length); | ||
2533 | |||
2534 | hdr = (void *)skb->data; | ||
2535 | /* Fix up the vendor event id with 0xff for vendor specific | ||
2536 | * instead of 0xe4 so that event send via monitoring socket can | ||
2537 | * be parsed properly. | ||
2538 | */ | ||
2539 | hdr->evt = 0xff; | ||
2540 | |||
2541 | /* When someone waits for the WMT event, the skb is being cloned | ||
2542 | * and being processed the events from there then. | ||
2543 | */ | ||
2544 | if (test_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags)) { | ||
2545 | data->evt_skb = skb_clone(skb, GFP_KERNEL); | ||
2546 | if (!data->evt_skb) | ||
2547 | goto err_out; | ||
2548 | } | ||
2549 | |||
2550 | err = hci_recv_frame(hdev, skb); | ||
2551 | if (err < 0) | ||
2552 | goto err_free_skb; | ||
2553 | |||
2554 | if (test_and_clear_bit(BTUSB_TX_WAIT_VND_EVT, | ||
2555 | &data->flags)) { | ||
2556 | /* Barrier to sync with other CPUs */ | ||
2557 | smp_mb__after_atomic(); | ||
2558 | wake_up_bit(&data->flags, | ||
2559 | BTUSB_TX_WAIT_VND_EVT); | ||
2560 | } | ||
2561 | err_out: | ||
2562 | return; | ||
2563 | err_free_skb: | ||
2564 | kfree_skb(data->evt_skb); | ||
2565 | data->evt_skb = NULL; | ||
2566 | return; | ||
2567 | } else if (urb->status == -ENOENT) { | ||
2568 | /* Avoid suspend failed when usb_kill_urb */ | ||
2569 | return; | ||
2570 | } | ||
2571 | |||
2572 | usb_mark_last_busy(data->udev); | ||
2573 | |||
2574 | /* The URB complete handler is still called with urb->actual_length = 0 | ||
2575 | * when the event is not available, so we should keep re-submitting | ||
2576 | * URB until WMT event returns, Also, It's necessary to wait some time | ||
2577 | * between the two consecutive control URBs to relax the target device | ||
2578 | * to generate the event. Otherwise, the WMT event cannot return from | ||
2579 | * the device successfully. | ||
2580 | */ | ||
2581 | udelay(100); | ||
2582 | |||
2583 | usb_anchor_urb(urb, &data->ctrl_anchor); | ||
2584 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
2585 | if (err < 0) { | ||
2586 | /* -EPERM: urb is being killed; | ||
2587 | * -ENODEV: device got disconnected | ||
2588 | */ | ||
2589 | if (err != -EPERM && err != -ENODEV) | ||
2590 | bt_dev_err(hdev, "urb %p failed to resubmit (%d)", | ||
2591 | urb, -err); | ||
2592 | usb_unanchor_urb(urb); | ||
2593 | } | ||
2594 | } | ||
2595 | |||
2596 | static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev) | ||
2597 | { | ||
2598 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
2599 | struct usb_ctrlrequest *dr; | ||
2600 | unsigned char *buf; | ||
2601 | int err, size = 64; | ||
2602 | unsigned int pipe; | ||
2603 | struct urb *urb; | ||
2604 | |||
2605 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
2606 | if (!urb) | ||
2607 | return -ENOMEM; | ||
2608 | |||
2609 | dr = kmalloc(sizeof(*dr), GFP_KERNEL); | ||
2610 | if (!dr) { | ||
2611 | usb_free_urb(urb); | ||
2612 | return -ENOMEM; | ||
2613 | } | ||
2614 | |||
2615 | dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN; | ||
2616 | dr->bRequest = 1; | ||
2617 | dr->wIndex = cpu_to_le16(0); | ||
2618 | dr->wValue = cpu_to_le16(48); | ||
2619 | dr->wLength = cpu_to_le16(size); | ||
2620 | |||
2621 | buf = kmalloc(size, GFP_KERNEL); | ||
2622 | if (!buf) { | ||
2623 | kfree(dr); | ||
2624 | return -ENOMEM; | ||
2625 | } | ||
2626 | |||
2627 | pipe = usb_rcvctrlpipe(data->udev, 0); | ||
2628 | |||
2629 | usb_fill_control_urb(urb, data->udev, pipe, (void *)dr, | ||
2630 | buf, size, btusb_mtk_wmt_recv, hdev); | ||
2631 | |||
2632 | urb->transfer_flags |= URB_FREE_BUFFER; | ||
2633 | |||
2634 | usb_anchor_urb(urb, &data->ctrl_anchor); | ||
2635 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
2636 | if (err < 0) { | ||
2637 | if (err != -EPERM && err != -ENODEV) | ||
2638 | bt_dev_err(hdev, "urb %p submission failed (%d)", | ||
2639 | urb, -err); | ||
2640 | usb_unanchor_urb(urb); | ||
2641 | } | ||
2642 | |||
2643 | usb_free_urb(urb); | ||
2644 | |||
2645 | return err; | ||
2646 | } | ||
2647 | |||
2648 | static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, | ||
2649 | struct btmtk_hci_wmt_params *wmt_params) | ||
2650 | { | ||
2651 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
2652 | struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc; | ||
2653 | u32 hlen, status = BTMTK_WMT_INVALID; | ||
2654 | struct btmtk_hci_wmt_evt *wmt_evt; | ||
2655 | struct btmtk_hci_wmt_cmd wc; | ||
2656 | struct btmtk_wmt_hdr *hdr; | ||
2657 | int err; | ||
2658 | |||
2659 | /* Submit control IN URB on demand to process the WMT event */ | ||
2660 | err = btusb_mtk_submit_wmt_recv_urb(hdev); | ||
2661 | if (err < 0) | ||
2662 | return err; | ||
2663 | |||
2664 | /* Send the WMT command and wait until the WMT event returns */ | ||
2665 | hlen = sizeof(*hdr) + wmt_params->dlen; | ||
2666 | if (hlen > 255) | ||
2667 | return -EINVAL; | ||
2668 | |||
2669 | hdr = (struct btmtk_wmt_hdr *)&wc; | ||
2670 | hdr->dir = 1; | ||
2671 | hdr->op = wmt_params->op; | ||
2672 | hdr->dlen = cpu_to_le16(wmt_params->dlen + 1); | ||
2673 | hdr->flag = wmt_params->flag; | ||
2674 | memcpy(wc.data, wmt_params->data, wmt_params->dlen); | ||
2675 | |||
2676 | set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); | ||
2677 | |||
2678 | err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc); | ||
2679 | |||
2680 | if (err < 0) { | ||
2681 | clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); | ||
2682 | return err; | ||
2683 | } | ||
2684 | |||
2685 | /* The vendor specific WMT commands are all answered by a vendor | ||
2686 | * specific event and will have the Command Status or Command | ||
2687 | * Complete as with usual HCI command flow control. | ||
2688 | * | ||
2689 | * After sending the command, wait for BTUSB_TX_WAIT_VND_EVT | ||
2690 | * state to be cleared. The driver specific event receive routine | ||
2691 | * will clear that state and with that indicate completion of the | ||
2692 | * WMT command. | ||
2693 | */ | ||
2694 | err = wait_on_bit_timeout(&data->flags, BTUSB_TX_WAIT_VND_EVT, | ||
2695 | TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT); | ||
2696 | if (err == -EINTR) { | ||
2697 | bt_dev_err(hdev, "Execution of wmt command interrupted"); | ||
2698 | clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); | ||
2699 | return err; | ||
2700 | } | ||
2701 | |||
2702 | if (err) { | ||
2703 | bt_dev_err(hdev, "Execution of wmt command timed out"); | ||
2704 | clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); | ||
2705 | return -ETIMEDOUT; | ||
2706 | } | ||
2707 | |||
2708 | /* Parse and handle the return WMT event */ | ||
2709 | wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data; | ||
2710 | if (wmt_evt->whdr.op != hdr->op) { | ||
2711 | bt_dev_err(hdev, "Wrong op received %d expected %d", | ||
2712 | wmt_evt->whdr.op, hdr->op); | ||
2713 | err = -EIO; | ||
2714 | goto err_free_skb; | ||
2715 | } | ||
2716 | |||
2717 | switch (wmt_evt->whdr.op) { | ||
2718 | case BTMTK_WMT_SEMAPHORE: | ||
2719 | if (wmt_evt->whdr.flag == 2) | ||
2720 | status = BTMTK_WMT_PATCH_UNDONE; | ||
2721 | else | ||
2722 | status = BTMTK_WMT_PATCH_DONE; | ||
2723 | break; | ||
2724 | case BTMTK_WMT_FUNC_CTRL: | ||
2725 | wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; | ||
2726 | if (be16_to_cpu(wmt_evt_funcc->status) == 0x404) | ||
2727 | status = BTMTK_WMT_ON_DONE; | ||
2728 | else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420) | ||
2729 | status = BTMTK_WMT_ON_PROGRESS; | ||
2730 | else | ||
2731 | status = BTMTK_WMT_ON_UNDONE; | ||
2732 | break; | ||
2733 | } | ||
2734 | |||
2735 | if (wmt_params->status) | ||
2736 | *wmt_params->status = status; | ||
2737 | |||
2738 | err_free_skb: | ||
2739 | kfree_skb(data->evt_skb); | ||
2740 | data->evt_skb = NULL; | ||
2741 | |||
2742 | return err; | ||
2743 | } | ||
2744 | |||
2745 | static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname) | ||
2746 | { | ||
2747 | struct btmtk_hci_wmt_params wmt_params; | ||
2748 | const struct firmware *fw; | ||
2749 | const u8 *fw_ptr; | ||
2750 | size_t fw_size; | ||
2751 | int err, dlen; | ||
2752 | u8 flag; | ||
2753 | |||
2754 | err = request_firmware(&fw, fwname, &hdev->dev); | ||
2755 | if (err < 0) { | ||
2756 | bt_dev_err(hdev, "Failed to load firmware file (%d)", err); | ||
2757 | return err; | ||
2758 | } | ||
2759 | |||
2760 | fw_ptr = fw->data; | ||
2761 | fw_size = fw->size; | ||
2762 | |||
2763 | /* The size of patch header is 30 bytes, should be skip */ | ||
2764 | if (fw_size < 30) | ||
2765 | goto err_release_fw; | ||
2766 | |||
2767 | fw_size -= 30; | ||
2768 | fw_ptr += 30; | ||
2769 | flag = 1; | ||
2770 | |||
2771 | wmt_params.op = BTMTK_WMT_PATCH_DWNLD; | ||
2772 | wmt_params.status = NULL; | ||
2773 | |||
2774 | while (fw_size > 0) { | ||
2775 | dlen = min_t(int, 250, fw_size); | ||
2776 | |||
2777 | /* Tell deivice the position in sequence */ | ||
2778 | if (fw_size - dlen <= 0) | ||
2779 | flag = 3; | ||
2780 | else if (fw_size < fw->size - 30) | ||
2781 | flag = 2; | ||
2782 | |||
2783 | wmt_params.flag = flag; | ||
2784 | wmt_params.dlen = dlen; | ||
2785 | wmt_params.data = fw_ptr; | ||
2786 | |||
2787 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2788 | if (err < 0) { | ||
2789 | bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)", | ||
2790 | err); | ||
2791 | goto err_release_fw; | ||
2792 | } | ||
2793 | |||
2794 | fw_size -= dlen; | ||
2795 | fw_ptr += dlen; | ||
2796 | } | ||
2797 | |||
2798 | wmt_params.op = BTMTK_WMT_RST; | ||
2799 | wmt_params.flag = 4; | ||
2800 | wmt_params.dlen = 0; | ||
2801 | wmt_params.data = NULL; | ||
2802 | wmt_params.status = NULL; | ||
2803 | |||
2804 | /* Activate funciton the firmware providing to */ | ||
2805 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2806 | if (err < 0) { | ||
2807 | bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); | ||
2808 | return err; | ||
2809 | } | ||
2810 | |||
2811 | /* Wait a few moments for firmware activation done */ | ||
2812 | usleep_range(10000, 12000); | ||
2813 | |||
2814 | err_release_fw: | ||
2815 | release_firmware(fw); | ||
2816 | |||
2817 | return err; | ||
2818 | } | ||
2819 | |||
2820 | static int btusb_mtk_func_query(struct hci_dev *hdev) | ||
2821 | { | ||
2822 | struct btmtk_hci_wmt_params wmt_params; | ||
2823 | int status, err; | ||
2824 | u8 param = 0; | ||
2825 | |||
2826 | /* Query whether the function is enabled */ | ||
2827 | wmt_params.op = BTMTK_WMT_FUNC_CTRL; | ||
2828 | wmt_params.flag = 4; | ||
2829 | wmt_params.dlen = sizeof(param); | ||
2830 | wmt_params.data = ¶m; | ||
2831 | wmt_params.status = &status; | ||
2832 | |||
2833 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2834 | if (err < 0) { | ||
2835 | bt_dev_err(hdev, "Failed to query function status (%d)", err); | ||
2836 | return err; | ||
2837 | } | ||
2838 | |||
2839 | return status; | ||
2840 | } | ||
2841 | |||
2842 | static int btusb_mtk_reg_read(struct btusb_data *data, u32 reg, u32 *val) | ||
2843 | { | ||
2844 | int pipe, err, size = sizeof(u32); | ||
2845 | void *buf; | ||
2846 | |||
2847 | buf = kzalloc(size, GFP_KERNEL); | ||
2848 | if (!buf) | ||
2849 | return -ENOMEM; | ||
2850 | |||
2851 | pipe = usb_rcvctrlpipe(data->udev, 0); | ||
2852 | err = usb_control_msg(data->udev, pipe, 0x63, | ||
2853 | USB_TYPE_VENDOR | USB_DIR_IN, | ||
2854 | reg >> 16, reg & 0xffff, | ||
2855 | buf, size, USB_CTRL_SET_TIMEOUT); | ||
2856 | if (err < 0) | ||
2857 | goto err_free_buf; | ||
2858 | |||
2859 | *val = get_unaligned_le32(buf); | ||
2860 | |||
2861 | err_free_buf: | ||
2862 | kfree(buf); | ||
2863 | |||
2864 | return err; | ||
2865 | } | ||
2866 | |||
2867 | static int btusb_mtk_id_get(struct btusb_data *data, u32 *id) | ||
2868 | { | ||
2869 | return btusb_mtk_reg_read(data, 0x80000008, id); | ||
2870 | } | ||
2871 | |||
2872 | static int btusb_mtk_setup(struct hci_dev *hdev) | ||
2873 | { | ||
2874 | struct btusb_data *data = hci_get_drvdata(hdev); | ||
2875 | struct btmtk_hci_wmt_params wmt_params; | ||
2876 | ktime_t calltime, delta, rettime; | ||
2877 | struct btmtk_tci_sleep tci_sleep; | ||
2878 | unsigned long long duration; | ||
2879 | struct sk_buff *skb; | ||
2880 | const char *fwname; | ||
2881 | int err, status; | ||
2882 | u32 dev_id; | ||
2883 | u8 param; | ||
2884 | |||
2885 | calltime = ktime_get(); | ||
2886 | |||
2887 | err = btusb_mtk_id_get(data, &dev_id); | ||
2888 | if (err < 0) { | ||
2889 | bt_dev_err(hdev, "Failed to get device id (%d)", err); | ||
2890 | return err; | ||
2891 | } | ||
2892 | |||
2893 | switch (dev_id) { | ||
2894 | case 0x7668: | ||
2895 | fwname = FIRMWARE_MT7668; | ||
2896 | break; | ||
2897 | default: | ||
2898 | bt_dev_err(hdev, "Unsupported support hardware variant (%08x)", | ||
2899 | dev_id); | ||
2900 | return -ENODEV; | ||
2901 | } | ||
2902 | |||
2903 | /* Query whether the firmware is already download */ | ||
2904 | wmt_params.op = BTMTK_WMT_SEMAPHORE; | ||
2905 | wmt_params.flag = 1; | ||
2906 | wmt_params.dlen = 0; | ||
2907 | wmt_params.data = NULL; | ||
2908 | wmt_params.status = &status; | ||
2909 | |||
2910 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2911 | if (err < 0) { | ||
2912 | bt_dev_err(hdev, "Failed to query firmware status (%d)", err); | ||
2913 | return err; | ||
2914 | } | ||
2915 | |||
2916 | if (status == BTMTK_WMT_PATCH_DONE) { | ||
2917 | bt_dev_info(hdev, "firmware already downloaded"); | ||
2918 | goto ignore_setup_fw; | ||
2919 | } | ||
2920 | |||
2921 | /* Setup a firmware which the device definitely requires */ | ||
2922 | err = btusb_mtk_setup_firmware(hdev, fwname); | ||
2923 | if (err < 0) | ||
2924 | return err; | ||
2925 | |||
2926 | ignore_setup_fw: | ||
2927 | err = readx_poll_timeout(btusb_mtk_func_query, hdev, status, | ||
2928 | status < 0 || status != BTMTK_WMT_ON_PROGRESS, | ||
2929 | 2000, 5000000); | ||
2930 | /* -ETIMEDOUT happens */ | ||
2931 | if (err < 0) | ||
2932 | return err; | ||
2933 | |||
2934 | /* The other errors happen in btusb_mtk_func_query */ | ||
2935 | if (status < 0) | ||
2936 | return status; | ||
2937 | |||
2938 | if (status == BTMTK_WMT_ON_DONE) { | ||
2939 | bt_dev_info(hdev, "function already on"); | ||
2940 | goto ignore_func_on; | ||
2941 | } | ||
2942 | |||
2943 | /* Enable Bluetooth protocol */ | ||
2944 | param = 1; | ||
2945 | wmt_params.op = BTMTK_WMT_FUNC_CTRL; | ||
2946 | wmt_params.flag = 0; | ||
2947 | wmt_params.dlen = sizeof(param); | ||
2948 | wmt_params.data = ¶m; | ||
2949 | wmt_params.status = NULL; | ||
2950 | |||
2951 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2952 | if (err < 0) { | ||
2953 | bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); | ||
2954 | return err; | ||
2955 | } | ||
2956 | |||
2957 | ignore_func_on: | ||
2958 | /* Apply the low power environment setup */ | ||
2959 | tci_sleep.mode = 0x5; | ||
2960 | tci_sleep.duration = cpu_to_le16(0x640); | ||
2961 | tci_sleep.host_duration = cpu_to_le16(0x640); | ||
2962 | tci_sleep.host_wakeup_pin = 0; | ||
2963 | tci_sleep.time_compensation = 0; | ||
2964 | |||
2965 | skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep, | ||
2966 | HCI_INIT_TIMEOUT); | ||
2967 | if (IS_ERR(skb)) { | ||
2968 | err = PTR_ERR(skb); | ||
2969 | bt_dev_err(hdev, "Failed to apply low power setting (%d)", err); | ||
2970 | return err; | ||
2971 | } | ||
2972 | kfree_skb(skb); | ||
2973 | |||
2974 | rettime = ktime_get(); | ||
2975 | delta = ktime_sub(rettime, calltime); | ||
2976 | duration = (unsigned long long)ktime_to_ns(delta) >> 10; | ||
2977 | |||
2978 | bt_dev_info(hdev, "Device setup in %llu usecs", duration); | ||
2979 | |||
2980 | return 0; | ||
2981 | } | ||
2982 | |||
2983 | static int btusb_mtk_shutdown(struct hci_dev *hdev) | ||
2984 | { | ||
2985 | struct btmtk_hci_wmt_params wmt_params; | ||
2986 | u8 param = 0; | ||
2987 | int err; | ||
2988 | |||
2989 | /* Disable the device */ | ||
2990 | wmt_params.op = BTMTK_WMT_FUNC_CTRL; | ||
2991 | wmt_params.flag = 0; | ||
2992 | wmt_params.dlen = sizeof(param); | ||
2993 | wmt_params.data = ¶m; | ||
2994 | wmt_params.status = NULL; | ||
2995 | |||
2996 | err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params); | ||
2997 | if (err < 0) { | ||
2998 | bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); | ||
2999 | return err; | ||
3000 | } | ||
3001 | |||
3002 | return 0; | ||
3003 | } | ||
3004 | |||
3005 | MODULE_FIRMWARE(FIRMWARE_MT7668); | ||
3006 | #endif | ||
3007 | |||
2442 | #ifdef CONFIG_PM | 3008 | #ifdef CONFIG_PM |
2443 | /* Configure an out-of-band gpio as wake-up pin, if specified in device tree */ | 3009 | /* Configure an out-of-band gpio as wake-up pin, if specified in device tree */ |
2444 | static int marvell_config_oob_wake(struct hci_dev *hdev) | 3010 | static int marvell_config_oob_wake(struct hci_dev *hdev) |
@@ -3046,6 +3612,7 @@ static int btusb_probe(struct usb_interface *intf, | |||
3046 | init_usb_anchor(&data->bulk_anchor); | 3612 | init_usb_anchor(&data->bulk_anchor); |
3047 | init_usb_anchor(&data->isoc_anchor); | 3613 | init_usb_anchor(&data->isoc_anchor); |
3048 | init_usb_anchor(&data->diag_anchor); | 3614 | init_usb_anchor(&data->diag_anchor); |
3615 | init_usb_anchor(&data->ctrl_anchor); | ||
3049 | spin_lock_init(&data->rxlock); | 3616 | spin_lock_init(&data->rxlock); |
3050 | 3617 | ||
3051 | if (id->driver_info & BTUSB_INTEL_NEW) { | 3618 | if (id->driver_info & BTUSB_INTEL_NEW) { |
@@ -3159,6 +3726,15 @@ static int btusb_probe(struct usb_interface *intf, | |||
3159 | if (id->driver_info & BTUSB_MARVELL) | 3726 | if (id->driver_info & BTUSB_MARVELL) |
3160 | hdev->set_bdaddr = btusb_set_bdaddr_marvell; | 3727 | hdev->set_bdaddr = btusb_set_bdaddr_marvell; |
3161 | 3728 | ||
3729 | #ifdef CONFIG_BT_HCIBTUSB_MTK | ||
3730 | if (id->driver_info & BTUSB_MEDIATEK) { | ||
3731 | hdev->setup = btusb_mtk_setup; | ||
3732 | hdev->shutdown = btusb_mtk_shutdown; | ||
3733 | hdev->manufacturer = 70; | ||
3734 | set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); | ||
3735 | } | ||
3736 | #endif | ||
3737 | |||
3162 | if (id->driver_info & BTUSB_SWAVE) { | 3738 | if (id->driver_info & BTUSB_SWAVE) { |
3163 | set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks); | 3739 | set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks); |
3164 | set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks); | 3740 | set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks); |