summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c85
1 files changed, 56 insertions, 29 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4e4c3083ae56..d72ac1fdcd98 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -182,7 +182,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
/*
* Add a new chip to the global chips list, keeping the list of chips sorted
- * by base order.
+ * by range(means [base, base + ngpio - 1]) order.
*
* Return -EBUSY if the new chip overlaps with some other chip's integer
* space.
@@ -190,31 +190,48 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
static int gpiochip_add_to_list(struct gpio_chip *chip)
{
struct list_head *pos;
- struct gpio_chip *_chip;
- int err = 0;
+ struct gpio_chip *iterator;
+ struct gpio_chip *previous = NULL;
- /* 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;
+ if (list_empty(&gpio_chips)) {
+ pos = gpio_chips.next;
+ goto found;
}
- /* 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;
+ list_for_each(pos, &gpio_chips) {
+ iterator = list_entry(pos, struct gpio_chip, list);
+ if (iterator->base >= chip->base + chip->ngpio) {
+ /*
+ * Iterator is the first GPIO chip so there is no
+ * previous one
+ */
+ if (previous == NULL) {
+ goto found;
+ } else {
+ /*
+ * We found a valid range(means
+ * [base, base + ngpio - 1]) between previous
+ * and iterator chip.
+ */
+ if (previous->base + previous->ngpio
+ <= chip->base)
+ goto found;
+ }
}
+ previous = iterator;
}
- if (!err)
- list_add_tail(&chip->list, pos);
+ /* We are beyond the last chip in the list */
+ if (iterator->base + iterator->ngpio <= chip->base)
+ goto found;
+
+ dev_err(chip->parent,
+ "GPIO integer space overlap, cannot add chip\n");
+ return -EBUSY;
- return err;
+found:
+ list_add_tail(&chip->list, pos);
+ return 0;
}
/**
@@ -252,7 +269,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
* Takes the names from gc->names and checks if they are all unique. If they
* are, they are assigned to their gpio descriptors.
*
- * Returns -EEXIST if one of the names is already used for a different GPIO.
+ * Warning if one of the names is already used for a different GPIO.
*/
static int gpiochip_set_desc_names(struct gpio_chip *gc)
{
@@ -267,7 +284,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
gpio = gpio_name_to_desc(gc->names[i]);
if (gpio)
- dev_warn(gc->dev, "Detected name collision for "
+ dev_warn(gc->parent, "Detected name collision for "
"GPIO name '%s'\n",
gc->names[i]);
}
@@ -289,7 +306,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
* different chip. Otherwise it returns zero as a success code.
*
* When gpiochip_add() is called very early during boot, so that GPIOs
- * can be freely used, the chip->dev device must be registered before
+ * can be freely used, the chip->parent device must be registered before
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
*
@@ -308,6 +325,11 @@ int gpiochip_add(struct gpio_chip *chip)
if (!descs)
return -ENOMEM;
+ if (chip->ngpio == 0) {
+ chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&gpio_lock, flags);
if (base < 0) {
@@ -348,8 +370,8 @@ int gpiochip_add(struct gpio_chip *chip)
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
- if (!chip->owner && chip->dev && chip->dev->driver)
- chip->owner = chip->dev->driver->owner;
+ if (!chip->owner && chip->parent && chip->parent->driver)
+ chip->owner = chip->parent->driver->owner;
status = gpiochip_set_desc_names(chip);
if (status)
@@ -424,7 +446,8 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_unlock_irqrestore(&gpio_lock, flags);
if (requested)
- dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
+ dev_crit(chip->parent,
+ "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
kfree(chip->desc);
chip->desc = NULL;
@@ -683,15 +706,16 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
if (!gpiochip || !irqchip)
return -EINVAL;
- if (!gpiochip->dev) {
+ if (!gpiochip->parent) {
pr_err("missing gpiochip .dev parent pointer\n");
return -EINVAL;
}
- of_node = gpiochip->dev->of_node;
+ of_node = gpiochip->parent->of_node;
#ifdef CONFIG_OF_GPIO
/*
* If the gpiochip has an assigned OF node this takes precedence
- * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
+ * FIXME: get rid of this and use gpiochip->parent->of_node
+ * everywhere
*/
if (gpiochip->of_node)
of_node = gpiochip->of_node;
@@ -1874,6 +1898,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
+ if (!acpi_can_fallback_to_crs(adev, con_id))
+ return ERR_PTR(-ENOENT);
+
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
@@ -2509,7 +2536,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
chip->base, chip->base + chip->ngpio - 1);
- dev = chip->dev;
+ dev = chip->parent;
if (dev)
seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
dev_name(dev));