From patchwork Fri Oct 11 09:32:15 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 20956 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f72.google.com (mail-pa0-f72.google.com [209.85.220.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 261012611D for ; Fri, 11 Oct 2013 09:32:27 +0000 (UTC) Received: by mail-pa0-f72.google.com with SMTP id bj1sf7756343pad.3 for ; Fri, 11 Oct 2013 02:32:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=nkXMBamvmeWfUO0v25rEdwUL03kFvrx2dqoWkhcBq+4=; b=G52c6YnKXLNCSRXGi5KTFmncBFocK4J79ja4F8uQy683MboMYraflW+avHvom+hWzb BYojJ+mK/XsQ4dozVRnkIl1fNlfxlpQENMRbItRuZkZJlegAirL8F2TsQSJgTeFPRrF9 yduuTW9Oat+2wodJtAw70Co7bzfsQuw0Zw8Iow1a4G3liMjmC5OZrCSrLcwXwDZSozYL kSQ9b1HM1NXiaXT71OAZwv/OtPNCQF5U8bbG2/7F7iQI9zvy3n0nGfa15+498ir9F5e0 m6A2+mmzBqQB4u2qgX8eH/ipFo0qUUhwryo2EXsJ5kQutTM4PnKM4rcMUhL3GghAHdyX D6Hw== X-Received: by 10.66.172.79 with SMTP id ba15mr7037344pac.26.1381483947113; Fri, 11 Oct 2013 02:32:27 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.94.68 with SMTP id da4ls1443203qeb.24.gmail; Fri, 11 Oct 2013 02:32:27 -0700 (PDT) X-Received: by 10.52.22.110 with SMTP id c14mr17183038vdf.28.1381483946966; Fri, 11 Oct 2013 02:32:26 -0700 (PDT) Received: from mail-vb0-f41.google.com (mail-vb0-f41.google.com [209.85.212.41]) by mx.google.com with ESMTPS id o5si16331059vdw.141.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 11 Oct 2013 02:32:26 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.41 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.41; Received: by mail-vb0-f41.google.com with SMTP id g17so2548983vbg.14 for ; Fri, 11 Oct 2013 02:32:26 -0700 (PDT) X-Gm-Message-State: ALoCoQnmW+Mr4DUQncq2PvVvh5V0f3cS8w3GQXxFXgdPn+IKCJduYE1lKbRHVFtqzeWfZhc2OBo3 X-Received: by 10.220.184.70 with SMTP id cj6mr20584347vcb.23.1381483946818; Fri, 11 Oct 2013 02:32:26 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp23458vcz; Fri, 11 Oct 2013 02:32:26 -0700 (PDT) X-Received: by 10.180.73.113 with SMTP id k17mr2460901wiv.6.1381483945707; Fri, 11 Oct 2013 02:32:25 -0700 (PDT) Received: from mail-wg0-f46.google.com (mail-wg0-f46.google.com [74.125.82.46]) by mx.google.com with ESMTPS id df6si20393055wjc.144.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 11 Oct 2013 02:32:25 -0700 (PDT) Received-SPF: neutral (google.com: 74.125.82.46 is neither permitted nor denied by best guess record for domain of linus.walleij@linaro.org) client-ip=74.125.82.46; Received: by mail-wg0-f46.google.com with SMTP id k14so3929113wgh.25 for ; Fri, 11 Oct 2013 02:32:25 -0700 (PDT) X-Received: by 10.180.72.195 with SMTP id f3mr2314672wiv.51.1381483945162; Fri, 11 Oct 2013 02:32:25 -0700 (PDT) Received: from localhost.localdomain ([85.235.11.236]) by mx.google.com with ESMTPSA id q17sm3863980wiv.10.1969.12.31.16.00.00 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 11 Oct 2013 02:32:24 -0700 (PDT) From: Linus Walleij To: linux-gpio@vger.kernel.org Cc: Alexandre Courbot , Linus Walleij , Enric Balletbo i Serra , Grant Likely , Jean-Christophe PLAGNIOL-VILLARD , Santosh Shilimkar , Stephen Warren Subject: [PATCH 1/2] gpio: add API to be strict about GPIO IRQ usage Date: Fri, 11 Oct 2013 11:32:15 +0200 Message-Id: <1381483935-12165-1-git-send-email-linus.walleij@linaro.org> X-Mailer: git-send-email 1.8.3.1 X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: linus.walleij@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.41 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , It is currently often possible in many GPIO drivers to request a GPIO line to be used as IRQ after calling gpio_to_irq() and, as the gpiolib is not aware of this, set the same line to output and start driving it, with undesired side effects. As it is a bogus usage scenario to request a line flagged as output to used as IRQ, we introduce APIs to let gpiolib track the use of a line as IRQ, and also set this flag from the userspace ABI. The API is symmetric so that lines can also be flagged from .irq_enable() and unflagged from IRQ by .irq_disable(). The debugfs file is altered so that we see if a line is reserved for IRQ. Cc: Enric Balletbo i Serra Cc: Grant Likely Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Santosh Shilimkar Cc: Stephen Warren Reviewed-by: Javier Martinez Canillas Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 88 ++++++++++++++++++++++++++++++++++++++++++++-- include/asm-generic/gpio.h | 3 ++ include/linux/gpio.h | 12 +++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4fc2860..1014cb5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -60,6 +60,7 @@ struct gpio_desc { #define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -96,6 +97,8 @@ static int gpiod_get_value(const struct gpio_desc *desc); static void gpiod_set_value(struct gpio_desc *desc, int value); static int gpiod_cansleep(const struct gpio_desc *desc); static int gpiod_to_irq(const struct gpio_desc *desc); +static int gpiod_lock_as_irq(struct gpio_desc *desc); +static void gpiod_unlock_as_irq(struct gpio_desc *desc); static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); static int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); @@ -163,6 +166,17 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio) } /** + * Convert an offset on a certain chip to a corresponding descriptor + */ +static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, + unsigned int offset) +{ + unsigned int gpio = chip->base + offset; + + return gpio_to_desc(gpio); +} + +/** * Convert a GPIO descriptor to the integer namespace. * This should disappear in the future but is needed since we still * use GPIO numbers for error messages and sysfs nodes @@ -428,6 +442,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { + gpiod_unlock_as_irq(desc); ret = 0; goto free_id; } @@ -466,6 +481,12 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (ret < 0) goto free_id; + ret = gpiod_lock_as_irq(desc); + if (ret < 0) { + gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); + goto free_id; + } + desc->flags |= gpio_flags; return 0; @@ -1730,6 +1751,14 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) return -EINVAL; } + /* GPIOs used for IRQs shall not be set as output */ + if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { + gpiod_err(desc, + "%s: tried to set a GPIO tied to an IRQ as output\n", + __func__); + return -EIO; + } + /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) return gpiod_direction_input(desc); @@ -2050,6 +2079,58 @@ int __gpio_to_irq(unsigned gpio) } EXPORT_SYMBOL_GPL(__gpio_to_irq); +/** + * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ + * @gpio: the GPIO line to lock as used for IRQ + * + * This is used directly by GPIO drivers that want to lock down + * a certain GPIO line to be used as IRQs, for example in the + * .to_irq() callback of their gpio_chip, or in the .irq_enable() + * of its irq_chip implementation if the GPIO is known from that + * code. + */ +static int gpiod_lock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return -EINVAL; + + if (test_bit(FLAG_IS_OUT, &desc->flags)) { + gpiod_err(desc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); + return -EIO; + } + + set_bit(FLAG_USED_AS_IRQ, &desc->flags); + return 0; +} + +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_lock_as_irq); + +/** + * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ + * @gpio: the GPIO line to unlock from IRQ usage + * + * This is used directly by GPIO drivers that want to indicate + * that a certain GPIO is no longer used exclusively for IRQ. + */ +static void gpiod_unlock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return; + + clear_bit(FLAG_USED_AS_IRQ, &desc->flags); +} + +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); /* There's no value in making it easy to inline GPIO calls that may sleep. * Common examples include ones connected to I2C or SPI chips. @@ -2091,6 +2172,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; struct gpio_desc *gdesc = &chip->desc[0]; int is_out; + int is_irq; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) @@ -2098,12 +2180,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", + is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", gpio, gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") - : "? "); + : "? ", + is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index bde6469..b309a5c 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -192,6 +192,9 @@ extern int __gpio_cansleep(unsigned gpio); extern int __gpio_to_irq(unsigned gpio); +extern int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset); +extern void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); + extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 552e3f4..a06ec3e 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -204,6 +204,18 @@ static inline int gpio_to_irq(unsigned gpio) return -EINVAL; } +static inline int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + WARN_ON(1); + return -EINVAL; +} + +static inline void gpio_unlock_as_irq(struct gpio_chip *chip, + unsigned int offset) +{ + WARN_ON(1); +} + static inline int irq_to_gpio(unsigned irq) { /* irq can never have been returned from gpio_to_irq() */