/branches/18.06.1/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 |