From patchwork Mon Oct 13 23:50:55 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Soren Brinkmann X-Patchwork-Id: 399318 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 DE3EF140119 for ; Tue, 14 Oct 2014 10:51:44 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752985AbaJMXvn (ORCPT ); Mon, 13 Oct 2014 19:51:43 -0400 Received: from mail-qa0-f47.google.com ([209.85.216.47]:56153 "EHLO mail-qa0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752554AbaJMXvn (ORCPT ); Mon, 13 Oct 2014 19:51:43 -0400 Received: by mail-qa0-f47.google.com with SMTP id cm18so5114003qab.6 for ; Mon, 13 Oct 2014 16:51:42 -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; bh=QcU5RodhGA8ZFXrdYFEiMNcYg3U4tB0gj4sz6RKn0dE=; b=lkUKkODB3eJOPpNdqLXKT0ekqMRIuwC8nwbogf7Kw1L5MfyNLTJf/OSd0+vBroNoKG oUyRpSQ+s6YMCu9p/zH1M7MCwSA9zSB1pl9zrveXQLgvjWQntXgoUYhfpTY8fOfoUbC/ 5RBDXWKpGOES63U0zBfwpxiSvPD9bsuihLeLuKY0z8niMnvAXDbq/MBEVBP8oadc/rp2 41fCzvJvx9b3zlMjw5glxZh31aKwSXIirfPOePNZFAz9HInRtfgemUe6nYwB0ziKqYh+ NI9bmS/ft98V9G3XnxnB8Wzt30sSOpK44BPkI3ZxyL2PijDz7Vf28p7QzdLDNAVpW9N2 fwMw== X-Received: by 10.229.7.133 with SMTP id d5mr3335011qcd.24.1413244302395; Mon, 13 Oct 2014 16:51:42 -0700 (PDT) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPSA id m8sm14125690qag.25.2014.10.13.16.51.40 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 13 Oct 2014 16:51:41 -0700 (PDT) From: Soren Brinkmann To: Linus Walleij Cc: Alexandre Courbot , linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, Soren Brinkmann Subject: [PATCH v2] gpio: lib-sysfs: Add 'wakeup' attribute Date: Mon, 13 Oct 2014 16:50:55 -0700 Message-Id: <1413244255-3880-1-git-send-email-soren.brinkmann@xilinx.com> X-Mailer: git-send-email 2.1.2.1.g5e69ed6 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 Reviewed-by: Alexandre Courbot --- v2: - fix error path to unlock mutex before return --- drivers/gpio/gpiolib-sysfs.c | 77 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 5f2150b619a7..7588b6d5ba94 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -286,6 +286,58 @@ 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 { + mutex_unlock(&sysfs_lock); + 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 +578,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 +634,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);