From 4faf3055079abfb5c7790f38b8708306be3cc4fc Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sat, 9 Nov 2013 14:24:06 +0100 Subject: [PATCH 1/6] led: trigger: disable LEDs with trigger before installing it This disables LEDs that have a trigger function assigned right before the trigger is installed. As the trigger was parsed before the LED has been registered, also swap LED registration and trigger parsing. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- drivers/led/led-gpio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/led/led-gpio.c b/drivers/led/led-gpio.c index 69db70fab..7a5ef473e 100644 --- a/drivers/led/led-gpio.c +++ b/drivers/led/led-gpio.c @@ -225,6 +225,8 @@ static void led_of_parse_trigger(struct led *led, struct device_node *np) for (i = 0; i < ARRAY_SIZE(triggers); i++) { struct led_trg *trg = &triggers[i]; if (!strcmp(trg->str, trigger)) { + /* disable LED before installing trigger */ + led_set(led, 0); led_set_trigger(trg->trg, led); return; } @@ -252,8 +254,8 @@ static int led_gpio_of_probe(struct device_d *dev) dev_dbg(dev, "register led %s on gpio%d, active_low = %d\n", gled->led.name, gled->gpio, gled->active_low); - led_of_parse_trigger(&gled->led, child); led_gpio_register(gled); + led_of_parse_trigger(&gled->led, child); } return 0; From ed4348e8b249b56c493519aefeb72c3a8e92737e Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sat, 9 Nov 2013 14:24:07 +0100 Subject: [PATCH 2/6] gpiolib: add get_direction callback At least for debugging purposes it is helpful to determine the current direction for a given GPIO. Add a callback to gpiochip, to allow to get it. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- include/gpio.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/gpio.h b/include/gpio.h index 140d53c83..708b2aa11 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -3,6 +3,9 @@ #include +#define GPIO_DIR_OUT (0 << 0) +#define GPIO_DIR_IN (1 << 0) + #ifndef CONFIG_GPIOLIB static inline int gpio_request(unsigned gpio, const char *label) { @@ -24,6 +27,7 @@ struct gpio_ops { void (*free)(struct gpio_chip *chip, unsigned offset); int (*direction_input)(struct gpio_chip *chip, unsigned offset); int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value); + int (*get_direction)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, unsigned offset); void (*set)(struct gpio_chip *chip, unsigned offset, int value); }; From fcc25285a2b98afd4e6c2324093b4f52f59a26d3 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sat, 9 Nov 2013 14:24:08 +0100 Subject: [PATCH 3/6] gpiolib: make gpiolib command more verbose This adds some more printf information to gpiolib command, like the gpiochip handling a specific gpio. Also, current direction and value of the gpio are printed, if the gpiochip provides the corresponding callbacks. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- drivers/gpio/gpiolib.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index ca6e8adab..b7db59651 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -228,16 +228,34 @@ static int do_gpiolib(int argc, char *argv[]) int i; printf("gpiolib: gpio lists\n"); - printf("%*crequested label\n", 11, ' '); for (i = 0; i < ARCH_NR_GPIOS; i++) { struct gpio_info *gi = &gpio_desc[i]; + int val = -1, dir = -1; if (!gi->chip) continue; - printf("gpio %*d: %*s %s\n", 4, - i, 9, gi->requested ? "true" : "false", + /* print chip information and header on first gpio */ + if (gi->chip->base == i) { + printf("\ngpios %u-%u, chip %s:\n", + gi->chip->base, + gi->chip->base + gi->chip->ngpio - 1, + gi->chip->dev->name); + printf("%*cdir val requested label\n", 13, ' '); + } + + if (gi->chip->ops->get_direction) + dir = gi->chip->ops->get_direction(gi->chip, + i - gi->chip->base); + if (gi->chip->ops->get) + val = gi->chip->ops->get(gi->chip, + i - gi->chip->base); + + printf(" gpio %*d: %*s %*s %*s %s\n", 4, i, + 3, (dir < 0) ? "unk" : ((dir == GPIO_DIR_IN) ? "in" : "out"), + 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"), + 9, gi->requested ? "true" : "false", gi->label ? gi->label : ""); } From d7fc449a2ea8686f73403922f045b6d39baab27f Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sat, 9 Nov 2013 14:24:09 +0100 Subject: [PATCH 4/6] gpio: dw: add get_direction callback This adds a callback function to read the current state of a GPIOs in/out direction. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- drivers/gpio/gpio-dw.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpio/gpio-dw.c b/drivers/gpio/gpio-dw.c index 791488a19..65770422a 100644 --- a/drivers/gpio/gpio-dw.c +++ b/drivers/gpio/gpio-dw.c @@ -90,9 +90,18 @@ static int dw_gpio_direction_output(struct gpio_chip *gc, return 0; } +static int dw_gpio_get_direction(struct gpio_chip *gc, unsigned offset) +{ + struct dw_gpio_instance *chip = to_dw_gpio(gc); + + return (readl(chip->regs + DW_GPIO_DDR) & (1 << offset)) ? + GPIO_DIR_OUT : GPIO_DIR_IN; +} + static struct gpio_ops imx_gpio_ops = { .direction_input = dw_gpio_direction_input, .direction_output = dw_gpio_direction_output, + .get_direction = dw_gpio_get_direction, .get = dw_gpio_get, .set = dw_gpio_set, }; From 6339a419e91ec16afe02cb9270c487778129aa3c Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Fri, 22 Nov 2013 00:11:23 +0400 Subject: [PATCH 5/6] gpio: unify gpio direction macros names with Linux kernel See linux.git/include/linux/gpio.h and linux.git/Documentation/gpio.txt for details. Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- drivers/gpio/gpio-dw.c | 2 +- drivers/gpio/gpiolib.c | 2 +- include/gpio.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-dw.c b/drivers/gpio/gpio-dw.c index 65770422a..e46cc8e12 100644 --- a/drivers/gpio/gpio-dw.c +++ b/drivers/gpio/gpio-dw.c @@ -95,7 +95,7 @@ static int dw_gpio_get_direction(struct gpio_chip *gc, unsigned offset) struct dw_gpio_instance *chip = to_dw_gpio(gc); return (readl(chip->regs + DW_GPIO_DDR) & (1 << offset)) ? - GPIO_DIR_OUT : GPIO_DIR_IN; + GPIOF_DIR_OUT : GPIOF_DIR_IN; } static struct gpio_ops imx_gpio_ops = { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7db59651..03fc19654 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -253,7 +253,7 @@ static int do_gpiolib(int argc, char *argv[]) i - gi->chip->base); printf(" gpio %*d: %*s %*s %*s %s\n", 4, i, - 3, (dir < 0) ? "unk" : ((dir == GPIO_DIR_IN) ? "in" : "out"), + 3, (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"), 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"), 9, gi->requested ? "true" : "false", gi->label ? gi->label : ""); diff --git a/include/gpio.h b/include/gpio.h index 708b2aa11..f33b43550 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -3,8 +3,8 @@ #include -#define GPIO_DIR_OUT (0 << 0) -#define GPIO_DIR_IN (1 << 0) +#define GPIOF_DIR_OUT (0 << 0) +#define GPIOF_DIR_IN (1 << 0) #ifndef CONFIG_GPIOLIB static inline int gpio_request(unsigned gpio, const char *label) From bcf08772662c47ff69b253c44ac2415507fb9a93 Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Fri, 22 Nov 2013 00:11:24 +0400 Subject: [PATCH 6/6] gpiolib: import gpio_request_array() from linux 3.7 Also import related functions gpio_request_one() and gpio_free_array(). This commit imports code from linux 3.7 as the more recent linux kernel versions use gpiolib descriptors, see this commit for details: commit 372e722ea4dd4ca11c3d04845e11cbc15f32144c Author: Alexandre Courbot Date: Sun Feb 3 01:29:29 2013 +0900 gpiolib: use descriptors internally Make sure gpiolib works internally with descriptors and (chip, offset) pairs instead of using the global integer namespace. This prepares the ground for the removal of the global gpio_desc[] array and the introduction of the descriptor-based GPIO API. Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- drivers/gpio/gpiolib.c | 66 ++++++++++++++++++++++++++++++++++++++++++ include/gpio.h | 39 +++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 03fc19654..cafef907e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -85,6 +85,72 @@ void gpio_free(unsigned gpio) free(gi->label); } +/** + * 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) +{ + int err; + + err = gpio_request(gpio, label); + if (err) + return err; + + if (flags & GPIOF_DIR_IN) + err = gpio_direction_input(gpio); + else + err = gpio_direction_output(gpio, + (flags & GPIOF_INIT_HIGH) ? 1 : 0); + + if (err) + goto free_gpio; + + return 0; + + free_gpio: + 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; + +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); + void gpio_set_value(unsigned gpio, int value) { struct gpio_info *gi = gpio_to_desc(gpio); diff --git a/include/gpio.h b/include/gpio.h index f33b43550..4a97521ae 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -6,6 +6,25 @@ #define GPIOF_DIR_OUT (0 << 0) #define GPIOF_DIR_IN (1 << 0) +#define GPIOF_INIT_LOW (0 << 1) +#define GPIOF_INIT_HIGH (1 << 1) + +#define GPIOF_IN (GPIOF_DIR_IN) +#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW) +#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH) + +/** + * struct gpio - a structure describing a GPIO with configuration + * @gpio: the GPIO number + * @flags: GPIO configuration as specified by GPIOF_* + * @label: a literal description string of this GPIO + */ +struct gpio { + unsigned gpio; + unsigned long flags; + const char *label; +}; + #ifndef CONFIG_GPIOLIB static inline int gpio_request(unsigned gpio, const char *label) { @@ -15,9 +34,29 @@ static inline int gpio_request(unsigned gpio, const char *label) static inline void gpio_free(unsigned gpio) { } + +static inline int gpio_request_one(unsigned gpio, + unsigned long flags, const char *label) +{ + return -ENOSYS; +} + +static inline int gpio_request_array(const struct gpio *array, size_t num) +{ + return -ENOSYS; +} + +static inline void gpio_free_array(const struct gpio *array, size_t num) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} #else int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); +int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); +int gpio_request_array(const struct gpio *array, size_t num); +void gpio_free_array(const struct gpio *array, size_t num); #endif struct gpio_chip;