From patchwork Wed Jan 25 18:34:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajat Jain X-Patchwork-Id: 719797 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3v7v0D75jJz9sD5 for ; Thu, 26 Jan 2017 05:36:44 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="Tbw89rcy"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752562AbdAYSgb (ORCPT ); Wed, 25 Jan 2017 13:36:31 -0500 Received: from mail-pf0-f179.google.com ([209.85.192.179]:34141 "EHLO mail-pf0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752282AbdAYSfO (ORCPT ); Wed, 25 Jan 2017 13:35:14 -0500 Received: by mail-pf0-f179.google.com with SMTP id e4so59763872pfg.1 for ; Wed, 25 Jan 2017 10:35:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=30YvqFynGL3UleeEabhL1g1JYcuBj6IXD59ZMLonUOU=; b=Tbw89rcymCyUq+88upD8EtWhAKbIAqK94LmW11oPNhxzSuY6lByxhpmLW9qBdBh/r1 FDir5qJFfAIJtDKNKlsZEuJQbjhm30bo70u+Urp8oyqIopx/hrPRryDZa49Pa8YT5tHq ZrVdnTR9JmtcNvsJ8vp73oRCJCXRd+h2YZehghlhzhz5pCCu0XYedRlhczvR35g0MgOg 4TeIttAnVZSX4+c9kZrAHVXuyvJuw/kENUQnVaEgq1RMq8aoU2UV2p7Nb5+V/KbmSHyw eyl5LX2pdt0Yyys+xsYnRXmg7VBTLDIy6flrrtVuuDfUbsirJudw5qIRTZCgRD0Pcm1C fArQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=30YvqFynGL3UleeEabhL1g1JYcuBj6IXD59ZMLonUOU=; b=s/IyKBHIMkkj4QnO3U5lU9GWf/UDKCb0rVl4UCVyJmygzfpAlbic1HFJIYafwzzuNz DpjVNfN9u10ZnBIg5c3uXeYYVFPVJetnkP2UNHDmS28guD8VkjYwkigGVSQH5YpvkVgr sX50P8EyuhKToAkHn8BGEJ1RfFE5V0U/QyqT2cPmnXCkeCHuud8Vs+YZoO/rVHwsMJgy DtdaKtaY4kAiC2L7dxyineknddwfnK/4+qd06F5FQ7RkUgJXpn8C2bSXnRDb6f+ApnOP 2XXtD2w4evIWWM8ZOoz6zT0oJ/eba3cEsNkKSgYcaibXCSKLFNUc8Y+EV3cLxCGDMxG7 UjAA== X-Gm-Message-State: AIkVDXKFCVFjv8IySqyvaZoojHRh/903ofBZdB/EW2x0CdsDJPDGL+FgB6oYIHBZYX1vKpEA X-Received: by 10.99.147.12 with SMTP id b12mr743657pge.158.1485369313849; Wed, 25 Jan 2017 10:35:13 -0800 (PST) Received: from rajat.mtv.corp.google.com ([172.22.64.13]) by smtp.gmail.com with ESMTPSA id t185sm2858073pgb.32.2017.01.25.10.35.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 25 Jan 2017 10:35:13 -0800 (PST) From: Rajat Jain To: Rob Herring , Mark Rutland , Marcel Holtmann , Gustavo Padovan , Johan Hedberg , Amitkumar Karwar , Wei-Ning Huang , Xinming Hu , netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-bluetooth@vger.kernel.org, Brian Norris , linux-kernel@vger.kernel.org Cc: Rajat Jain , rajatxjain@gmail.com Subject: [PATCH v6 2/3] Bluetooth: btusb: Add out-of-band wakeup support Date: Wed, 25 Jan 2017 10:34:59 -0800 Message-Id: <20170125183500.8292-2-rajatja@google.com> X-Mailer: git-send-email 2.11.0.483.g087da7b7c-goog In-Reply-To: <20170125183500.8292-1-rajatja@google.com> References: <20170125183500.8292-1-rajatja@google.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 Reviewed-by: Brian Norris Acked-by: Rob Herring --- v6: Remove the newlines in error statements ("\n") v5: Move the call to pm_wakeup_event() to the begining of irq handler. v4: Move the set_bit(BTUSB_OOB_WAKE_DISABLED,..) call to the beginning of btusb_config_oob_wake() v3: Add Brian's "Reviewed-by" v2: * Use interrupt-names ("wakeup") instead of assuming first interrupt. * Leave it on device tree to specify IRQ flags (level /edge triggered) * Mark the device as non wakeable on exit. Documentation/devicetree/bindings/net/btusb.txt | 40 ++++++++++++ drivers/bluetooth/btusb.c | 85 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/btusb.txt 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 @@ +Generic Bluetooth controller over USB (btusb driver) +--------------------------------------------------- + +Required properties: + + - compatible : should comply with the format "usbVID,PID" specified in + Documentation/devicetree/bindings/usb/usb-device.txt + At the time of writing, the only OF supported devices + (more may be added later) are: + + "usb1286,204e" (Marvell 8997) + +Optional properties: + + - interrupt-parent: phandle of the parent interrupt controller + - interrupt-names: (see below) + - interrupts : The interrupt specified by the name "wakeup" is the interrupt + that shall be used for out-of-band wake-on-bt. Driver will + request this interrupt for wakeup. During system suspend, the + irq will be enabled so that the bluetooth chip can wakeup host + platform out of band. During system resume, the irq will be + disabled to make sure unnecessary interrupt is not received. + +Example: + +Following example uses irq pin number 3 of gpio0 for out of band wake-on-bt: + +&usb_host1_ehci { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + mvl_bt1: bt@1 { + compatible = "usb1286,204e"; + reg = <1>; + interrupt-parent = <&gpio0>; + interrupt-name = "wakeup"; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; +}; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ce22cefceed1..0e7aed20b71b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -369,6 +371,7 @@ static const struct usb_device_id blacklist_table[] = { #define BTUSB_BOOTING 9 #define BTUSB_RESET_RESUME 10 #define BTUSB_DIAG_RUNNING 11 +#define BTUSB_OOB_WAKE_DISABLED 12 struct btusb_data { struct hci_dev *hdev; @@ -416,6 +419,8 @@ struct btusb_data { int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); int (*setup_on_usb)(struct hci_dev *hdev); + + int oob_wake_irq; /* irq for out-of-band wake-on-bt */ }; static inline void btusb_free_frags(struct btusb_data *data) @@ -2728,6 +2733,66 @@ static int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable) } #endif +#ifdef CONFIG_PM +static irqreturn_t btusb_oob_wake_handler(int irq, void *priv) +{ + struct btusb_data *data = priv; + + pm_wakeup_event(&data->udev->dev, 0); + + /* Disable only if not already disabled (keep it balanced) */ + if (!test_and_set_bit(BTUSB_OOB_WAKE_DISABLED, &data->flags)) { + disable_irq_nosync(irq); + disable_irq_wake(irq); + } + return IRQ_HANDLED; +} + +static const struct of_device_id btusb_match_table[] = { + { .compatible = "usb1286,204e" }, + { } +}; +MODULE_DEVICE_TABLE(of, btusb_match_table); + +/* Use an oob wakeup pin? */ +static int btusb_config_oob_wake(struct hci_dev *hdev) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct device *dev = &data->udev->dev; + int irq, ret; + + set_bit(BTUSB_OOB_WAKE_DISABLED, &data->flags); + + if (!of_match_device(btusb_match_table, dev)) + return 0; + + /* Move on if no IRQ specified */ + irq = of_irq_get_byname(dev->of_node, "wakeup"); + if (irq <= 0) { + bt_dev_dbg(hdev, "%s: no OOB Wakeup IRQ in DT", __func__); + return 0; + } + + ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler, + 0, "OOB Wake-on-BT", data); + if (ret) { + bt_dev_err(hdev, "%s: IRQ request failed", __func__); + return ret; + } + + ret = device_init_wakeup(dev, true); + if (ret) { + bt_dev_err(hdev, "%s: failed to init_wakeup", __func__); + return ret; + } + + data->oob_wake_irq = irq; + disable_irq(irq); + bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq); + return 0; +} +#endif + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2849,6 +2914,11 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame; hdev->notify = btusb_notify; +#ifdef CONFIG_PM + err = btusb_config_oob_wake(hdev); + if (err) + goto out_free_dev; +#endif if (id->driver_info & BTUSB_CW6622) set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks); @@ -3061,6 +3131,9 @@ static void btusb_disconnect(struct usb_interface *intf) usb_driver_release_interface(&btusb_driver, data->isoc); } + if (data->oob_wake_irq) + device_init_wakeup(&data->udev->dev, false); + hci_free_dev(hdev); } @@ -3089,6 +3162,12 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); + if (data->oob_wake_irq && device_may_wakeup(&data->udev->dev)) { + clear_bit(BTUSB_OOB_WAKE_DISABLED, &data->flags); + enable_irq_wake(data->oob_wake_irq); + enable_irq(data->oob_wake_irq); + } + /* Optionally request a device reset on resume, but only when * wakeups are disabled. If wakeups are enabled we assume the * device will stay powered up throughout suspend. @@ -3126,6 +3205,12 @@ static int btusb_resume(struct usb_interface *intf) if (--data->suspend_count) return 0; + /* Disable only if not already disabled (keep it balanced) */ + if (!test_and_set_bit(BTUSB_OOB_WAKE_DISABLED, &data->flags)) { + disable_irq(data->oob_wake_irq); + disable_irq_wake(data->oob_wake_irq); + } + if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done;