mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-18 11:54:37 +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/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
@ -71,6 +72,8 @@ struct gpio_desc {
|
|||||||
};
|
};
|
||||||
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
|
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
|
||||||
|
|
||||||
|
static LIST_HEAD(gpio_chips);
|
||||||
|
|
||||||
#ifdef CONFIG_GPIO_SYSFS
|
#ifdef CONFIG_GPIO_SYSFS
|
||||||
static DEFINE_IDR(dirent_idr);
|
static DEFINE_IDR(dirent_idr);
|
||||||
#endif
|
#endif
|
||||||
@ -1014,6 +1017,43 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
|
|||||||
|
|
||||||
#endif /* CONFIG_GPIO_SYSFS */
|
#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
|
* gpiochip_add() - register a gpio_chip
|
||||||
* @chip: the chip to register, with chip->base initialized
|
* @chip: the chip to register, with chip->base initialized
|
||||||
@ -1055,13 +1095,8 @@ int gpiochip_add(struct gpio_chip *chip)
|
|||||||
chip->base = base;
|
chip->base = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* these GPIO numbers must not be managed by another gpio_chip */
|
status = gpiochip_add_to_list(chip);
|
||||||
for (id = base; id < base + chip->ngpio; id++) {
|
|
||||||
if (gpio_desc[id].chip != NULL) {
|
|
||||||
status = -EBUSY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
for (id = base; id < base + chip->ngpio; id++) {
|
for (id = base; id < base + chip->ngpio; id++) {
|
||||||
gpio_desc[id].chip = chip;
|
gpio_desc[id].chip = chip;
|
||||||
@ -1135,6 +1170,8 @@ int gpiochip_remove(struct gpio_chip *chip)
|
|||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
for (id = chip->base; id < chip->base + chip->ngpio; id++)
|
for (id = chip->base; id < chip->base + chip->ngpio; id++)
|
||||||
gpio_desc[id].chip = NULL;
|
gpio_desc[id].chip = NULL;
|
||||||
|
|
||||||
|
list_del(&chip->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||||
|
@ -53,6 +53,7 @@ struct device_node;
|
|||||||
* @label: for diagnostics
|
* @label: for diagnostics
|
||||||
* @dev: optional device providing the GPIOs
|
* @dev: optional device providing the GPIOs
|
||||||
* @owner: helps prevent removal of modules exporting active 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
|
* @request: optional hook for chip-specific activation, such as
|
||||||
* enabling module power and clock; may sleep
|
* enabling module power and clock; may sleep
|
||||||
* @free: optional hook for chip-specific deactivation, such as
|
* @free: optional hook for chip-specific deactivation, such as
|
||||||
@ -98,6 +99,7 @@ struct gpio_chip {
|
|||||||
const char *label;
|
const char *label;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
int (*request)(struct gpio_chip *chip,
|
int (*request)(struct gpio_chip *chip,
|
||||||
unsigned offset);
|
unsigned offset);
|
||||||
|
Loading…
Reference in New Issue
Block a user