mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
gpiolib: link all gpio_chips using a list
Add a list member to gpio_chip that allows all chips to be parsed quickly. The current method requires parsing the entire GPIO integer space, which is painfully slow. Using a list makes many chip operations that involve lookup or parsing faster, and also simplifies the code. It is also necessary to eventually get rid of the global gpio_desc[] array. The list of gpio_chips is always ordered by base GPIO number to ensure chips traversal is done in the right order. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
0fa2fd9a0d
commit
1a989d0f1d
@ -3,6 +3,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/debugfs.h>
|
||||
@ -71,6 +72,8 @@ struct gpio_desc {
|
||||
};
|
||||
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
|
||||
|
||||
static LIST_HEAD(gpio_chips);
|
||||
|
||||
#ifdef CONFIG_GPIO_SYSFS
|
||||
static DEFINE_IDR(dirent_idr);
|
||||
#endif
|
||||
@ -1014,6 +1017,43 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
|
||||
|
||||
#endif /* CONFIG_GPIO_SYSFS */
|
||||
|
||||
/*
|
||||
* Add a new chip to the global chips list, keeping the list of chips sorted
|
||||
* by base order.
|
||||
*
|
||||
* Return -EBUSY if the new chip overlaps with some other chip's integer
|
||||
* space.
|
||||
*/
|
||||
static int gpiochip_add_to_list(struct gpio_chip *chip)
|
||||
{
|
||||
struct list_head *pos = &gpio_chips;
|
||||
struct gpio_chip *_chip;
|
||||
int err = 0;
|
||||
|
||||
/* find where to insert our chip */
|
||||
list_for_each(pos, &gpio_chips) {
|
||||
_chip = list_entry(pos, struct gpio_chip, list);
|
||||
/* shall we insert before _chip? */
|
||||
if (_chip->base >= chip->base + chip->ngpio)
|
||||
break;
|
||||
}
|
||||
|
||||
/* are we stepping on the chip right before? */
|
||||
if (pos != &gpio_chips && pos->prev != &gpio_chips) {
|
||||
_chip = list_entry(pos->prev, struct gpio_chip, list);
|
||||
if (_chip->base + _chip->ngpio > chip->base) {
|
||||
dev_err(chip->dev,
|
||||
"GPIO integer space overlap, cannot add chip\n");
|
||||
err = -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!err)
|
||||
list_add_tail(&chip->list, pos);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_add() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
@ -1055,13 +1095,8 @@ int gpiochip_add(struct gpio_chip *chip)
|
||||
chip->base = base;
|
||||
}
|
||||
|
||||
/* these GPIO numbers must not be managed by another gpio_chip */
|
||||
for (id = base; id < base + chip->ngpio; id++) {
|
||||
if (gpio_desc[id].chip != NULL) {
|
||||
status = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = gpiochip_add_to_list(chip);
|
||||
|
||||
if (status == 0) {
|
||||
for (id = base; id < base + chip->ngpio; id++) {
|
||||
gpio_desc[id].chip = chip;
|
||||
@ -1135,6 +1170,8 @@ int gpiochip_remove(struct gpio_chip *chip)
|
||||
if (status == 0) {
|
||||
for (id = chip->base; id < chip->base + chip->ngpio; id++)
|
||||
gpio_desc[id].chip = NULL;
|
||||
|
||||
list_del(&chip->list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
@ -53,6 +53,7 @@ struct device_node;
|
||||
* @label: for diagnostics
|
||||
* @dev: optional device providing the GPIOs
|
||||
* @owner: helps prevent removal of modules exporting active GPIOs
|
||||
* @list: links gpio_chips together for traversal
|
||||
* @request: optional hook for chip-specific activation, such as
|
||||
* enabling module power and clock; may sleep
|
||||
* @free: optional hook for chip-specific deactivation, such as
|
||||
@ -98,6 +99,7 @@ struct gpio_chip {
|
||||
const char *label;
|
||||
struct device *dev;
|
||||
struct module *owner;
|
||||
struct list_head list;
|
||||
|
||||
int (*request)(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
|
Loading…
Reference in New Issue
Block a user