diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 115 |
1 files changed, 100 insertions, 15 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 572d372899d..faa1cc66e9c 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 */ @@ -237,7 +248,7 @@ static ssize_t gpio_value_show(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else - status = sprintf(buf, "%d\n", gpio_get_value_cansleep(gpio)); + status = sprintf(buf, "%d\n", !!gpio_get_value_cansleep(gpio)); mutex_unlock(&sysfs_lock); return status; @@ -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,9 @@ void gpio_free(unsigned gpio) { unsigned long flags; struct gpio_desc *desc; + struct gpio_chip *chip; + + might_sleep(); if (!gpio_is_valid(gpio)) { WARN_ON(extra_checks); @@ -802,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); @@ -869,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 */ @@ -877,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); @@ -907,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 */ @@ -915,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); @@ -1008,6 +1075,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. @@ -1020,7 +1105,7 @@ int gpio_get_value_cansleep(unsigned gpio) might_sleep_if(extra_checks); chip = gpio_to_chip(gpio); - return chip->get(chip, gpio - chip->base); + return chip->get ? chip->get(chip, gpio - chip->base) : 0; } EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); |