diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 14:58:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 14:58:15 -0400 |
commit | ea584595fc85e65796335033dfca25ed655cd0ed (patch) | |
tree | 79d444c507472f6c66d887ad332e7c1784eeb4de /drivers/gpio/gpiolib.c | |
parent | 782d59c5dfc5ac39ac8cfb4c6dd40597938dde9c (diff) | |
parent | a092e19b688be88f7329bd05f90cb92ebe1a4f5b (diff) | |
download | linux-ea584595fc85e65796335033dfca25ed655cd0ed.tar.bz2 |
Merge tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO changes from Linus Walleij:
"This is the bulk of GPIO changes for the v3.18 development cycle:
- Increase the default ARCH_NR_GPIO from 256 to 512. This was done
to avoid having a custom <asm/gpio.h> header for the x86
architecture - GPIO is custom and complicated enough as it is
already! We want to move to a radix to store the descriptors going
forward, and finally get rid of this fixed array size altogether.
- Endgame patching of the gpio_remove() semantics initiated by
Abdoulaye Berthe. It is not accepted by the system that the
removal of a GPIO chip fails during eg reboot or shutdown, and
therefore the return value has now painfully been refactored away.
For special cases like GPIO expanders on a hot-pluggable bus like
USB, we may later add some gpiochip_try_remove() call, but for the
cases we have now, return values are moot.
- Some incremental refactoring of the gpiolib core and ACPI GPIO
library for more descriptor usage.
- Refactor the chained IRQ handler set-up method to handle also
threaded, nested interrupts and set up the parent IRQ correctly.
Switch STMPE and TC3589x drivers to use this registration method.
- Add a .irq_not_threaded flag to the struct gpio_chip, so that also
GPIO expanders that block but are still not using threaded IRQ
handlers.
- New drivers for the ARM64 X-Gene SoC GPIO controller.
- The syscon GPIO driver has been improved to handle the "DSP GPIO"
found on the TI Keystone 2 SoC:s.
- ADNP driver switched to use gpiolib irqchip helpers.
- Refactor the DWAPB driver to support being instantiated from and
MFD cell (platform device).
- Incremental feature improvement in the Zynq, MCP23S08, DWAPB, OMAP,
Xilinx and Crystalcove drivers.
- Various minor fixes"
* tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (52 commits)
gpio: pch: Build context save/restore only for PM
pinctrl: abx500: get rid of unused variable
gpio: ks8695: fix 'else should follow close brace '}''
gpio: stmpe: add verbose debug code
gpio: stmpe: fix up interrupt enable logic
gpio: staticize xway_stp_init()
gpio: handle also nested irqchips in the chained handler set-up
gpio: set parent irq on chained handlers
gpiolib: irqchip: use irq_find_mapping while removing irqchip
gpio: crystalcove: support virtual GPIO
pinctrl: bcm281xx: make Kconfig dependency more strict
gpio: kona: enable only on BCM_MOBILE or for compile testing
gpio, bcm-kona, LLVMLinux: Remove use of __initconst
gpio: Fix ngpio in gpio-xilinx driver
gpio: dwapb: fix pointer to integer cast
gpio: xgene: Remove unneeded #ifdef CONFIG_OF guard
gpio: xgene: Remove unneeded forward declation for struct xgene_gpio
gpio: xgene: Fix missing spin_lock_init()
gpio: ks8695: fix switch case indentation
gpiolib: add irq_not_threaded flag to gpio_chip
...
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 90 |
1 files changed, 54 insertions, 36 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c68d037de656..e8e98ca25ec7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -308,10 +308,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); * * A gpio_chip with any GPIOs still requested may not be removed. */ -int gpiochip_remove(struct gpio_chip *chip) +void gpiochip_remove(struct gpio_chip *chip) { unsigned long flags; - int status = 0; unsigned id; acpi_gpiochip_remove(chip); @@ -323,24 +322,15 @@ int gpiochip_remove(struct gpio_chip *chip) of_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { - if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { - status = -EBUSY; - break; - } - } - if (status == 0) { - for (id = 0; id < chip->ngpio; id++) - chip->desc[id].chip = NULL; - - list_del(&chip->list); + if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) + dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); } + for (id = 0; id < chip->ngpio; id++) + chip->desc[id].chip = NULL; + list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); - - if (status == 0) - gpiochip_unexport(chip); - - return status; + gpiochip_unexport(chip); } EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -395,30 +385,47 @@ static struct gpio_chip *find_chip_by_name(const char *name) */ /** - * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip - * @gpiochip: the gpiochip to add the irqchip to - * @irqchip: the irqchip to add to the gpiochip + * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to set the irqchip chain to + * @irqchip: the irqchip to chain to the gpiochip * @parent_irq: the irq number corresponding to the parent IRQ for this * chained irqchip * @parent_handler: the parent interrupt handler for the accumulated IRQ - * coming out of the gpiochip + * coming out of the gpiochip. If the interrupt is nested rather than + * cascaded, pass NULL in this handler argument */ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, int parent_irq, irq_flow_handler_t parent_handler) { - if (gpiochip->can_sleep) { - chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); + unsigned int offset; + + if (!gpiochip->irqdomain) { + chip_err(gpiochip, "called %s before setting up irqchip\n", + __func__); return; } - /* - * The parent irqchip is already using the chip_data for this - * irqchip, so our callbacks simply use the handler_data. - */ - irq_set_handler_data(parent_irq, gpiochip); - irq_set_chained_handler(parent_irq, parent_handler); + if (parent_handler) { + if (gpiochip->can_sleep) { + chip_err(gpiochip, + "you cannot have chained interrupts on a " + "chip that may sleep\n"); + return; + } + /* + * The parent irqchip is already using the chip_data for this + * irqchip, so our callbacks simply use the handler_data. + */ + irq_set_handler_data(parent_irq, gpiochip); + irq_set_chained_handler(parent_irq, parent_handler); + } + + /* Set the parent IRQ for all affected IRQs */ + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), + parent_irq); } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); @@ -447,7 +454,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); /* Chips that can sleep need nested thread handlers */ - if (chip->can_sleep) + if (chip->can_sleep && !chip->irq_not_threaded) irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); @@ -524,7 +531,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) /* Remove all IRQ mappings and delete the domain */ if (gpiochip->irqdomain) { for (offset = 0; offset < gpiochip->ngpio; offset++) - irq_dispose_mapping(gpiochip->irq_base + offset); + irq_dispose_mapping( + irq_find_mapping(gpiochip->irqdomain, offset)); irq_domain_remove(gpiochip->irqdomain); } @@ -895,12 +903,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * allows the GPIO chip module to be unloaded as needed (we assume that the * GPIO chip driver handles freeing the GPIOs it has requested). */ -int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, + const char *label) { - if (!desc || !desc->chip) - return -EINVAL; + struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); + int err; - return __gpiod_request(desc, label); + if (IS_ERR(desc)) { + chip_err(chip, "failed to get GPIO descriptor\n"); + return desc; + } + + err = __gpiod_request(desc, label); + if (err < 0) + return ERR_PTR(err); + + return desc; } EXPORT_SYMBOL_GPL(gpiochip_request_own_desc); @@ -1652,7 +1670,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, * a result. In that case, use platform lookup as a fallback. */ if (!desc || desc == ERR_PTR(-ENOENT)) { - dev_dbg(dev, "using lookup tables for GPIO lookup"); + dev_dbg(dev, "using lookup tables for GPIO lookup\n"); desc = gpiod_find(dev, con_id, idx, &lookupflags); } |