diff options
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 120 |
1 files changed, 37 insertions, 83 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 4461540653a8..4fbc208c32cf 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -57,14 +57,10 @@ struct gpio_bank { u16 irq; int irq_base; struct irq_domain *domain; - u32 suspend_wakeup; - u32 saved_wakeup; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; u32 saved_datain; - u32 saved_fallingdetect; - u32 saved_risingdetect; u32 level_mask; u32 toggle_mask; spinlock_t lock; @@ -178,12 +174,22 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank) if (bank->dbck_enable_mask && !bank->dbck_enabled) { clk_enable(bank->dbck); bank->dbck_enabled = true; + + __raw_writel(bank->dbck_enable_mask, + bank->base + bank->regs->debounce_en); } } static inline void _gpio_dbck_disable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && bank->dbck_enabled) { + /* + * Disable debounce before cutting it's clock. If debounce is + * enabled but the clock is not, GPIO module seems to be unable + * to detect events and generate interrupts at least on OMAP3. + */ + __raw_writel(0, bank->base + bank->regs->debounce_en); + clk_disable(bank->dbck); bank->dbck_enabled = false; } @@ -516,11 +522,11 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_lock_irqsave(&bank->lock, flags); if (enable) - bank->suspend_wakeup |= gpio_bit; + bank->context.wake_en |= gpio_bit; else - bank->suspend_wakeup &= ~gpio_bit; + bank->context.wake_en &= ~gpio_bit; - __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en); + __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -640,7 +646,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 isr; unsigned int gpio_irq, gpio_index; struct gpio_bank *bank; - u32 retrigger = 0; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -677,8 +682,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } - isr |= retrigger; - retrigger = 0; if (!isr) break; @@ -789,8 +792,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(mask_reg); - __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg); + __raw_writel(0xffff & ~bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -805,7 +807,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(bank->saved_wakeup, mask_reg); + __raw_writel(bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1089,7 +1091,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->is_mpuio = pdata->is_mpuio; bank->non_wakeup_gpios = pdata->non_wakeup_gpios; bank->loses_context = pdata->loses_context; - bank->get_context_loss_count = pdata->get_context_loss_count; bank->regs = pdata->regs; #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); @@ -1143,6 +1144,9 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); + if (bank->loses_context) + bank->get_context_loss_count = pdata->get_context_loss_count; + pm_runtime_put(bank->dev); list_add_tail(&bank->node, &omap_gpio_list); @@ -1152,54 +1156,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_OMAP2PLUS -#if defined(CONFIG_PM_SLEEP) -static int omap_gpio_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); - void __iomem *base = bank->base; - void __iomem *wakeup_enable; - unsigned long flags; - - if (!bank->mod_usage || !bank->loses_context) - return 0; - - if (!bank->regs->wkup_en || !bank->suspend_wakeup) - return 0; - - wakeup_enable = bank->base + bank->regs->wkup_en; - - spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(wakeup_enable); - _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); - _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1); - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static int omap_gpio_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); - void __iomem *base = bank->base; - unsigned long flags; - - if (!bank->mod_usage || !bank->loses_context) - return 0; - - if (!bank->regs->wkup_en || !bank->saved_wakeup) - return 0; - - spin_lock_irqsave(&bank->lock, flags); - _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); - _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1); - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - #if defined(CONFIG_PM_RUNTIME) static void omap_gpio_restore_context(struct gpio_bank *bank); @@ -1233,6 +1189,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) __raw_writel(wake_hi | bank->context.risingdetect, bank->base + bank->regs->risingdetect); + if (!bank->enabled_non_wakeup_gpios) + goto update_gpio_context_count; + if (bank->power_mode != OFF_MODE) { bank->power_mode = 0; goto update_gpio_context_count; @@ -1244,11 +1203,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) */ bank->saved_datain = __raw_readl(bank->base + bank->regs->datain); - l1 = __raw_readl(bank->base + bank->regs->fallingdetect); - l2 = __raw_readl(bank->base + bank->regs->risingdetect); + l1 = bank->context.fallingdetect; + l2 = bank->context.risingdetect; - bank->saved_fallingdetect = l1; - bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; @@ -1290,16 +1247,10 @@ static int omap_gpio_runtime_resume(struct device *dev) __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - if (!bank->workaround_enabled) { - spin_unlock_irqrestore(&bank->lock, flags); - return 0; - } - if (bank->get_context_loss_count) { context_lost_cnt_after = bank->get_context_loss_count(bank->dev); - if (context_lost_cnt_after != bank->context_loss_count || - !context_lost_cnt_after) { + if (context_lost_cnt_after != bank->context_loss_count) { omap_gpio_restore_context(bank); } else { spin_unlock_irqrestore(&bank->lock, flags); @@ -1307,9 +1258,14 @@ static int omap_gpio_runtime_resume(struct device *dev) } } - __raw_writel(bank->saved_fallingdetect, + if (!bank->workaround_enabled) { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } + + __raw_writel(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->saved_risingdetect, + __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); l = __raw_readl(bank->base + bank->regs->datain); @@ -1326,14 +1282,15 @@ static int omap_gpio_runtime_resume(struct device *dev) * No need to generate IRQs for the rising edge for gpio IRQs * configured with falling edge only; and vice versa. */ - gen0 = l & bank->saved_fallingdetect; + gen0 = l & bank->context.fallingdetect; gen0 &= bank->saved_datain; - gen1 = l & bank->saved_risingdetect; + gen1 = l & bank->context.risingdetect; gen1 &= ~(bank->saved_datain); /* FIXME: Consider GPIO IRQs with level detections properly! */ - gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect)); + gen = l & (~(bank->context.fallingdetect) & + ~(bank->context.risingdetect)); /* Consider all GPIO IRQs needed to be updated */ gen |= gen0 | gen1; @@ -1343,14 +1300,14 @@ static int omap_gpio_runtime_resume(struct device *dev) old0 = __raw_readl(bank->base + bank->regs->leveldetect0); old1 = __raw_readl(bank->base + bank->regs->leveldetect1); - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + if (!bank->regs->irqstatus_raw0) { __raw_writel(old0 | gen, bank->base + bank->regs->leveldetect0); __raw_writel(old1 | gen, bank->base + bank->regs->leveldetect1); } - if (cpu_is_omap44xx()) { + if (bank->regs->irqstatus_raw0) { __raw_writel(old0 | l, bank->base + bank->regs->leveldetect0); __raw_writel(old1 | l, bank->base + @@ -1429,14 +1386,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) } #endif /* CONFIG_PM_RUNTIME */ #else -#define omap_gpio_suspend NULL -#define omap_gpio_resume NULL #define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_resume NULL #endif static const struct dev_pm_ops gpio_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, NULL) }; |