|
24 | 24 | #include <linux/module.h>
|
25 | 25 | #include <linux/usb.h>
|
26 | 26 | #include <linux/firmware.h>
|
| 27 | +#include <linux/of_device.h> |
| 28 | +#include <linux/of_irq.h> |
27 | 29 | #include <asm/unaligned.h>
|
28 | 30 |
|
29 | 31 | #include <net/bluetooth/bluetooth.h>
|
@@ -373,6 +375,7 @@ static const struct usb_device_id blacklist_table[] = {
|
373 | 375 | #define BTUSB_BOOTING 9
|
374 | 376 | #define BTUSB_RESET_RESUME 10
|
375 | 377 | #define BTUSB_DIAG_RUNNING 11
|
| 378 | +#define BTUSB_OOB_WAKE_ENABLED 12 |
376 | 379 |
|
377 | 380 | struct btusb_data {
|
378 | 381 | struct hci_dev *hdev;
|
@@ -420,6 +423,8 @@ struct btusb_data {
|
420 | 423 | int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
|
421 | 424 |
|
422 | 425 | int (*setup_on_usb)(struct hci_dev *hdev);
|
| 426 | + |
| 427 | + int oob_wake_irq; /* irq for out-of-band wake-on-bt */ |
423 | 428 | };
|
424 | 429 |
|
425 | 430 | static inline void btusb_free_frags(struct btusb_data *data)
|
@@ -2732,6 +2737,66 @@ static int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable)
|
2732 | 2737 | }
|
2733 | 2738 | #endif
|
2734 | 2739 |
|
| 2740 | +#ifdef CONFIG_PM |
| 2741 | +static irqreturn_t btusb_oob_wake_handler(int irq, void *priv) |
| 2742 | +{ |
| 2743 | + struct btusb_data *data = priv; |
| 2744 | + |
| 2745 | + pm_wakeup_event(&data->udev->dev, 0); |
| 2746 | + |
| 2747 | + /* Disable only if not already disabled (keep it balanced) */ |
| 2748 | + if (test_and_clear_bit(BTUSB_OOB_WAKE_ENABLED, &data->flags)) { |
| 2749 | + disable_irq_nosync(irq); |
| 2750 | + disable_irq_wake(irq); |
| 2751 | + } |
| 2752 | + return IRQ_HANDLED; |
| 2753 | +} |
| 2754 | + |
| 2755 | +static const struct of_device_id btusb_match_table[] = { |
| 2756 | + { .compatible = "usb1286,204e" }, |
| 2757 | + { } |
| 2758 | +}; |
| 2759 | +MODULE_DEVICE_TABLE(of, btusb_match_table); |
| 2760 | + |
| 2761 | +/* Use an oob wakeup pin? */ |
| 2762 | +static int btusb_config_oob_wake(struct hci_dev *hdev) |
| 2763 | +{ |
| 2764 | + struct btusb_data *data = hci_get_drvdata(hdev); |
| 2765 | + struct device *dev = &data->udev->dev; |
| 2766 | + int irq, ret; |
| 2767 | + |
| 2768 | + clear_bit(BTUSB_OOB_WAKE_ENABLED, &data->flags); |
| 2769 | + |
| 2770 | + if (!of_match_device(btusb_match_table, dev)) |
| 2771 | + return 0; |
| 2772 | + |
| 2773 | + /* Move on if no IRQ specified */ |
| 2774 | + irq = of_irq_get_byname(dev->of_node, "wakeup"); |
| 2775 | + if (irq <= 0) { |
| 2776 | + bt_dev_dbg(hdev, "%s: no OOB Wakeup IRQ in DT", __func__); |
| 2777 | + return 0; |
| 2778 | + } |
| 2779 | + |
| 2780 | + ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler, |
| 2781 | + 0, "OOB Wake-on-BT", data); |
| 2782 | + if (ret) { |
| 2783 | + bt_dev_err(hdev, "%s: IRQ request failed", __func__); |
| 2784 | + return ret; |
| 2785 | + } |
| 2786 | + |
| 2787 | + ret = device_init_wakeup(dev, true); |
| 2788 | + if (ret) { |
| 2789 | + bt_dev_err(hdev, "%s: failed to init_wakeup", __func__); |
| 2790 | + return ret; |
| 2791 | + } |
| 2792 | + |
| 2793 | + data->oob_wake_irq = irq; |
| 2794 | + disable_irq(irq); |
| 2795 | + bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); |
| 2796 | + return 0; |
| 2797 | +} |
| 2798 | +#endif |
| 2799 | + |
2735 | 2800 | static int btusb_probe(struct usb_interface *intf,
|
2736 | 2801 | const struct usb_device_id *id)
|
2737 | 2802 | {
|
@@ -2853,6 +2918,11 @@ static int btusb_probe(struct usb_interface *intf,
|
2853 | 2918 | hdev->send = btusb_send_frame;
|
2854 | 2919 | hdev->notify = btusb_notify;
|
2855 | 2920 |
|
| 2921 | +#ifdef CONFIG_PM |
| 2922 | + err = btusb_config_oob_wake(hdev); |
| 2923 | + if (err) |
| 2924 | + goto out_free_dev; |
| 2925 | +#endif |
2856 | 2926 | if (id->driver_info & BTUSB_CW6622)
|
2857 | 2927 | set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
|
2858 | 2928 |
|
@@ -3065,6 +3135,9 @@ static void btusb_disconnect(struct usb_interface *intf)
|
3065 | 3135 | usb_driver_release_interface(&btusb_driver, data->isoc);
|
3066 | 3136 | }
|
3067 | 3137 |
|
| 3138 | + if (data->oob_wake_irq) |
| 3139 | + device_init_wakeup(&data->udev->dev, false); |
| 3140 | + |
3068 | 3141 | hci_free_dev(hdev);
|
3069 | 3142 | }
|
3070 | 3143 |
|
@@ -3093,6 +3166,12 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
|
3093 | 3166 | btusb_stop_traffic(data);
|
3094 | 3167 | usb_kill_anchored_urbs(&data->tx_anchor);
|
3095 | 3168 |
|
| 3169 | + if (data->oob_wake_irq && device_may_wakeup(&data->udev->dev)) { |
| 3170 | + set_bit(BTUSB_OOB_WAKE_ENABLED, &data->flags); |
| 3171 | + enable_irq_wake(data->oob_wake_irq); |
| 3172 | + enable_irq(data->oob_wake_irq); |
| 3173 | + } |
| 3174 | + |
3096 | 3175 | /* Optionally request a device reset on resume, but only when
|
3097 | 3176 | * wakeups are disabled. If wakeups are enabled we assume the
|
3098 | 3177 | * device will stay powered up throughout suspend.
|
@@ -3130,6 +3209,12 @@ static int btusb_resume(struct usb_interface *intf)
|
3130 | 3209 | if (--data->suspend_count)
|
3131 | 3210 | return 0;
|
3132 | 3211 |
|
| 3212 | + /* Disable only if not already disabled (keep it balanced) */ |
| 3213 | + if (test_and_clear_bit(BTUSB_OOB_WAKE_ENABLED, &data->flags)) { |
| 3214 | + disable_irq(data->oob_wake_irq); |
| 3215 | + disable_irq_wake(data->oob_wake_irq); |
| 3216 | + } |
| 3217 | + |
3133 | 3218 | if (!test_bit(HCI_RUNNING, &hdev->flags))
|
3134 | 3219 | goto done;
|
3135 | 3220 |
|
|
0 commit comments