diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 111 |
1 files changed, 99 insertions, 12 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index eb0c3fe44b29..6a6bd569e1f8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -8,6 +8,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/idr.h> #include <linux/slab.h> @@ -399,7 +400,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, goto free_id; } - pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); + pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value"); if (!pdesc->value_sd) { ret = -ENODEV; goto free_id; @@ -722,7 +723,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) unsigned long flags; struct gpio_desc *desc; int status = -EINVAL; - char *ioname = NULL; + const char *ioname = NULL; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -753,7 +754,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) struct device *dev; dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%d", gpio); + desc, ioname ? ioname : "gpio%u", gpio); if (!IS_ERR(dev)) { status = sysfs_create_group(&dev->kobj, &gpio_attr_group); @@ -893,10 +894,12 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); void gpio_unexport(unsigned gpio) { struct gpio_desc *desc; - int status = -EINVAL; + int status = 0; - if (!gpio_is_valid(gpio)) + if (!gpio_is_valid(gpio)) { + status = -EINVAL; goto done; + } mutex_lock(&sysfs_lock); @@ -911,7 +914,6 @@ void gpio_unexport(unsigned gpio) clear_bit(FLAG_EXPORT, &desc->flags); put_device(dev); device_unregister(dev); - status = 0; } else status = -ENODEV; } @@ -1099,16 +1101,24 @@ int gpiochip_add(struct gpio_chip *chip) } } + of_gpiochip_add(chip); + unlock: spin_unlock_irqrestore(&gpio_lock, flags); - if (status == 0) - status = gpiochip_export(chip); + + if (status) + goto fail; + + status = gpiochip_export(chip); + if (status) + goto fail; + + return 0; fail: /* failures here can mean systems won't boot... */ - if (status) - pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n", - chip->base, chip->base + chip->ngpio - 1, - chip->label ? : "generic"); + pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", + chip->base, chip->base + chip->ngpio - 1, + chip->label ? : "generic"); return status; } EXPORT_SYMBOL_GPL(gpiochip_add); @@ -1127,6 +1137,8 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + of_gpiochip_remove(chip); + for (id = chip->base; id < chip->base + chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { status = -EBUSY; @@ -1147,6 +1159,38 @@ int gpiochip_remove(struct gpio_chip *chip) } EXPORT_SYMBOL_GPL(gpiochip_remove); +/** + * gpiochip_find() - iterator for locating a specific gpio_chip + * @data: data to pass to match function + * @callback: Callback function to check gpio_chip + * + * Similar to bus_find_device. It returns a reference to a gpio_chip as + * determined by a user supplied @match callback. The callback should return + * 0 if the device doesn't match and non-zero if it does. If the callback is + * non-zero, this function will return to the caller and not iterate over any + * more gpio_chips. + */ +struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *chip, void *data)) +{ + struct gpio_chip *chip = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&gpio_lock, flags); + for (i = 0; i < ARCH_NR_GPIOS; i++) { + if (!gpio_desc[i].chip) + continue; + + if (match(gpio_desc[i].chip, data)) { + chip = gpio_desc[i].chip; + break; + } + } + spin_unlock_irqrestore(&gpio_lock, flags); + + return chip; +} /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. @@ -1447,6 +1491,49 @@ fail: } EXPORT_SYMBOL_GPL(gpio_direction_output); +/** + * gpio_set_debounce - sets @debounce time for a @gpio + * @gpio: the gpio to set debounce time + * @debounce: debounce time is microseconds + */ +int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + unsigned long flags; + struct gpio_chip *chip; + struct gpio_desc *desc = &gpio_desc[gpio]; + int status = -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); + + if (!gpio_is_valid(gpio)) + goto fail; + chip = desc->chip; + if (!chip || !chip->set || !chip->set_debounce) + goto fail; + gpio -= chip->base; + if (gpio >= chip->ngpio) + goto fail; + status = gpio_ensure_requested(desc, gpio); + if (status < 0) + goto fail; + + /* now we know the gpio is valid and chip won't vanish */ + + spin_unlock_irqrestore(&gpio_lock, flags); + + might_sleep_if(extra_checks && chip->can_sleep); + + return chip->set_debounce(chip, gpio, debounce); + +fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) + pr_debug("%s: gpio-%d status %d\n", + __func__, gpio, status); + + return status; +} +EXPORT_SYMBOL_GPL(gpio_set_debounce); /* I/O calls are only valid after configuration completed; the relevant * "is this a valid GPIO" error checks should already have been done. |