aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrygorii Strashko <grygorii.strashko@ti.com>2016-04-12 06:52:31 -0400
committerLinus Walleij <linus.walleij@linaro.org>2016-04-26 09:56:47 -0400
commit0c0451e7634564052a045d4398a91ea4ef1f755b (patch)
tree3e463469f33072a3e91e6d2552c8a902ed78e422
parentf7cb5120c4e0de10c3e069f5318417da0326fb45 (diff)
gpio: omap: fix irq triggering in smart-idle wakeup mode
Now GPIO IRQ loss is observed on dra7-evm after suspend/resume cycle in the following case: extcon_usb1(id_irq) -> pcf8575.gpio1 -> omapgpio6.gpio11 -> gic the extcon_usb1 is wake up source and it enables IRQ wake up for id_irq by calling enable/disable_irq_wake() during suspend/resume which, in turn, causes execution of omap_gpio_wake_enable(). And omap_gpio_wake_enable() will set/clear corresponding bit in GPIO_IRQWAKEN_x register. omapgpio6 configuration after boot - wakeup is enabled for GPIO IRQs by default from omap_gpio_irq_type: GPIO_IRQSTATUS_SET_0 | 0x00000400 GPIO_IRQSTATUS_CLR_0 | 0x00000400 GPIO_IRQWAKEN_0 | 0x00000400 GPIO_RISINGDETECT | 0x00000000 GPIO_FALLINGDETECT | 0x00000400 omapgpio6 configuration after after suspend/resume cycle: GPIO_IRQSTATUS_SET_0 | 0x00000400 GPIO_IRQSTATUS_CLR_0 | 0x00000400 GPIO_IRQWAKEN_0 | 0x00000000 <--- GPIO_RISINGDETECT | 0x00000000 GPIO_FALLINGDETECT | 0x00000400 As result, system will start to lose interrupts from pcf8575 GPIO expander, because when OMAP GPIO IP is in smart-idle wakeup mode, there is no guarantee that transition(s) on input non wake up GPIO pin will trigger asynchronous wake-up request to PRCM and then IRQ generation. IRQ will be generated when GPIO is in active mode - for example, some time after accessing GPIO bank registers IRQs will be generated normally, but issue will happen again once PRCM will put GPIO in low power smart-idle wakeup mode. Note 1. Issue is not reproduced if debounce clk is enabled for GPIO bank. Note 2. Issue hardly reproducible if GPIO pins group contains both wakeup/non-wakeup gpios - for example, it will be hard to reproduce issue with pin2 if GPIO_IRQWAKEN_0=0x1 GPIO_IRQSTATUS_SET_0=0x3 GPIO_FALLINGDETECT = 0x3 (TRM "Power Saving by Grouping the Edge/Level Detection"). Note 3. There nothing common bitween System wake up and OMAP GPIO bank IP wake up logic - the last one defines how the GPIO bank ON-IDLE-ON transition will happen inside SoC under control of PRCM. Hence, fix the problem by removing omap_set_gpio_wakeup() function completely and so keeping always in sync GPIO IRQ mask/unmask (IRQSTATUS_SET) and wake up enable (GPIO_IRQWAKEN) bits; and adding IRQCHIP_MASK_ON_SUSPEND flag in OMAP GPIO irqchip. That way non wakeup GPIO IRQs will be properly masked/unmask by IRQ PM core during suspend/resume cycle. Cc: Roger Quadros <rogerq@ti.com> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/gpio-omap.c42
1 files changed, 2 insertions, 40 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 551dfa9d97ab..b98ede78c9d8 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -611,51 +611,12 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
611 omap_disable_gpio_irqbank(bank, BIT(offset)); 611 omap_disable_gpio_irqbank(bank, BIT(offset));
612} 612}
613 613
614/*
615 * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
616 * 1510 does not seem to have a wake-up register. If JTAG is connected
617 * to the target, system will wake up always on GPIO events. While
618 * system is running all registered GPIO interrupts need to have wake-up
619 * enabled. When system is suspended, only selected GPIO interrupts need
620 * to have wake-up enabled.
621 */
622static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
623 int enable)
624{
625 u32 gpio_bit = BIT(offset);
626 unsigned long flags;
627
628 if (bank->non_wakeup_gpios & gpio_bit) {
629 dev_err(bank->chip.parent,
630 "Unable to modify wakeup on non-wakeup GPIO%d\n",
631 offset);
632 return -EINVAL;
633 }
634
635 raw_spin_lock_irqsave(&bank->lock, flags);
636 if (enable)
637 bank->context.wake_en |= gpio_bit;
638 else
639 bank->context.wake_en &= ~gpio_bit;
640
641 writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en);
642 raw_spin_unlock_irqrestore(&bank->lock, flags);
643
644 return 0;
645}
646
647/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ 614/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
648static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) 615static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
649{ 616{
650 struct gpio_bank *bank = omap_irq_data_get_bank(d); 617 struct gpio_bank *bank = omap_irq_data_get_bank(d);
651 unsigned offset = d->hwirq;
652 int ret;
653 618
654 ret = omap_set_gpio_wakeup(bank, offset, enable); 619 return irq_set_irq_wake(bank->irq, enable);
655 if (!ret)
656 ret = irq_set_irq_wake(bank->irq, enable);
657
658 return ret;
659} 620}
660 621
661static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) 622static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -1187,6 +1148,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
1187 irqc->irq_bus_lock = omap_gpio_irq_bus_lock, 1148 irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
1188 irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, 1149 irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
1189 irqc->name = dev_name(&pdev->dev); 1150 irqc->name = dev_name(&pdev->dev);
1151 irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
1190 1152
1191 bank->irq = platform_get_irq(pdev, 0); 1153 bank->irq = platform_get_irq(pdev, 0);
1192 if (bank->irq <= 0) { 1154 if (bank->irq <= 0) {