Add code to support 'gpio-hog' nodes used in some .dts files in Linux kernel. Cc: cphealy@xxxxxxxxx Cc: Nikita Yushchenko <nikita.yoush@xxxxxxxxxxxxxxxxxx> Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> --- drivers/gpio/gpiolib.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 28f6a5e..a3e17ad 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -5,6 +5,7 @@ #include <command.h> #include <complete.h> #include <gpio.h> +#include <of_gpio.h> #include <errno.h> #include <malloc.h> @@ -304,6 +305,99 @@ static int gpiochip_find_base(int start, int ngpio) return base; } +static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip, + unsigned int idx) +{ + struct device_node *chip_np = chip->dev->device_node; + unsigned long flags = 0; + u32 gpio_cells, gpio_num, gpio_flags; + int ret, gpio; + const char *name = NULL; + + ret = of_property_read_u32(chip_np, "#gpio-cells", &gpio_cells); + if (ret) + return ret; + + /* + * Support for GPIOs that don't have #gpio-cells set to 2 is + * not implemented + */ + if (WARN_ON(gpio_cells != 2)) + return -ENOTSUPP; + + ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells, + &gpio_num); + if (ret) + return ret; + + ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells + 1, + &gpio_flags); + if (ret) + return ret; + + if (gpio_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + gpio = gpio_get_num(chip->dev, gpio_num); + if (ret == -EPROBE_DEFER) + return ret; + + if (ret < 0) { + dev_err(chip->dev, "unable to get gpio %u\n", gpio_num); + return ret; + } + + + /* + * Note that, in order to be compatible with Linux, the code + * below interprets 'output-high' as to mean 'output-active'. + * That is, when processed for active-low GPIO, it will result + * in output being asserted logically 'active', but physically + * 'low'. + * + * Conversely it means that specifying 'output-low' for + * 'active-low' GPIO would result in 'high' level observed on + * the corresponding pin + * + */ + if (of_property_read_bool(np, "input")) + flags |= GPIOF_DIR_IN; + else if (of_property_read_bool(np, "output-low")) + flags |= GPIOF_OUT_INIT_INACTIVE; + else if (of_property_read_bool(np, "output-high")) + flags |= GPIOF_OUT_INIT_ACTIVE; + else + return -EINVAL; + + of_property_read_string(np, "line-name", &name); + + return gpio_request_one(gpio, flags, name); +} + +static int of_gpiochip_scan_hogs(struct gpio_chip *chip) +{ + struct device_node *np; + int ret, i; + + for_each_available_child_of_node(chip->dev->device_node, np) { + if (!of_property_read_bool(np, "gpio-hog")) + continue; + + for (ret = 0, i = 0; + !ret; + ret = of_hog_gpio(np, chip, i), i++) + ; + /* + * We ignore -EOVERFLOW because it serves us as an + * indicator that there's no more GPIOs to handle. + */ + if (ret < 0 && ret != -EOVERFLOW) + return ret; + } + + return 0; +} + int gpiochip_add(struct gpio_chip *chip) { int base, i; @@ -322,7 +416,7 @@ int gpiochip_add(struct gpio_chip *chip) for (i = chip->base; i < chip->base + chip->ngpio; i++) gpio_desc[i].chip = chip; - return 0; + return of_gpiochip_scan_hogs(chip); } void gpiochip_remove(struct gpio_chip *chip) -- 2.9.4 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox