diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 51a8d41..cd16e83 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -49,6 +49,7 @@ struct gpio_desc { #define FLAG_RESERVED 2 #define FLAG_EXPORT 3 /* protected by sysfs_lock */ #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ +#define FLAG_IS_PORT 5 #ifdef CONFIG_DEBUG_FS const char *label; @@ -859,6 +860,84 @@ void gpio_free(unsigned gpio) } EXPORT_SYMBOL_GPL(gpio_free); +int gpio_port_request(unsigned gpio, const char *label) +{ + struct gpio_desc *desc; + struct gpio_chip *chip; + int status = -EINVAL; + unsigned long flags; + unsigned _gpio; + + spin_lock_irqsave(&gpio_lock, flags); + + if (!gpio_is_valid(gpio)) + goto done; + desc = &gpio_desc[gpio]; + chip = desc->chip; + if (chip == NULL) + goto done; + + for (_gpio = chip->base; _gpio < chip->base + chip->ngpio; _gpio++) { + spin_unlock_irqrestore(&gpio_lock, flags); + status = gpio_request(_gpio, label); + if (status < 0) + goto err; + spin_lock_irqsave(&gpio_lock, flags); + + desc = &gpio_desc[_gpio]; + set_bit(FLAG_IS_PORT, &desc->flags); + } + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; + +err: + /* free any GPIOs that may have been successfully requested */ + for ( ; _gpio >= chip->base; _gpio--) + gpio_free(_gpio); + spin_lock_irqsave(&gpio_lock, flags); +done: + pr_debug("gpio_port_request: gpio-%d (%s) status %d\n", + gpio, label ? : "?", status); + spin_unlock_irqrestore(&gpio_lock, flags); + return status; +} +EXPORT_SYMBOL_GPL(gpio_port_request); + +void gpio_port_free(unsigned gpio) +{ + unsigned long flags; + struct gpio_desc *desc; + struct gpio_chip *chip; + unsigned _gpio; + + might_sleep(); + + if (!gpio_is_valid(gpio)) { + WARN_ON(extra_checks); + return; + } + + spin_lock_irqsave(&gpio_lock, flags); + + desc = &gpio_desc[gpio]; + chip = desc->chip; + + for (_gpio = chip->base; _gpio < chip->base + chip->ngpio; _gpio++) { + desc = &gpio_desc[_gpio]; + if (!test_bit(FLAG_IS_PORT, &desc->flags)) + WARN_ON(extra_checks); + + spin_unlock_irqrestore(&gpio_lock, flags); + gpio_free(_gpio); + spin_lock_irqsave(&gpio_lock, flags); + + clear_bit(FLAG_IS_PORT, &desc->flags); + } + spin_unlock_irqrestore(&gpio_lock, flags); +} +EXPORT_SYMBOL_GPL(gpio_port_free); + /** * gpiochip_is_requested - return string iff signal was requested diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index d6c379d..9f7ebd5 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -116,6 +116,9 @@ extern int __must_check gpiochip_remove(struct gpio_chip *chip); extern int gpio_request(unsigned gpio, const char *label); extern void gpio_free(unsigned gpio); +extern int gpio_port_request(unsigned gpio, const char *label); +extern void gpio_port_free(unsigned gpio); + extern int gpio_direction_input(unsigned gpio); extern int gpio_direction_output(unsigned gpio, int value);