From patchwork Sat Aug 1 01:17:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Fong X-Patchwork-Id: 6921571 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7EDA5C05AC for ; Sat, 1 Aug 2015 01:20:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 812972060E for ; Sat, 1 Aug 2015 01:20:38 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7AA7F204FF for ; Sat, 1 Aug 2015 01:20:37 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZLLRk-0002MC-45; Sat, 01 Aug 2015 01:18:44 +0000 Received: from mail-pd0-x230.google.com ([2607:f8b0:400e:c02::230]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZLLRP-0002DQ-Ql for linux-arm-kernel@lists.infradead.org; Sat, 01 Aug 2015 01:18:25 +0000 Received: by pdrg1 with SMTP id g1so50459756pdr.2 for ; Fri, 31 Jul 2015 18:18:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PXk2DbVGghVbRbPYh2vtIvVq4DyHeAPTZlhWNki7Hnc=; b=c+OcD6UUT284DxjSDIB15lMffZyy7ML0zRknX4DLslmVU3Ojn/YaJVq4f2ECjeBRom shvwUNFbvH6KVABao0Zg/cxKFr2bOFcopgn1kulZ1Mta27pz3EeVfyoR9Lod+HGcqBKQ gH6j/GdJH2dS7L1q7XFw7paf8mqknm3ulAgUKwsUkIEX91ESI79ikcHPpPd7a+/7b0K7 PfF7nXeaXKsdmD+rO5MGvr/pmfTuYB5q93WAibfS0s51eKQ5JAgWPBU+eWoPByRVUsue xD1VK4mv7tpM2T0/QlLQvnsxaJMrYSuQm+ikpb6/pWjvViADk1DS2FSrRMQkKuxFeh+R p+Nw== X-Received: by 10.70.134.198 with SMTP id pm6mr13376553pdb.17.1438391882956; Fri, 31 Jul 2015 18:18:02 -0700 (PDT) Received: from gregory-irv-00.broadcom.com (5520-maca-inet1-outside.broadcom.com. [216.31.211.11]) by smtp.gmail.com with ESMTPSA id a5sm9696004pdk.90.2015.07.31.18.17.59 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 31 Jul 2015 18:18:00 -0700 (PDT) From: Gregory Fong To: Linus Walleij Subject: [PATCH v4 3/4] gpio: brcmstb: support wakeup from S5 cold boot Date: Fri, 31 Jul 2015 18:17:44 -0700 Message-Id: <1438391865-7862-4-git-send-email-gregory.0xf0@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1438391865-7862-1-git-send-email-gregory.0xf0@gmail.com> References: <1438391865-7862-1-git-send-email-gregory.0xf0@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150731_181824_042858_E0C7F62A X-CRM114-Status: GOOD ( 19.04 ) X-Spam-Score: -2.5 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Alexandre Courbot , Florian Fainelli , Russell King , Pawel Moll , devicetree@vger.kernel.org, Ian Campbell , linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, Rob Herring , bcm-kernel-feedback-list@broadcom.com, Gregory Fong , Kumar Gala , Brian Norris , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP For wake from S5, we need to: - register a reboot handler - set wakeup capability before requesting IRQ so wakeup count is incremented - mask all GPIO IRQs and clear any pending interrupts during driver probe to since no driver will yet be registered to handle any IRQs carried over from boot at that time, and it's possible that the booted kernel does not request the same IRQ anyway. This means that /sys/.../power/wakeup_count is valid at boot time, and we can properly account for S5 wakeup stats. e.g.: ### After waking from S5 from a GPIO key # cat /sys/bus/platform/drivers/brcmstb-gpio/f04172c0.gpio/power/wakeup enabled # cat /sys/bus/platform/drivers/brcmstb-gpio/f04172c0.gpio/power/wakeup_count 1 Signed-off-by: Gregory Fong --- v4: rename __brcmstb_gpio_irq_set_wake() to brcmstb_gpio_priv_set_wake(). drivers/gpio/gpio-brcmstb.c | 56 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 46cc4e9..9ea86d2 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -20,6 +20,7 @@ #include #include #include +#include #define GIO_BANK_SIZE 0x20 #define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00) @@ -48,6 +49,7 @@ struct brcmstb_gpio_priv { int gpio_base; bool can_wake; int parent_wake_irq; + struct notifier_block reboot_notifier; }; #define MAX_GPIO_PER_BANK 32 @@ -167,10 +169,9 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } -static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) +static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, + unsigned int enable) { - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); int ret = 0; /* @@ -188,6 +189,14 @@ static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) return ret; } +static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); + + return brcmstb_gpio_priv_set_wake(priv, enable); +} + static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data) { struct brcmstb_gpio_priv *priv = data; @@ -246,6 +255,19 @@ static void brcmstb_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } +static int brcmstb_gpio_reboot(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct brcmstb_gpio_priv *priv = + container_of(nb, struct brcmstb_gpio_priv, reboot_notifier); + + /* Enable GPIO for S5 cold boot */ + if (action == SYS_POWER_OFF) + brcmstb_gpio_priv_set_wake(priv, 1); + + return NOTIFY_DONE; +} + /* Make sure that the number of banks matches up between properties */ static int brcmstb_gpio_sanity_check_banks(struct device *dev, struct device_node *np, struct resource *res) @@ -285,6 +307,12 @@ static int brcmstb_gpio_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "gpiochip_remove fail in cleanup\n"); } + if (priv->reboot_notifier.notifier_call) { + ret = unregister_reboot_notifier(&priv->reboot_notifier); + if (ret) + dev_err(&pdev->dev, + "failed to unregister reboot notifier\n"); + } return ret; } @@ -342,7 +370,16 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, dev_warn(dev, "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); } else { - int err = devm_request_irq(dev, priv->parent_wake_irq, + int err; + + /* + * Set wakeup capability before requesting wakeup + * interrupt, so we can process boot-time "wakeups" + * (e.g., from S5 cold boot) + */ + device_set_wakeup_capable(dev, true); + device_wakeup_enable(dev); + err = devm_request_irq(dev, priv->parent_wake_irq, brcmstb_gpio_wake_irq_handler, 0, "brcmstb-gpio-wake", priv); @@ -351,8 +388,9 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, return err; } - device_set_wakeup_capable(dev, true); - device_wakeup_enable(dev); + priv->reboot_notifier.notifier_call = + brcmstb_gpio_reboot; + register_reboot_notifier(&priv->reboot_notifier); priv->can_wake = true; } } @@ -455,6 +493,12 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) /* not all ngpio lines are valid, will use bank width later */ gc->ngpio = MAX_GPIO_PER_BANK; + /* + * Mask all interrupts by default, since wakeup interrupts may + * be retained from S5 cold boot + */ + bank->bgc.write_reg(reg_base + GIO_MASK(bank->id), 0); + err = gpiochip_add(gc); if (err) { dev_err(dev, "Could not add gpiochip for bank %d\n",