diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 85 |
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)); |