aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajat Jain <rajatja@google.com>2017-02-01 17:24:09 -0500
committerMarcel Holtmann <marcel@holtmann.org>2017-02-16 11:21:59 -0500
commitfd913ef7ce619467c6b0644af48ba1fec499c623 (patch)
treee323cc6e819c2782c30f09d85a29eb4d05ecd10d
parent10ab133b7a1a7265600d580d9e056d86aea70b53 (diff)
Bluetooth: btusb: Add out-of-band wakeup support
Some onboard BT chips (e.g. Marvell 8997) contain a wakeup pin that can be connected to a gpio on the CPU side, and can be used to wakeup the host out-of-band. This can be useful in situations where the in-band wakeup is not possible or not preferable (e.g. the in-band wakeup may require the USB host controller to remain active, and hence consuming more system power during system sleep). The oob gpio interrupt to be used for wakeup on the CPU side, is read from the device tree node, (using standard interrupt descriptors). A devcie tree binding document is also added for the driver. The compatible string is in compliance with Documentation/devicetree/bindings/usb/usb-device.txt Signed-off-by: Rajat Jain <rajatja@google.com> Reviewed-by: Brian Norris <briannorris@chromium.org> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--Documentation/devicetree/bindings/net/btusb.txt40
-rw-r--r--drivers/bluetooth/btusb.c85
2 files changed, 125 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/btusb.txt b/Documentation/devicetree/bindings/net/btusb.txt
new file mode 100644
index 000000000000..2c0355c85972
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/btusb.txt
@@ -0,0 +1,40 @@
1Generic Bluetooth controller over USB (btusb driver)
2---------------------------------------------------
3
4Required properties:
5
6 - compatible : should comply with the format "usbVID,PID" specified in
7 Documentation/devicetree/bindings/usb/usb-device.txt
8 At the time of writing, the only OF supported devices
9 (more may be added later) are:
10
11 "usb1286,204e" (Marvell 8997)
12
13Optional properties:
14
15 - interrupt-parent: phandle of the parent interrupt controller
16 - interrupt-names: (see below)
17 - interrupts : The interrupt specified by the name "wakeup" is the interrupt
18 that shall be used for out-of-band wake-on-bt. Driver will
19 request this interrupt for wakeup. During system suspend, the
20 irq will be enabled so that the bluetooth chip can wakeup host
21 platform out of band. During system resume, the irq will be
22 disabled to make sure unnecessary interrupt is not received.
23
24Example:
25
26Following example uses irq pin number 3 of gpio0 for out of band wake-on-bt:
27
28&usb_host1_ehci {
29 status = "okay";
30 #address-cells = <1>;
31 #size-cells = <0>;
32
33 mvl_bt1: bt@1 {
34 compatible = "usb1286,204e";
35 reg = <1>;
36 interrupt-parent = <&gpio0>;
37 interrupt-name = "wakeup";
38 interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
39 };
40};
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 699b2dbaf75b..f6bf990ccaeb 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -24,6 +24,8 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/usb.h> 25#include <linux/usb.h>
26#include <linux/firmware.h> 26#include <linux/firmware.h>
27#include <linux/of_device.h>
28#include <linux/of_irq.h>
27#include <asm/unaligned.h> 29#include <asm/unaligned.h>
28 30
29#include <net/bluetooth/bluetooth.h> 31#include <net/bluetooth/bluetooth.h>
@@ -373,6 +375,7 @@ static const struct usb_device_id blacklist_table[] = {
373#define BTUSB_BOOTING 9 375#define BTUSB_BOOTING 9
374#define BTUSB_RESET_RESUME 10 376#define BTUSB_RESET_RESUME 10
375#define BTUSB_DIAG_RUNNING 11 377#define BTUSB_DIAG_RUNNING 11
378#define BTUSB_OOB_WAKE_ENABLED 12
376 379
377struct btusb_data { 380struct btusb_data {
378 struct hci_dev *hdev; 381 struct hci_dev *hdev;
@@ -420,6 +423,8 @@ struct btusb_data {
420 int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); 423 int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
421 424
422 int (*setup_on_usb)(struct hci_dev *hdev); 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
425static inline void btusb_free_frags(struct btusb_data *data) 430static 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#endif 2738#endif
2734 2739
2740#ifdef CONFIG_PM
2741static 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
2755static const struct of_device_id btusb_match_table[] = {
2756 { .compatible = "usb1286,204e" },
2757 { }
2758};
2759MODULE_DEVICE_TABLE(of, btusb_match_table);
2760
2761/* Use an oob wakeup pin? */
2762static 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
2735static int btusb_probe(struct usb_interface *intf, 2800static int btusb_probe(struct usb_interface *intf,
2736 const struct usb_device_id *id) 2801 const struct usb_device_id *id)
2737{ 2802{
@@ -2853,6 +2918,11 @@ static int btusb_probe(struct usb_interface *intf,
2853 hdev->send = btusb_send_frame; 2918 hdev->send = btusb_send_frame;
2854 hdev->notify = btusb_notify; 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 if (id->driver_info & BTUSB_CW6622) 2926 if (id->driver_info & BTUSB_CW6622)
2857 set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks); 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 usb_driver_release_interface(&btusb_driver, data->isoc); 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 hci_free_dev(hdev); 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 btusb_stop_traffic(data); 3166 btusb_stop_traffic(data);
3094 usb_kill_anchored_urbs(&data->tx_anchor); 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 /* Optionally request a device reset on resume, but only when 3175 /* Optionally request a device reset on resume, but only when
3097 * wakeups are disabled. If wakeups are enabled we assume the 3176 * wakeups are disabled. If wakeups are enabled we assume the
3098 * device will stay powered up throughout suspend. 3177 * device will stay powered up throughout suspend.
@@ -3130,6 +3209,12 @@ static int btusb_resume(struct usb_interface *intf)
3130 if (--data->suspend_count) 3209 if (--data->suspend_count)
3131 return 0; 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 if (!test_bit(HCI_RUNNING, &hdev->flags)) 3218 if (!test_bit(HCI_RUNNING, &hdev->flags))
3134 goto done; 3219 goto done;
3135 3220