diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 245 |
1 files changed, 151 insertions, 94 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9764ddf0f0..27674af54c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -48,6 +48,11 @@ static struct gpio_info *gpio_to_desc(unsigned gpio) return NULL; } +static unsigned gpioinfo_chip_offset(struct gpio_info *gi) +{ + return (gi - gpio_desc) - gi->chip->base; +} + static int gpio_adjust_value(struct gpio_info *gi, int value) { @@ -57,16 +62,10 @@ static int gpio_adjust_value(struct gpio_info *gi, return !!value ^ gi->active_low; } -int gpio_request(unsigned gpio, const char *label) +static int gpioinfo_request(struct gpio_info *gi, const char *label) { - struct gpio_info *gi = gpio_to_desc(gpio); int ret; - if (!gi) { - ret = -ENODEV; - goto done; - } - if (gi->requested) { ret = -EBUSY; goto done; @@ -75,7 +74,8 @@ int gpio_request(unsigned gpio, const char *label) ret = 0; if (gi->chip->ops->request) { - ret = gi->chip->ops->request(gi->chip, gpio - gi->chip->base); + ret = gi->chip->ops->request(gi->chip, + gpioinfo_chip_offset(gi)); if (ret) goto done; } @@ -86,8 +86,8 @@ int gpio_request(unsigned gpio, const char *label) done: if (ret) - pr_err("_gpio_request: gpio-%d (%s) status %d\n", - gpio, label ? : "?", ret); + pr_err("_gpio_request: gpio-%td (%s) status %d\n", + gi - gpio_desc, label ? : "?", ret); return ret; } @@ -126,18 +126,26 @@ int gpio_find_by_name(const char *name) return -ENOENT; } -void gpio_free(unsigned gpio) +int gpio_request(unsigned gpio, const char *label) { struct gpio_info *gi = gpio_to_desc(gpio); - if (!gi) - return; + if (!gi) { + pr_err("_gpio_request: gpio-%d (%s) status %d\n", + gpio, label ? : "?", -ENODEV); + return -ENODEV; + } + + return gpioinfo_request(gi, label); +} +static void gpioinfo_free(struct gpio_info *gi) +{ if (!gi->requested) return; if (gi->chip->ops->free) - gi->chip->ops->free(gi->chip, gpio - gi->chip->base); + gi->chip->ops->free(gi->chip, gpioinfo_chip_offset(gi)); gi->requested = false; gi->active_low = false; @@ -145,81 +153,21 @@ void gpio_free(unsigned gpio) gi->label = NULL; } -/** - * gpio_request_one - request a single GPIO with initial configuration - * @gpio: the GPIO number - * @flags: GPIO configuration as specified by GPIOF_* - * @label: a literal description string of this GPIO - */ -int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) +void gpio_free(unsigned gpio) { - int err; struct gpio_info *gi = gpio_to_desc(gpio); - /* - * Not all of the flags below are mulit-bit, but, for the sake - * of consistency, the code is written as if all of them were. - */ - const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW; - const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN; - const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL; - const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE; - const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH; - - err = gpio_request(gpio, label); - if (err) - return err; - - gi->active_low = active_low; - - if (dir_in) - err = gpio_direction_input(gpio); - else if (logical) - err = gpio_direction_active(gpio, init_active); - else - err = gpio_direction_output(gpio, init_high); - - if (err) - gpio_free(gpio); - - return err; -} -EXPORT_SYMBOL_GPL(gpio_request_one); - -/** - * gpio_request_array - request multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - */ -int gpio_request_array(const struct gpio *array, size_t num) -{ - int i, err; - - for (i = 0; i < num; i++, array++) { - err = gpio_request_one(array->gpio, array->flags, array->label); - if (err) - goto err_free; - } - return 0; + if (!gi) + return; -err_free: - while (i--) - gpio_free((--array)->gpio); - return err; + gpioinfo_free(gi); } -EXPORT_SYMBOL_GPL(gpio_request_array); -/** - * gpio_free_array - release multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - */ -void gpio_free_array(const struct gpio *array, size_t num) +static void gpioinfo_set_value(struct gpio_info *gi, int value) { - while (num--) - gpio_free((array++)->gpio); + if (gi->chip->ops->set) + gi->chip->ops->set(gi->chip, gpioinfo_chip_offset(gi), value); } -EXPORT_SYMBOL_GPL(gpio_free_array); void gpio_set_value(unsigned gpio, int value) { @@ -231,8 +179,7 @@ void gpio_set_value(unsigned gpio, int value) if (gpio_ensure_requested(gi, gpio)) return; - if (gi->chip->ops->set) - gi->chip->ops->set(gi->chip, gpio - gi->chip->base, value); + gpioinfo_set_value(gi, value); } EXPORT_SYMBOL(gpio_set_value); @@ -247,6 +194,14 @@ void gpio_set_active(unsigned gpio, bool value) } EXPORT_SYMBOL(gpio_set_active); +static int gpioinfo_get_value(struct gpio_info *gi) +{ + if (!gi->chip->ops->get) + return -ENOSYS; + + return gi->chip->ops->get(gi->chip, gpioinfo_chip_offset(gi)); +} + int gpio_get_value(unsigned gpio) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -259,9 +214,7 @@ int gpio_get_value(unsigned gpio) if (ret) return ret; - if (!gi->chip->ops->get) - return -ENOSYS; - return gi->chip->ops->get(gi->chip, gpio - gi->chip->base); + return gpioinfo_get_value(gi); } EXPORT_SYMBOL(gpio_get_value); @@ -276,6 +229,15 @@ int gpio_is_active(unsigned gpio) } EXPORT_SYMBOL(gpio_is_active); +static int gpioinfo_direction_output(struct gpio_info *gi, int value) +{ + if (!gi->chip->ops->direction_output) + return -ENOSYS; + + return gi->chip->ops->direction_output(gi->chip, + gpioinfo_chip_offset(gi), value); +} + int gpio_direction_output(unsigned gpio, int value) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -288,13 +250,15 @@ int gpio_direction_output(unsigned gpio, int value) if (ret) return ret; - if (!gi->chip->ops->direction_output) - return -ENOSYS; - return gi->chip->ops->direction_output(gi->chip, gpio - gi->chip->base, - value); + return gpioinfo_direction_output(gi, value); } EXPORT_SYMBOL(gpio_direction_output); +static int gpioinfo_direction_active(struct gpio_info *gi, bool value) +{ + return gpioinfo_direction_output(gi, gpio_adjust_value(gi, value)); +} + int gpio_direction_active(unsigned gpio, bool value) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -302,10 +266,19 @@ int gpio_direction_active(unsigned gpio, bool value) if (!gi) return -ENODEV; - return gpio_direction_output(gpio, gpio_adjust_value(gi, value)); + return gpioinfo_direction_active(gi, value); } EXPORT_SYMBOL(gpio_direction_active); +static int gpioinfo_direction_input(struct gpio_info *gi) +{ + if (!gi->chip->ops->direction_input) + return -ENOSYS; + + return gi->chip->ops->direction_input(gi->chip, + gpioinfo_chip_offset(gi)); +} + int gpio_direction_input(unsigned gpio) { struct gpio_info *gi = gpio_to_desc(gpio); @@ -318,12 +291,96 @@ int gpio_direction_input(unsigned gpio) if (ret) return ret; - if (!gi->chip->ops->direction_input) - return -ENOSYS; - return gi->chip->ops->direction_input(gi->chip, gpio - gi->chip->base); + return gpioinfo_direction_input(gi); } EXPORT_SYMBOL(gpio_direction_input); +static int gpioinfo_request_one(struct gpio_info *gi, unsigned long flags, + const char *label) +{ + int err; + + /* + * Not all of the flags below are mulit-bit, but, for the sake + * of consistency, the code is written as if all of them were. + */ + const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW; + const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN; + const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL; + const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE; + const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH; + + err = gpioinfo_request(gi, label); + if (err) + return err; + + gi->active_low = active_low; + + if (dir_in) + err = gpioinfo_direction_input(gi); + else if (logical) + err = gpioinfo_direction_active(gi, init_active); + else + err = gpioinfo_direction_output(gi, init_high); + + if (err) + gpioinfo_free(gi); + + return err; +} + +/** + * gpio_request_one - request a single GPIO with initial configuration + * @gpio: the GPIO number + * @flags: GPIO configuration as specified by GPIOF_* + * @label: a literal description string of this GPIO + */ +int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) +{ + struct gpio_info *gi = gpio_to_desc(gpio); + + if (!gi) + return -ENODEV; + + return gpioinfo_request_one(gi, flags, label); +} +EXPORT_SYMBOL_GPL(gpio_request_one); + +/** + * gpio_request_array - request multiple GPIOs in a single call + * @array: array of the 'struct gpio' + * @num: how many GPIOs in the array + */ +int gpio_request_array(const struct gpio *array, size_t num) +{ + int i, err; + + for (i = 0; i < num; i++, array++) { + err = gpio_request_one(array->gpio, array->flags, array->label); + if (err) + goto err_free; + } + return 0; + +err_free: + while (i--) + gpio_free((--array)->gpio); + return err; +} +EXPORT_SYMBOL_GPL(gpio_request_array); + +/** + * gpio_free_array - release multiple GPIOs in a single call + * @array: array of the 'struct gpio' + * @num: how many GPIOs in the array + */ +void gpio_free_array(const struct gpio *array, size_t num) +{ + while (num--) + gpio_free((array++)->gpio); +} +EXPORT_SYMBOL_GPL(gpio_free_array); + static int gpiochip_find_base(int start, int ngpio) { int i; |