diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-06-08 09:48:16 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-07-05 18:14:30 -0400 |
commit | 594fa265e084073443390c5b93d5410fd28e9bcd (patch) | |
tree | 42c0e5536ae2fd016159e1e1bd1f27f0a9f3cac2 /drivers | |
parent | a19e3da5bc5fc6c10ab73f310bea80f3845b4531 (diff) |
of/gpio: stop using device_node data pointer to find gpio_chip
Currently the kernel uses the struct device_node.data pointer to resolve
a struct gpio_chip pointer from a device tree node. However, the .data
member doesn't provide any type checking and there aren't any rules
enforced on what it should be used for. There's no guarantee that the
data stored in it actually points to an gpio_chip pointer.
Instead of relying on the .data pointer, this patch modifies the code
to add a lookup function which scans through the registered gpio_chips
and returns the gpio_chip that has a pointer to the specified
device_node.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Anton Vorontsov <avorontsov@ru.mvista.com>
CC: Grant Likely <grant.likely@secretlab.ca>
CC: David Brownell <dbrownell@users.sourceforge.net>
CC: Bill Gatliff <bgat@billgatliff.com>
CC: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Jean Delvare <khali@linux-fr.org>
CC: linux-kernel@vger.kernel.org
CC: devicetree-discuss@lists.ozlabs.org
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpiolib.c | 32 | ||||
-rw-r--r-- | drivers/of/gpio.c | 15 |
2 files changed, 44 insertions, 3 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 713ca0e37f23..73fd328f6fe4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -1153,6 +1153,38 @@ int gpiochip_remove(struct gpio_chip *chip) | |||
1153 | } | 1153 | } |
1154 | EXPORT_SYMBOL_GPL(gpiochip_remove); | 1154 | EXPORT_SYMBOL_GPL(gpiochip_remove); |
1155 | 1155 | ||
1156 | /** | ||
1157 | * gpiochip_find() - iterator for locating a specific gpio_chip | ||
1158 | * @data: data to pass to match function | ||
1159 | * @callback: Callback function to check gpio_chip | ||
1160 | * | ||
1161 | * Similar to bus_find_device. It returns a reference to a gpio_chip as | ||
1162 | * determined by a user supplied @match callback. The callback should return | ||
1163 | * 0 if the device doesn't match and non-zero if it does. If the callback is | ||
1164 | * non-zero, this function will return to the caller and not iterate over any | ||
1165 | * more gpio_chips. | ||
1166 | */ | ||
1167 | struct gpio_chip *gpiochip_find(void *data, | ||
1168 | int (*match)(struct gpio_chip *chip, void *data)) | ||
1169 | { | ||
1170 | struct gpio_chip *chip = NULL; | ||
1171 | unsigned long flags; | ||
1172 | int i; | ||
1173 | |||
1174 | spin_lock_irqsave(&gpio_lock, flags); | ||
1175 | for (i = 0; i < ARCH_NR_GPIOS; i++) { | ||
1176 | if (!gpio_desc[i].chip) | ||
1177 | continue; | ||
1178 | |||
1179 | if (match(gpio_desc[i].chip, data)) { | ||
1180 | chip = gpio_desc[i].chip; | ||
1181 | break; | ||
1182 | } | ||
1183 | } | ||
1184 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
1185 | |||
1186 | return chip; | ||
1187 | } | ||
1156 | 1188 | ||
1157 | /* These "optional" allocation calls help prevent drivers from stomping | 1189 | /* These "optional" allocation calls help prevent drivers from stomping |
1158 | * on each other, and help provide better diagnostics in debugfs. | 1190 | * on each other, and help provide better diagnostics in debugfs. |
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index fde53a3a45a3..c8618d3282cf 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c | |||
@@ -46,7 +46,7 @@ int of_get_gpio_flags(struct device_node *np, int index, | |||
46 | goto err0; | 46 | goto err0; |
47 | } | 47 | } |
48 | 48 | ||
49 | gc = gpio_np->data; | 49 | gc = of_node_to_gpiochip(gpio_np); |
50 | if (!gc) { | 50 | if (!gc) { |
51 | pr_debug("%s: gpio controller %s isn't registered\n", | 51 | pr_debug("%s: gpio controller %s isn't registered\n", |
52 | np->full_name, gpio_np->full_name); | 52 | np->full_name, gpio_np->full_name); |
@@ -193,7 +193,6 @@ int of_mm_gpiochip_add(struct device_node *np, | |||
193 | if (mm_gc->save_regs) | 193 | if (mm_gc->save_regs) |
194 | mm_gc->save_regs(mm_gc); | 194 | mm_gc->save_regs(mm_gc); |
195 | 195 | ||
196 | np->data = &mm_gc->gc; | ||
197 | mm_gc->gc.of_node = np; | 196 | mm_gc->gc.of_node = np; |
198 | 197 | ||
199 | ret = gpiochip_add(gc); | 198 | ret = gpiochip_add(gc); |
@@ -207,7 +206,6 @@ int of_mm_gpiochip_add(struct device_node *np, | |||
207 | np->full_name, gc->base); | 206 | np->full_name, gc->base); |
208 | return 0; | 207 | return 0; |
209 | err2: | 208 | err2: |
210 | np->data = NULL; | ||
211 | iounmap(mm_gc->regs); | 209 | iounmap(mm_gc->regs); |
212 | err1: | 210 | err1: |
213 | kfree(gc->label); | 211 | kfree(gc->label); |
@@ -217,3 +215,14 @@ err0: | |||
217 | return ret; | 215 | return ret; |
218 | } | 216 | } |
219 | EXPORT_SYMBOL(of_mm_gpiochip_add); | 217 | EXPORT_SYMBOL(of_mm_gpiochip_add); |
218 | |||
219 | /* Private function for resolving node pointer to gpio_chip */ | ||
220 | static int of_gpiochip_is_match(struct gpio_chip *chip, void *data) | ||
221 | { | ||
222 | return chip->of_node == data; | ||
223 | } | ||
224 | |||
225 | struct gpio_chip *of_node_to_gpiochip(struct device_node *np) | ||
226 | { | ||
227 | return gpiochip_find(np, of_gpiochip_is_match); | ||
228 | } | ||