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 | |
| 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>
| -rw-r--r-- | Documentation/gpio/board.txt | 28 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 108 | ||||
| -rw-r--r-- | include/linux/gpio/driver.h | 21 |
3 files changed, 85 insertions, 72 deletions
diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 0d03506f2cc5..ba169faad5c6 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt | |||
| @@ -72,10 +72,11 @@ where | |||
| 72 | 72 | ||
| 73 | - chip_label is the label of the gpiod_chip instance providing the GPIO | 73 | - chip_label is the label of the gpiod_chip instance providing the GPIO |
| 74 | - chip_hwnum is the hardware number of the GPIO within the chip | 74 | - chip_hwnum is the hardware number of the GPIO within the chip |
| 75 | - dev_id is the identifier of the device that will make use of this GPIO. If | 75 | - dev_id is the identifier of the device that will make use of this GPIO. It |
| 76 | NULL, the GPIO will be available to all devices. | 76 | can be NULL, in which case it will be matched for calls to gpiod_get() |
| 77 | with a NULL device. | ||
| 77 | - con_id is the name of the GPIO function from the device point of view. It | 78 | - con_id is the name of the GPIO function from the device point of view. It |
| 78 | can be NULL. | 79 | can be NULL, in which case it will match any function. |
| 79 | - idx is the index of the GPIO within the function. | 80 | - idx is the index of the GPIO within the function. |
| 80 | - flags is defined to specify the following properties: | 81 | - flags is defined to specify the following properties: |
| 81 | * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low | 82 | * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low |
| @@ -86,18 +87,23 @@ In the future, these flags might be extended to support more properties. | |||
| 86 | 87 | ||
| 87 | Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. | 88 | Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. |
| 88 | 89 | ||
| 89 | A lookup table can then be defined as follows: | 90 | A lookup table can then be defined as follows, with an empty entry defining its |
| 91 | end: | ||
| 90 | 92 | ||
| 91 | struct gpiod_lookup gpios_table[] = { | 93 | struct gpiod_lookup_table gpios_table = { |
| 92 | GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH), | 94 | .dev_id = "foo.0", |
| 93 | GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH), | 95 | .table = { |
| 94 | GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH), | 96 | GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH), |
| 95 | GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW), | 97 | GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH), |
| 96 | }; | 98 | GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH), |
| 99 | GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW), | ||
| 100 | { }, | ||
| 101 | }, | ||
| 102 | }; | ||
| 97 | 103 | ||
| 98 | And the table can be added by the board code as follows: | 104 | And the table can be added by the board code as follows: |
| 99 | 105 | ||
| 100 | gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table)); | 106 | gpiod_add_lookup_table(&gpios_table); |
| 101 | 107 | ||
| 102 | The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: | 108 | The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: |
| 103 | 109 | ||
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 | ||
