summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2014-04-09 13:34:39 +0200
committerLinus Walleij <linus.walleij@linaro.org>2014-04-28 12:35:07 -0700
commit1c8732bb0355b929b09173464cdca7df4d516f89 (patch)
treeaff50774b50c3f4567be23f9d6deeb187ab4a62f /drivers/gpio/gpiolib.c
parentd1db0eea852497762cab43b905b879dfcd3b8987 (diff)
downloadlinux-1c8732bb0355b929b09173464cdca7df4d516f89.tar.bz2
gpio: support threaded interrupts in irqchip helpers
Some off-chip GPIO expanders need to be communicated by I2C or SPI traffic, but may still support IRQs. By the sleeping nature of such buses, such IRQ handlers need to be threaded. Support such handlers in the gpiochip irqchip helpers by flagging IRQs as threaded if the .can_sleep property of the gpiochip is true. Helpfully deny registration of chained IRQ handlers if the .can_sleep property is set, as such chips will invariably need a nested handler rather than a chained handler. Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f48817d97480..c12fe9dfd2db 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1363,6 +1363,11 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
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");
+ return;
+ }
+
irq_set_chained_handler(parent_irq, parent_handler);
/*
* The parent irqchip is already using the chip_data for this
@@ -1389,6 +1394,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
irq_set_chip_data(irq, chip);
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+ /* Chips that can sleep need nested thread handlers */
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
@@ -1401,9 +1409,13 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
{
+ struct gpio_chip *chip = d->host_data;
+
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 0);
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
}