From 3d599d1ca57f443e5c4ff5af1e69d90350082f77 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 15 Oct 2008 22:03:12 -0700 Subject: gpio_free might sleep, generic part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the documentation gpio_free should only be called from task context only. To make this more explicit add a might sleep to all implementations. This is the generic part which changes gpiolib and the fallback implementation only. Signed-off-by: Uwe Kleine-König Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8d2940517c99..317004fd94fb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -792,6 +792,8 @@ void gpio_free(unsigned gpio) unsigned long flags; struct gpio_desc *desc; + might_sleep(); + if (!gpio_is_valid(gpio)) { WARN_ON(extra_checks); return; -- cgit v1.2.3 From 0f6d504e73b49374c6093efe6aa60ab55058248a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 15 Oct 2008 22:03:14 -0700 Subject: gpiolib: gpio_to_irq() hooks Add a new gpiolib mechanism: gpio_chip instances can provide mappings between their (input) GPIOs and any associated IRQs. This makes it easier for platforms to support IRQs that are provided by board-specific external chips instead of as part of their core (such as SOC-integrated GPIOs). Also update the irq_to_gpio() description, saying to avoid it because it's not always supported. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 5 +++-- drivers/gpio/gpiolib.c | 18 ++++++++++++++++++ include/asm-generic/gpio.h | 7 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 18022e249c53..8a7c45956d24 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -264,7 +264,7 @@ map between them using calls like: /* map GPIO numbers to IRQ numbers */ int gpio_to_irq(unsigned gpio); - /* map IRQ numbers to GPIO numbers */ + /* map IRQ numbers to GPIO numbers (avoid using this) */ int irq_to_gpio(unsigned irq); Those return either the corresponding number in the other namespace, or @@ -284,7 +284,8 @@ system wakeup capabilities. Non-error values returned from irq_to_gpio() would most commonly be used with gpio_get_value(), for example to initialize or update driver state -when the IRQ is edge-triggered. +when the IRQ is edge-triggered. Note that some platforms don't support +this reverse mapping, so you should avoid using it. Emulating Open Drain Signals diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 317004fd94fb..29a7e6b1be5d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1010,6 +1010,24 @@ int __gpio_cansleep(unsigned gpio) } EXPORT_SYMBOL_GPL(__gpio_cansleep); +/** + * __gpio_to_irq() - return the IRQ corresponding to a GPIO + * @gpio: gpio whose IRQ will be returned (already requested) + * Context: any + * + * This is used directly or indirectly to implement gpio_to_irq(). + * It returns the number of the IRQ signaled by this (input) GPIO, + * or a negative errno. + */ +int __gpio_to_irq(unsigned gpio) +{ + struct gpio_chip *chip; + + chip = gpio_to_chip(gpio); + return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; +} +EXPORT_SYMBOL_GPL(__gpio_to_irq); + /* There's no value in making it easy to inline GPIO calls that may sleep. diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 2c5744b66dec..04cb1d175df1 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -40,6 +40,8 @@ struct module; * returns either the value actually sensed, or zero * @direction_output: configures signal "offset" as output, or returns error * @set: assigns output value for signal "offset" + * @to_irq: optional hook supporting non-static gpio_to_irq() mappings; + * implementation may not sleep * @dbg_show: optional routine to show contents in debugfs; default code * will be used when this is omitted, but custom code can show extra * state (such as pullup/pulldown configuration). @@ -73,6 +75,10 @@ struct gpio_chip { unsigned offset, int value); void (*set)(struct gpio_chip *chip, unsigned offset, int value); + + int (*to_irq)(struct gpio_chip *chip, + unsigned offset); + void (*dbg_show)(struct seq_file *s, struct gpio_chip *chip); int base; @@ -112,6 +118,7 @@ extern void __gpio_set_value(unsigned gpio, int value); extern int __gpio_cansleep(unsigned gpio); +extern int __gpio_to_irq(unsigned gpio); #ifdef CONFIG_GPIO_SYSFS -- cgit v1.2.3 From 35e8bb5175c1a6ff6253f1a2acb30bfe52a2f500 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 15 Oct 2008 22:03:16 -0700 Subject: gpiolib: request/free hooks Add a new internal mechanism to gpiolib to support low power operations by letting gpio_chip instances see when their GPIOs are in use. When no GPIOs are active, chips may be able to enter lower powered runtime states by disabling clocks and/or power domains. Signed-off-by: David Brownell Cc: "Magnus Damm" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 4 ++ drivers/gpio/gpiolib.c | 91 +++++++++++++++++++++++++++++++++++++++------- include/asm-generic/gpio.h | 9 +++++ 3 files changed, 91 insertions(+), 13 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 8a7c45956d24..b1b988701247 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -240,6 +240,10 @@ signal, or (b) something wrongly believes it's safe to remove drivers needed to manage a signal that's in active use. That is, requesting a GPIO can serve as a kind of lock. +Some platforms may also use knowledge about what GPIOs are active for +power management, such as by powering down unused chip sectors and, more +easily, gating off unused clocks. + These two calls are optional because not not all current Linux platforms offer such functionality in their GPIO support; a valid implementation could return success for all gpio_request() calls. Unlike the other calls, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 29a7e6b1be5d..9112830107a5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -67,17 +67,28 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) * when setting direction, and otherwise illegal. Until board setup code * and drivers use explicit requests everywhere (which won't happen when * those calls have no teeth) we can't avoid autorequesting. This nag - * message should motivate switching to explicit requests... + * message should motivate switching to explicit requests... so should + * the weaker cleanup after faults, compared to gpio_request(). */ -static void gpio_ensure_requested(struct gpio_desc *desc) +static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) { if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { - pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); + struct gpio_chip *chip = desc->chip; + int gpio = chip->base + offset; + + if (!try_module_get(chip->owner)) { + pr_err("GPIO-%d: module can't be gotten \n", gpio); + clear_bit(FLAG_REQUESTED, &desc->flags); + /* lose */ + return -EIO; + } + pr_warning("GPIO-%d autorequested\n", gpio); desc_set_label(desc, "[auto]"); - if (!try_module_get(desc->chip->owner)) - pr_err("GPIO-%d: module can't be gotten \n", - (int)(desc - gpio_desc)); + /* caller must chip->request() w/o spinlock */ + if (chip->request) + return 1; } + return 0; } /* caller holds gpio_lock *OR* gpio is marked as requested */ @@ -752,6 +763,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove); int gpio_request(unsigned gpio, const char *label) { struct gpio_desc *desc; + struct gpio_chip *chip; int status = -EINVAL; unsigned long flags; @@ -760,14 +772,15 @@ int gpio_request(unsigned gpio, const char *label) if (!gpio_is_valid(gpio)) goto done; desc = &gpio_desc[gpio]; - if (desc->chip == NULL) + chip = desc->chip; + if (chip == NULL) goto done; - if (!try_module_get(desc->chip->owner)) + if (!try_module_get(chip->owner)) goto done; /* NOTE: gpio_request() can be called in early boot, - * before IRQs are enabled. + * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { @@ -775,7 +788,20 @@ int gpio_request(unsigned gpio, const char *label) status = 0; } else { status = -EBUSY; - module_put(desc->chip->owner); + module_put(chip->owner); + } + + if (chip->request) { + /* chip->request may sleep */ + spin_unlock_irqrestore(&gpio_lock, flags); + status = chip->request(chip, gpio - chip->base); + spin_lock_irqsave(&gpio_lock, flags); + + if (status < 0) { + desc_set_label(desc, NULL); + module_put(chip->owner); + clear_bit(FLAG_REQUESTED, &desc->flags); + } } done: @@ -791,6 +817,7 @@ void gpio_free(unsigned gpio) { unsigned long flags; struct gpio_desc *desc; + struct gpio_chip *chip; might_sleep(); @@ -804,9 +831,17 @@ void gpio_free(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) { + chip = desc->chip; + if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { + if (chip->free) { + spin_unlock_irqrestore(&gpio_lock, flags); + might_sleep_if(extra_checks && chip->can_sleep); + chip->free(chip, gpio - chip->base); + spin_lock_irqsave(&gpio_lock, flags); + } desc_set_label(desc, NULL); module_put(desc->chip->owner); + clear_bit(FLAG_REQUESTED, &desc->flags); } else WARN_ON(extra_checks); @@ -871,7 +906,9 @@ int gpio_direction_input(unsigned gpio) gpio -= chip->base; if (gpio >= chip->ngpio) goto fail; - gpio_ensure_requested(desc); + status = gpio_ensure_requested(desc, gpio); + if (status < 0) + goto fail; /* now we know the gpio is valid and chip won't vanish */ @@ -879,9 +916,22 @@ int gpio_direction_input(unsigned gpio) might_sleep_if(extra_checks && chip->can_sleep); + if (status) { + status = chip->request(chip, gpio); + if (status < 0) { + pr_debug("GPIO-%d: chip request fail, %d\n", + chip->base + gpio, status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ + goto lose; + } + } + status = chip->direction_input(chip, gpio); if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); +lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); @@ -909,7 +959,9 @@ int gpio_direction_output(unsigned gpio, int value) gpio -= chip->base; if (gpio >= chip->ngpio) goto fail; - gpio_ensure_requested(desc); + status = gpio_ensure_requested(desc, gpio); + if (status < 0) + goto fail; /* now we know the gpio is valid and chip won't vanish */ @@ -917,9 +969,22 @@ int gpio_direction_output(unsigned gpio, int value) might_sleep_if(extra_checks && chip->can_sleep); + if (status) { + status = chip->request(chip, gpio); + if (status < 0) { + pr_debug("GPIO-%d: chip request fail, %d\n", + chip->base + gpio, status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ + goto lose; + } + } + status = chip->direction_output(chip, gpio, value); if (status == 0) set_bit(FLAG_IS_OUT, &desc->flags); +lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 04cb1d175df1..81797ec9ab29 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -35,6 +35,10 @@ struct module; * @label: for diagnostics * @dev: optional device providing the GPIOs * @owner: helps prevent removal of modules exporting active GPIOs + * @request: optional hook for chip-specific activation, such as + * enabling module power and clock; may sleep + * @free: optional hook for chip-specific deactivation, such as + * disabling module power and clock; may sleep * @direction_input: configures signal "offset" as input, or returns error * @get: returns value for signal "offset"; for output signals this * returns either the value actually sensed, or zero @@ -67,6 +71,11 @@ struct gpio_chip { struct device *dev; struct module *owner; + int (*request)(struct gpio_chip *chip, + unsigned offset); + void (*free)(struct gpio_chip *chip, + unsigned offset); + int (*direction_input)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, -- cgit v1.2.3