| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From e058fa1969019c2f6705c53c4130e364a877d4e6 Mon Sep 17 00:00:00 2001 | 
|  | 2 | From: Jonas Gorski <jonas.gorski@gmail.com> | 
|  | 3 | Date: Sun, 26 Nov 2017 12:07:31 +0100 | 
|  | 4 | Subject: [PATCH] gpio: fix device tree gpio hogs on dual role gpio/pincontrol | 
|  | 5 | controllers | 
|  | 6 |  | 
|  | 7 | For dual role gpio and pincontrol controller, the device registration | 
|  | 8 | path is often: | 
|  | 9 |  | 
|  | 10 | pinctrl_register(...); | 
|  | 11 | gpiochip_add_data(...); | 
|  | 12 | gpiochip_add_pin_range(...); | 
|  | 13 |  | 
|  | 14 | If the device tree node has any gpio-hogs, the code will try to apply them | 
|  | 15 | in the gpiochip_add_data step, but fail as they cannot be requested, as the | 
|  | 16 | ranges are missing. But we also cannot first add the pinranges, as the | 
|  | 17 | appropriate data structures are only initialized in gpiochip_add_data. | 
|  | 18 |  | 
|  | 19 | To fix this, defer gpio-hogs to the time pin ranges get added instead of | 
|  | 20 | directly at chip request time, if the gpio-chip has a request method. | 
|  | 21 |  | 
|  | 22 | Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> | 
|  | 23 | --- | 
|  | 24 |  | 
|  | 25 | drivers/gpio/gpiolib-of.c | 20 +++++++++++++++----- | 
|  | 26 | drivers/gpio/gpiolib.c    |  5 +++-- | 
|  | 27 | drivers/gpio/gpiolib.h    |  8 ++++++++ | 
|  | 28 | 3 files changed, 26 insertions(+), 7 deletions(-) | 
|  | 29 |  | 
|  | 30 | --- a/drivers/gpio/gpiolib-of.c | 
|  | 31 | +++ b/drivers/gpio/gpiolib-of.c | 
|  | 32 | @@ -621,12 +621,15 @@ static struct gpio_desc *of_parse_own_gp | 
|  | 33 | /** | 
|  | 34 | * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions | 
|  | 35 | * @chip:	gpio chip to act on | 
|  | 36 | + * @start:	first gpio to check | 
|  | 37 | + * @num:	number of gpios to check | 
|  | 38 | * | 
|  | 39 | - * This is only used by of_gpiochip_add to request/set GPIO initial | 
|  | 40 | - * configuration. | 
|  | 41 | + * This is used by of_gpiochip_add, gpiochip_add_pingroup_range and | 
|  | 42 | + * gpiochip_add_pin_range to request/set GPIO initial configuration. | 
|  | 43 | * It returns error if it fails otherwise 0 on success. | 
|  | 44 | */ | 
|  | 45 | -static int of_gpiochip_scan_gpios(struct gpio_chip *chip) | 
|  | 46 | +int of_gpiochip_scan_gpios(struct gpio_chip *chip, unsigned int start, | 
|  | 47 | +			   unsigned int num) | 
|  | 48 | { | 
|  | 49 | struct gpio_desc *desc = NULL; | 
|  | 50 | struct device_node *np; | 
|  | 51 | @@ -634,7 +637,7 @@ static int of_gpiochip_scan_gpios(struct | 
|  | 52 | unsigned long lflags; | 
|  | 53 | enum gpiod_flags dflags; | 
|  | 54 | unsigned int i; | 
|  | 55 | -	int ret; | 
|  | 56 | +	int ret, hwgpio; | 
|  | 57 |  | 
|  | 58 | for_each_available_child_of_node(chip->of_node, np) { | 
|  | 59 | if (!of_property_read_bool(np, "gpio-hog")) | 
|  | 60 | @@ -646,6 +649,10 @@ static int of_gpiochip_scan_gpios(struct | 
|  | 61 | if (IS_ERR(desc)) | 
|  | 62 | break; | 
|  | 63 |  | 
|  | 64 | +			hwgpio = gpio_chip_hwgpio(desc); | 
|  | 65 | +			if (hwgpio < start || hwgpio >= (start + num)) | 
|  | 66 | +				continue; | 
|  | 67 | + | 
|  | 68 | ret = gpiod_hog(desc, name, lflags, dflags); | 
|  | 69 | if (ret < 0) { | 
|  | 70 | of_node_put(np); | 
|  | 71 | @@ -906,9 +913,11 @@ int of_gpiochip_add(struct gpio_chip *ch | 
|  | 72 |  | 
|  | 73 | of_node_get(chip->of_node); | 
|  | 74 |  | 
|  | 75 | -	ret = of_gpiochip_scan_gpios(chip); | 
|  | 76 | -	if (ret) | 
|  | 77 | -		of_node_put(chip->of_node); | 
|  | 78 | +	if (!chip->request) { | 
|  | 79 | +		ret = of_gpiochip_scan_gpios(chip, 0, chip->ngpio); | 
|  | 80 | +		if (ret) | 
|  | 81 | +			of_node_put(chip->of_node); | 
|  | 82 | +	} | 
|  | 83 |  | 
|  | 84 | return ret; | 
|  | 85 | } | 
|  | 86 | --- a/drivers/gpio/gpiolib.c | 
|  | 87 | +++ b/drivers/gpio/gpiolib.c | 
|  | 88 | @@ -2580,7 +2580,8 @@ int gpiochip_add_pingroup_range(struct g | 
|  | 89 |  | 
|  | 90 | list_add_tail(&pin_range->node, &gdev->pin_ranges); | 
|  | 91 |  | 
|  | 92 | -	return 0; | 
|  | 93 | +	return of_gpiochip_scan_gpios(chip, gpio_offset, | 
|  | 94 | +				      pin_range->range.npins); | 
|  | 95 | } | 
|  | 96 | EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); | 
|  | 97 |  | 
|  | 98 | @@ -2637,7 +2638,7 @@ int gpiochip_add_pin_range(struct gpio_c | 
|  | 99 |  | 
|  | 100 | list_add_tail(&pin_range->node, &gdev->pin_ranges); | 
|  | 101 |  | 
|  | 102 | -	return 0; | 
|  | 103 | +	return of_gpiochip_scan_gpios(chip, gpio_offset, npins); | 
|  | 104 | } | 
|  | 105 | EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); | 
|  | 106 |  | 
|  | 107 | --- a/drivers/gpio/gpiolib-of.h | 
|  | 108 | +++ b/drivers/gpio/gpiolib-of.h | 
|  | 109 | @@ -13,6 +13,8 @@ struct gpio_desc *of_find_gpio(struct de | 
|  | 110 | unsigned long *lookupflags); | 
|  | 111 | int of_gpiochip_add(struct gpio_chip *gc); | 
|  | 112 | void of_gpiochip_remove(struct gpio_chip *gc); | 
|  | 113 | +int of_gpiochip_scan_gpios(struct gpio_chip *chip, unsigned int start, | 
|  | 114 | +			   unsigned int num); | 
|  | 115 | int of_gpio_get_count(struct device *dev, const char *con_id); | 
|  | 116 | bool of_gpio_need_valid_mask(const struct gpio_chip *gc); | 
|  | 117 | #else | 
|  | 118 | @@ -25,6 +27,12 @@ static inline struct gpio_desc *of_find_ | 
|  | 119 | } | 
|  | 120 | static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } | 
|  | 121 | static inline void of_gpiochip_remove(struct gpio_chip *gc) { } | 
|  | 122 | +static inline int of_gpiochip_scan_gpios(struct gpio_chip *chip, | 
|  | 123 | +					 unsigned int start, | 
|  | 124 | +					 unsigned int num) | 
|  | 125 | +{ | 
|  | 126 | +	return 0; | 
|  | 127 | +} | 
|  | 128 | static inline int of_gpio_get_count(struct device *dev, const char *con_id) | 
|  | 129 | { | 
|  | 130 | return 0; |