From 6d6127e537cd6aacc7bb553b43b548c75b79d286 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jonas.gorski@gmail.com>
Date: Mon, 19 Feb 2018 10:18:06 +0100
Subject: [PATCH] brcm63xx: fix gpio hogs on gpio/pinctrl nodes

Work around a chicken/egg issue in registration of dual gpio/pinctrl
nodes.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
 ...tree-gpio-hogs-on-dual-role-gpio-pin.patch | 127 ++++++++++++++++++
 ...tree-gpio-hogs-on-dual-role-gpio-pin.patch | 126 +++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 target/linux/brcm63xx/patches-4.14/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
 create mode 100644 target/linux/brcm63xx/patches-4.9/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch

diff --git a/target/linux/brcm63xx/patches-4.14/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch b/target/linux/brcm63xx/patches-4.14/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
new file mode 100644
index 0000000000..436f1aa532
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.14/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
@@ -0,0 +1,127 @@
+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
+@@ -237,12 +237,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;
+@@ -250,7 +253,7 @@ static int of_gpiochip_scan_gpios(struct
+ 	enum gpio_lookup_flags 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"))
+@@ -262,6 +265,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);
+@@ -499,7 +506,10 @@ int of_gpiochip_add(struct gpio_chip *ch
+ 
+ 	of_node_get(chip->of_node);
+ 
+-	return of_gpiochip_scan_gpios(chip);
++	if (!chip->request)
++		status = of_gpiochip_scan_gpios(chip, 0, chip->ngpio);
++
++	return status;
+ }
+ 
+ void of_gpiochip_remove(struct gpio_chip *chip)
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1938,7 +1938,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);
+ 
+@@ -1990,7 +1991,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.h
++++ b/drivers/gpio/gpiolib.h
+@@ -99,6 +99,8 @@ struct gpio_desc *of_get_named_gpiod_fla
+ 		   const char *list_name, int index, enum of_gpio_flags *flags);
+ 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);
+ #else
+ static inline struct gpio_desc *of_find_gpio(struct device *dev,
+ 					     const char *con_id,
+@@ -114,6 +116,12 @@ static inline struct gpio_desc *of_get_n
+ }
+ 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;
++}
+ #endif /* CONFIG_OF_GPIO */
+ 
+ #ifdef CONFIG_ACPI
diff --git a/target/linux/brcm63xx/patches-4.9/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch b/target/linux/brcm63xx/patches-4.9/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
new file mode 100644
index 0000000000..5028941451
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.9/143-gpio-fix-device-tree-gpio-hogs-on-dual-role-gpio-pin.patch
@@ -0,0 +1,126 @@
+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
+@@ -274,19 +274,22 @@ static void of_gpiochip_set_names(struct
+ /**
+  * 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 retures 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;
+ 	const char *name;
+ 	enum gpio_lookup_flags lflags;
+ 	enum gpiod_flags dflags;
+-	int ret;
++	int ret, hwgpio;
+ 
+ 	for_each_available_child_of_node(chip->of_node, np) {
+ 		if (!of_property_read_bool(np, "gpio-hog"))
+@@ -296,6 +299,10 @@ static int of_gpiochip_scan_gpios(struct
+ 		if (IS_ERR(desc))
+ 			continue;
+ 
++		hwgpio = gpio_chip_hwgpio(desc);
++		if (hwgpio < start || hwgpio >= (start + num))
++			continue;
++
+ 		ret = gpiod_hog(desc, name, lflags, dflags);
+ 		if (ret < 0)
+ 			return ret;
+@@ -531,7 +538,10 @@ int of_gpiochip_add(struct gpio_chip *ch
+ 
+ 	of_node_get(chip->of_node);
+ 
+-	return of_gpiochip_scan_gpios(chip);
++	if (!chip->request)
++		status = of_gpiochip_scan_gpios(chip, 0, chip->ngpio);
++
++	return status;
+ }
+ 
+ void of_gpiochip_remove(struct gpio_chip *chip)
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1884,7 +1884,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);
+ 
+@@ -1933,7 +1934,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.h
++++ b/drivers/gpio/gpiolib.h
+@@ -96,6 +96,8 @@ struct gpio_desc *of_get_named_gpiod_fla
+ 		   const char *list_name, int index, enum of_gpio_flags *flags);
+ 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);
+ #else
+ static inline struct gpio_desc *of_find_gpio(struct device *dev,
+ 					     const char *con_id,
+@@ -111,6 +113,12 @@ static inline struct gpio_desc *of_get_n
+ }
+ 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;
++}
+ #endif /* CONFIG_OF_GPIO */
+ 
+ #ifdef CONFIG_ACPI
-- 
2.30.2