bcm63xx: add linux v5.15 support
[openwrt/staging/ldir.git] / target / linux / bcm63xx / patches-5.15 / 143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
diff --git a/target/linux/bcm63xx/patches-5.15/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch b/target/linux/bcm63xx/patches-5.15/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
new file mode 100644 (file)
index 0000000..dca7865
--- /dev/null
@@ -0,0 +1,161 @@
+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
+@@ -646,23 +646,30 @@ static struct gpio_desc *of_parse_own_gp
+  * of_gpiochip_add_hog - Add all hogs in a hog device node
+  * @chip:     gpio chip to act on
+  * @hog:      device node describing the hogs
++ * @start:    first gpio to check
++ * @num:      number of gpios to check
+  *
+  * Returns error if it fails otherwise 0 on success.
+  */
+-static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
++static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog,
++                             unsigned int start, unsigned int num)
+ {
+       enum gpiod_flags dflags;
+       struct gpio_desc *desc;
+       unsigned long lflags;
+       const char *name;
+       unsigned int i;
+-      int ret;
++      int ret, hwgpio;
+       for (i = 0;; i++) {
+               desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
+               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)
+                       return ret;
+@@ -678,12 +685,15 @@ static int of_gpiochip_add_hog(struct 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 device_node *np;
+       int ret;
+@@ -692,7 +702,7 @@ static int of_gpiochip_scan_gpios(struct
+               if (!of_property_read_bool(np, "gpio-hog"))
+                       continue;
+-              ret = of_gpiochip_add_hog(chip, np);
++              ret = of_gpiochip_add_hog(chip, np, start, num);
+               if (ret < 0) {
+                       of_node_put(np);
+                       return ret;
+@@ -758,7 +768,7 @@ static int of_gpio_notify(struct notifie
+               if (chip == NULL)
+                       return NOTIFY_OK;       /* not for us */
+-              ret = of_gpiochip_add_hog(chip, rd->dn);
++              ret = of_gpiochip_add_hog(chip, rd->dn, 0, chip->ngpio);
+               if (ret < 0) {
+                       pr_err("%s: failed to add hogs for %pOF\n", __func__,
+                              rd->dn);
+@@ -1030,9 +1040,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
+@@ -1768,7 +1768,8 @@ int gpiochip_add_pingroup_range(struct g
+       list_add_tail(&pin_range->node, &gdev->pin_ranges);
+-      return 0;
++      return of_gpiochip_scan_gpios(gc, gpio_offset,
++                                    pin_range->range.npins);
+ }
+ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
+@@ -1825,7 +1826,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(gc, 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);
+ void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
+@@ -26,6 +28,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;