From patchwork Fri Aug 29 17:58:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Soren Brinkmann X-Patchwork-Id: 384339 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3AACA1400E9 for ; Sat, 30 Aug 2014 03:59:43 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754175AbaH2R7M (ORCPT ); Fri, 29 Aug 2014 13:59:12 -0400 Received: from mail-pa0-f42.google.com ([209.85.220.42]:48263 "EHLO mail-pa0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751944AbaH2R7I (ORCPT ); Fri, 29 Aug 2014 13:59:08 -0400 Received: by mail-pa0-f42.google.com with SMTP id lf10so7029335pab.29 for ; Fri, 29 Aug 2014 10:59:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=ULvEjkZ9RXaLUzKPnu1LeZh7Drd1X9wj2B35YyZSXhE=; b=v+zkALwDy4LA6dSmgpvK6HskNgJRnsFUkRQbfquOqoCTFXxN2QM8yxxB9EeIi8V6cG 3J3xWaobYvxLAoTQfuwjXCbdjqDJMNoEWg0sSSNEnP4DgBv4Qf6j1KF/qmJeToxBf1Qb AOM4UiRVt+iwg0V92Mj7tBWgIYIdU9ENdxBhgJfoGEgi90dherYhtOzuGOoaIRyWW5If XscbXnzf2yhMg2uJJuZwBfukS7R6k4+QgNOwGQrNXL/8Op4STGBobbgR1wxIhy+UBoww gnRFm+IR3F6XYTn5Wfahhk7tmAE1T/Hs/ZilZ58Xw27hvtkevmDNReudXD0wTRdv1Svy 3CGw== X-Received: by 10.68.103.4 with SMTP id fs4mr17877169pbb.58.1409335148149; Fri, 29 Aug 2014 10:59:08 -0700 (PDT) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPSA id zm5sm500940pbb.76.2014.08.29.10.59.06 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 29 Aug 2014 10:59:07 -0700 (PDT) From: Soren Brinkmann To: Alexandre Courbot , Linus Walleij Cc: =?UTF-8?q?S=C3=B6ren=20Brinkmann?= , Michal Simek , Harini Katakam , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, Lars-Peter Clausen , Ezra Savard Subject: [PATCH 3/3] gpio: lib-sysfs: Add 'wakeup' attribute Date: Fri, 29 Aug 2014 10:58:47 -0700 Message-Id: <1409335127-26712-4-git-send-email-soren.brinkmann@xilinx.com> X-Mailer: git-send-email 2.1.0.1.g27b9230 In-Reply-To: <1409335127-26712-1-git-send-email-soren.brinkmann@xilinx.com> References: <1409335127-26712-1-git-send-email-soren.brinkmann@xilinx.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Add an attribute 'wakeup' to the GPIO sysfs interface which allows marking/unmarking a GPIO as wake IRQ. The file 'wakeup' is created in each exported GPIOs directory, if an IRQ is associated with that GPIO and the irqchip implements set_wake(). Writing 'enabled' to that file will enable wake for that GPIO, while writing 'disabled' will disable wake. Reading that file will return either 'disabled' or 'enabled' depening on the currently set flag for the GPIO's IRQ. Signed-off-by: Soren Brinkmann --- drivers/gpio/gpiolib-sysfs.c | 75 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 5f2150b619a7..aaf021eaaff5 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -286,6 +286,56 @@ found: static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); +static ssize_t gpio_wakeup_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t status; + const struct gpio_desc *desc = dev_get_drvdata(dev); + int irq = gpiod_to_irq(desc); + struct irq_desc *irq_desc = irq_to_desc(irq); + + mutex_lock(&sysfs_lock); + + if (irqd_is_wakeup_set(&irq_desc->irq_data)) + status = sprintf(buf, "enabled\n"); + else + status = sprintf(buf, "disabled\n"); + + mutex_unlock(&sysfs_lock); + + return status; +} + +static ssize_t gpio_wakeup_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + unsigned int on; + struct gpio_desc *desc = dev_get_drvdata(dev); + int irq = gpiod_to_irq(desc); + + mutex_lock(&sysfs_lock); + + if (sysfs_streq("enabled", buf)) + on = true; + else if (sysfs_streq("disabled", buf)) + on = false; + else + return -EINVAL; + + ret = irq_set_irq_wake(irq, on); + + mutex_unlock(&sysfs_lock); + + if (ret) + pr_warn("%s: failed to %s wake\n", __func__, + on ? "enable" : "disable"); + + return size; +} + +static DEVICE_ATTR(wakeup, 0644, gpio_wakeup_show, gpio_wakeup_store); + static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, int value) { @@ -526,7 +576,7 @@ static struct class gpio_class = { int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { unsigned long flags; - int status; + int status, irq; const char *ioname = NULL; struct device *dev; int offset; @@ -582,11 +632,24 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) goto fail_unregister_device; } - if (gpiod_to_irq(desc) >= 0 && (direction_may_change || - !test_bit(FLAG_IS_OUT, &desc->flags))) { - status = device_create_file(dev, &dev_attr_edge); - if (status) - goto fail_unregister_device; + irq = gpiod_to_irq(desc); + if (irq >= 0) { + struct irq_desc *irq_desc = irq_to_desc(irq); + struct irq_chip *irqchip = irq_desc_get_chip(irq_desc); + + if (direction_may_change || + !test_bit(FLAG_IS_OUT, &desc->flags)) { + status = device_create_file(dev, &dev_attr_edge); + if (status) + goto fail_unregister_device; + } + + if (irqchip->flags & IRQCHIP_SKIP_SET_WAKE || + irqchip->irq_set_wake) { + status = device_create_file(dev, &dev_attr_wakeup); + if (status) + goto fail_unregister_device; + } } set_bit(FLAG_EXPORT, &desc->flags);