diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2013-12-02 22:20:11 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-12-09 08:05:51 -0500 |
commit | ad824783fb23bbc8295cffb6214b3b82d25f7d4a (patch) | |
tree | 745d128c1d04dca7a6c7b10dd737f116f13ddcb1 /drivers/gpio/gpiolib.c | |
parent | bdc54ef45d7670aeb52ce73f8b7ad5f3e5563661 (diff) |
gpio: better lookup method for platform GPIOs
Change the format of the platform GPIO lookup tables to make them less
confusing and improve lookup efficiency.
The previous format was a single linked-list that required to compare
the device name and function ID of every single GPIO defined for each
lookup. Switch that to a list of per-device tables, so that the lookup
can be done in two steps, omitting the GPIOs that are not relevant for a
particular device.
The matching rules are now defined as follows:
- The device name must match *exactly*, and can be NULL for GPIOs not
assigned to a particular device,
- If the function ID in the lookup table is NULL, the con_id argument of
gpiod_get() will not be used for lookup. However, if it is defined, it
must match exactly.
- The index must always match.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 108 |
1 files changed, 58 insertions, 50 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 44a232701179..4eb262a31777 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -2260,18 +2260,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) | |||
2260 | EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); | 2260 | EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); |
2261 | 2261 | ||
2262 | /** | 2262 | /** |
2263 | * gpiod_add_table() - register GPIO device consumers | 2263 | * gpiod_add_lookup_table() - register GPIO device consumers |
2264 | * @table: array of consumers to register | 2264 | * @table: table of consumers to register |
2265 | * @num: number of consumers in table | ||
2266 | */ | 2265 | */ |
2267 | void gpiod_add_table(struct gpiod_lookup *table, size_t size) | 2266 | void gpiod_add_lookup_table(struct gpiod_lookup_table *table) |
2268 | { | 2267 | { |
2269 | mutex_lock(&gpio_lookup_lock); | 2268 | mutex_lock(&gpio_lookup_lock); |
2270 | 2269 | ||
2271 | while (size--) { | 2270 | list_add_tail(&table->list, &gpio_lookup_list); |
2272 | list_add_tail(&table->list, &gpio_lookup_list); | ||
2273 | table++; | ||
2274 | } | ||
2275 | 2271 | ||
2276 | mutex_unlock(&gpio_lookup_lock); | 2272 | mutex_unlock(&gpio_lookup_lock); |
2277 | } | 2273 | } |
@@ -2327,72 +2323,84 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, | |||
2327 | return desc; | 2323 | return desc; |
2328 | } | 2324 | } |
2329 | 2325 | ||
2330 | static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, | 2326 | static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) |
2331 | unsigned int idx, | ||
2332 | enum gpio_lookup_flags *flags) | ||
2333 | { | 2327 | { |
2334 | const char *dev_id = dev ? dev_name(dev) : NULL; | 2328 | const char *dev_id = dev ? dev_name(dev) : NULL; |
2335 | struct gpio_desc *desc = ERR_PTR(-ENODEV); | 2329 | struct gpiod_lookup_table *table; |
2336 | unsigned int match, best = 0; | ||
2337 | struct gpiod_lookup *p; | ||
2338 | 2330 | ||
2339 | mutex_lock(&gpio_lookup_lock); | 2331 | mutex_lock(&gpio_lookup_lock); |
2340 | 2332 | ||
2341 | list_for_each_entry(p, &gpio_lookup_list, list) { | 2333 | list_for_each_entry(table, &gpio_lookup_list, list) { |
2342 | match = 0; | 2334 | if (table->dev_id && dev_id) { |
2335 | /* | ||
2336 | * Valid strings on both ends, must be identical to have | ||
2337 | * a match | ||
2338 | */ | ||
2339 | if (!strcmp(table->dev_id, dev_id)) | ||
2340 | goto found; | ||
2341 | } else { | ||
2342 | /* | ||
2343 | * One of the pointers is NULL, so both must be to have | ||
2344 | * a match | ||
2345 | */ | ||
2346 | if (dev_id == table->dev_id) | ||
2347 | goto found; | ||
2348 | } | ||
2349 | } | ||
2350 | table = NULL; | ||
2343 | 2351 | ||
2344 | if (p->dev_id) { | 2352 | found: |
2345 | if (!dev_id || strcmp(p->dev_id, dev_id)) | 2353 | mutex_unlock(&gpio_lookup_lock); |
2346 | continue; | 2354 | return table; |
2355 | } | ||
2347 | 2356 | ||
2348 | match += 2; | 2357 | static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, |
2349 | } | 2358 | unsigned int idx, |
2359 | enum gpio_lookup_flags *flags) | ||
2360 | { | ||
2361 | struct gpio_desc *desc = ERR_PTR(-ENODEV); | ||
2362 | struct gpiod_lookup_table *table; | ||
2363 | struct gpiod_lookup *p; | ||
2350 | 2364 | ||
2351 | if (p->con_id) { | 2365 | table = gpiod_find_lookup_table(dev); |
2352 | if (!con_id || strcmp(p->con_id, con_id)) | 2366 | if (!table) |
2353 | continue; | 2367 | return desc; |
2354 | 2368 | ||
2355 | match += 1; | 2369 | for (p = &table->table[0]; p->chip_label; p++) { |
2356 | } | 2370 | struct gpio_chip *chip; |
2357 | 2371 | ||
2372 | /* idx must always match exactly */ | ||
2358 | if (p->idx != idx) | 2373 | if (p->idx != idx) |
2359 | continue; | 2374 | continue; |
2360 | 2375 | ||
2361 | if (match > best) { | 2376 | /* If the lookup entry has a con_id, require exact match */ |
2362 | struct gpio_chip *chip; | 2377 | if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) |
2363 | 2378 | continue; | |
2364 | chip = find_chip_by_name(p->chip_label); | ||
2365 | |||
2366 | if (!chip) { | ||
2367 | dev_warn(dev, "cannot find GPIO chip %s\n", | ||
2368 | p->chip_label); | ||
2369 | continue; | ||
2370 | } | ||
2371 | 2379 | ||
2372 | if (chip->ngpio <= p->chip_hwnum) { | 2380 | chip = find_chip_by_name(p->chip_label); |
2373 | dev_warn(dev, "GPIO chip %s has %d GPIOs\n", | ||
2374 | chip->label, chip->ngpio); | ||
2375 | continue; | ||
2376 | } | ||
2377 | 2381 | ||
2378 | desc = gpio_to_desc(chip->base + p->chip_hwnum); | 2382 | if (!chip) { |
2379 | *flags = p->flags; | 2383 | dev_warn(dev, "cannot find GPIO chip %s\n", |
2384 | p->chip_label); | ||
2385 | continue; | ||
2386 | } | ||
2380 | 2387 | ||
2381 | if (match != 3) | 2388 | if (chip->ngpio <= p->chip_hwnum) { |
2382 | best = match; | 2389 | dev_warn(dev, "GPIO chip %s has %d GPIOs\n", |
2383 | else | 2390 | chip->label, chip->ngpio); |
2384 | break; | 2391 | continue; |
2385 | } | 2392 | } |
2386 | } | ||
2387 | 2393 | ||
2388 | mutex_unlock(&gpio_lookup_lock); | 2394 | desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); |
2395 | *flags = p->flags; | ||
2396 | } | ||
2389 | 2397 | ||
2390 | return desc; | 2398 | return desc; |
2391 | } | 2399 | } |
2392 | 2400 | ||
2393 | /** | 2401 | /** |
2394 | * gpio_get - obtain a GPIO for a given GPIO function | 2402 | * gpio_get - obtain a GPIO for a given GPIO function |
2395 | * @dev: GPIO consumer | 2403 | * @dev: GPIO consumer, can be NULL for system-global GPIOs |
2396 | * @con_id: function within the GPIO consumer | 2404 | * @con_id: function within the GPIO consumer |
2397 | * | 2405 | * |
2398 | * Return the GPIO descriptor corresponding to the function con_id of device | 2406 | * Return the GPIO descriptor corresponding to the function con_id of device |