| From e058fa1969019c2f6705c53c4130e364a877d4e6 Mon Sep 17 00:00:00 2001 |
| From: Jonas Gorski <jonas.gorski@gmail.com> |
| Date: Sun, 26 Nov 2017 12:07:31 +0100 |
| Subject: [PATCH] gpio: fix device tree gpio hogs on dual role gpio/pincontrol |
| controllers |
| |
| For dual role gpio and pincontrol controller, the device registration |
| path is often: |
| |
| pinctrl_register(...); |
| gpiochip_add_data(...); |
| gpiochip_add_pin_range(...); |
| |
| If the device tree node has any gpio-hogs, the code will try to apply them |
| in the gpiochip_add_data step, but fail as they cannot be requested, as the |
| ranges are missing. But we also cannot first add the pinranges, as the |
| appropriate data structures are only initialized in gpiochip_add_data. |
| |
| To fix this, defer gpio-hogs to the time pin ranges get added instead of |
| directly at chip request time, if the gpio-chip has a request method. |
| |
| Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> |
| --- |
| |
| drivers/gpio/gpiolib-of.c | 20 +++++++++++++++----- |
| drivers/gpio/gpiolib.c | 5 +++-- |
| drivers/gpio/gpiolib.h | 8 ++++++++ |
| 3 files changed, 26 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/gpio/gpiolib-of.c |
| +++ b/drivers/gpio/gpiolib-of.c |
| @@ -621,12 +621,15 @@ static struct gpio_desc *of_parse_own_gp |
| /** |
| * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions |
| * @chip: gpio chip to act on |
| + * @start: first gpio to check |
| + * @num: number of gpios to check |
| * |
| - * This is only used by of_gpiochip_add to request/set GPIO initial |
| - * configuration. |
| + * This is used by of_gpiochip_add, gpiochip_add_pingroup_range and |
| + * gpiochip_add_pin_range to request/set GPIO initial configuration. |
| * It returns error if it fails otherwise 0 on success. |
| */ |
| -static int of_gpiochip_scan_gpios(struct gpio_chip *chip) |
| +int of_gpiochip_scan_gpios(struct gpio_chip *chip, unsigned int start, |
| + unsigned int num) |
| { |
| struct gpio_desc *desc = NULL; |
| struct device_node *np; |
| @@ -634,7 +637,7 @@ static int of_gpiochip_scan_gpios(struct |
| unsigned long lflags; |
| enum gpiod_flags dflags; |
| unsigned int i; |
| - int ret; |
| + int ret, hwgpio; |
| |
| for_each_available_child_of_node(chip->of_node, np) { |
| if (!of_property_read_bool(np, "gpio-hog")) |
| @@ -646,6 +649,10 @@ static int of_gpiochip_scan_gpios(struct |
| if (IS_ERR(desc)) |
| break; |
| |
| + hwgpio = gpio_chip_hwgpio(desc); |
| + if (hwgpio < start || hwgpio >= (start + num)) |
| + continue; |
| + |
| ret = gpiod_hog(desc, name, lflags, dflags); |
| if (ret < 0) { |
| of_node_put(np); |
| @@ -906,9 +913,11 @@ int of_gpiochip_add(struct gpio_chip *ch |
| |
| of_node_get(chip->of_node); |
| |
| - ret = of_gpiochip_scan_gpios(chip); |
| - if (ret) |
| - of_node_put(chip->of_node); |
| + if (!chip->request) { |
| + ret = of_gpiochip_scan_gpios(chip, 0, chip->ngpio); |
| + if (ret) |
| + of_node_put(chip->of_node); |
| + } |
| |
| return ret; |
| } |
| --- a/drivers/gpio/gpiolib.c |
| +++ b/drivers/gpio/gpiolib.c |
| @@ -2580,7 +2580,8 @@ int gpiochip_add_pingroup_range(struct g |
| |
| list_add_tail(&pin_range->node, &gdev->pin_ranges); |
| |
| - return 0; |
| + return of_gpiochip_scan_gpios(chip, gpio_offset, |
| + pin_range->range.npins); |
| } |
| EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); |
| |
| @@ -2637,7 +2638,7 @@ int gpiochip_add_pin_range(struct gpio_c |
| |
| list_add_tail(&pin_range->node, &gdev->pin_ranges); |
| |
| - return 0; |
| + return of_gpiochip_scan_gpios(chip, gpio_offset, npins); |
| } |
| EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); |
| |
| --- a/drivers/gpio/gpiolib-of.h |
| +++ b/drivers/gpio/gpiolib-of.h |
| @@ -13,6 +13,8 @@ struct gpio_desc *of_find_gpio(struct de |
| unsigned long *lookupflags); |
| int of_gpiochip_add(struct gpio_chip *gc); |
| void of_gpiochip_remove(struct gpio_chip *gc); |
| +int of_gpiochip_scan_gpios(struct gpio_chip *chip, unsigned int start, |
| + unsigned int num); |
| int of_gpio_get_count(struct device *dev, const char *con_id); |
| bool of_gpio_need_valid_mask(const struct gpio_chip *gc); |
| #else |
| @@ -25,6 +27,12 @@ static inline struct gpio_desc *of_find_ |
| } |
| static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } |
| static inline void of_gpiochip_remove(struct gpio_chip *gc) { } |
| +static inline int of_gpiochip_scan_gpios(struct gpio_chip *chip, |
| + unsigned int start, |
| + unsigned int num) |
| +{ |
| + return 0; |
| +} |
| static inline int of_gpio_get_count(struct device *dev, const char *con_id) |
| { |
| return 0; |