From a118b5f3391fc60e1619a79f8ceb070bb7b39b2d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 22 Dec 2008 14:27:12 +0200 Subject: OMAP3: GPIO fixes for off-mode Off mode is now using the omap2 retention fix code for scanning GPIOs during off-mode transitions. All the *non_wakeup_gpios variables are now used for off-mode transition tracking on OMAP3. This patch fixes cases where GPIO state changes are missed during off-mode. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 10 ++++++---- arch/arm/plat-omap/gpio.c | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ea0000bc5358..5de07db636bd 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -376,14 +376,15 @@ void omap_sram_idle(void) core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(2); - omap2_gpio_prepare_for_retention(); if (per_next_state == PWRDM_POWER_OFF) { if (core_next_state == PWRDM_POWER_ON) { per_next_state = PWRDM_POWER_RET; pwrdm_set_next_pwrst(per_pwrdm, per_next_state); per_state_modified = 1; - } else + } else { + omap2_gpio_prepare_for_retention(); omap3_per_save_context(); + } } } @@ -454,9 +455,10 @@ void omap_sram_idle(void) /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); - if (per_prev_state == PWRDM_POWER_OFF) + if (per_prev_state == PWRDM_POWER_OFF) { omap3_per_restore_context(); - omap2_gpio_resume_after_retention(); + omap2_gpio_resume_after_retention(); + } omap_uart_resume_idle(2); if (per_state_modified) pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 45a225d09125..6216f4f09e82 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -731,7 +731,9 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA); } - } else { + } + /* This part needs to be executed always for OMAP34xx */ + if (cpu_is_omap34xx() || (bank->non_wakeup_gpios & gpio_bit)) { if (trigger != 0) bank->enabled_non_wakeup_gpios |= gpio_bit; else @@ -1845,7 +1847,8 @@ static int __init _omap_gpio_init(void) __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); } - if (i < ARRAY_SIZE(non_wakeup_gpios)) + if (cpu_is_omap24xx() && + i < ARRAY_SIZE(non_wakeup_gpios)) bank->non_wakeup_gpios = non_wakeup_gpios[i]; gpio_count = 32; } @@ -2031,10 +2034,13 @@ static int workaround_enabled; void omap2_gpio_prepare_for_retention(void) { int i, c = 0; + int min = 0; + if (cpu_is_omap34xx()) + min = 1; /* Remove triggering for all non-wakeup GPIOs. Otherwise spurious * IRQs will be generated. See OMAP2420 Errata item 1.101. */ - for (i = 0; i < gpio_bank_count; i++) { + for (i = min; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; u32 l1, l2; @@ -2088,10 +2094,13 @@ void omap2_gpio_prepare_for_retention(void) void omap2_gpio_resume_after_retention(void) { int i; + int min = 0; if (!workaround_enabled) return; - for (i = 0; i < gpio_bank_count; i++) { + if (cpu_is_omap34xx()) + min = 1; + for (i = min; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; u32 l, gen, gen0, gen1; @@ -2119,7 +2128,7 @@ void omap2_gpio_resume_after_retention(void) * horribly racy, but it's the best we can do to work around * this silicon bug. */ l ^= bank->saved_datain; - l &= bank->non_wakeup_gpios; + l &= bank->enabled_non_wakeup_gpios; /* * No need to generate IRQs for the rising edge for gpio IRQs -- cgit v1.2.1 From 699117a69f53efbdf8fddbd6d991575c0a22fd74 Mon Sep 17 00:00:00 2001 From: Chunqiu Wang Date: Wed, 24 Jun 2009 17:13:39 +0000 Subject: OMAP3: GPIO: Only enable WAKEUPEN for edge detection GPIOs According to the GPIO 'Wakeup and Interrupt' section of the TRM[1], wake-up requests can only be generated on edge transitions. Also for OMAP3, only edge GPIOs may lose interrupts when PER enters RET/OFF state, this is addressed by gpio prepare|resume idle functions [1] Section 25.5.3.1 OMAP34xx_ES3.1_TRM_V_Q Signed-off-by: Chunqiu Wang Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/gpio.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 6216f4f09e82..2f185ffaca4a 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -724,7 +724,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, OMAP4_GPIO_IRQWAKEN0); } } else { - if (trigger != 0) + /* + * GPIO wakeup request can only be generated on edge + * transitions + */ + if (trigger & IRQ_TYPE_EDGE_BOTH) __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA); else @@ -734,7 +738,13 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, } /* This part needs to be executed always for OMAP34xx */ if (cpu_is_omap34xx() || (bank->non_wakeup_gpios & gpio_bit)) { - if (trigger != 0) + /* + * Log the edge gpio and manually trigger the IRQ + * after resume if the input level changes + * to avoid irq lost during PER RET/OFF mode + * Applies for omap2 non-wakeup gpio and all omap3 gpios + */ + if (trigger & IRQ_TYPE_EDGE_BOTH) bank->enabled_non_wakeup_gpios |= gpio_bit; else bank->enabled_non_wakeup_gpios &= ~gpio_bit; -- cgit v1.2.1 From 43ffcd9a042858a9e9f9fe014bb073e55db34c67 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 27 Jan 2009 11:09:24 -0800 Subject: OMAP2/3: GPIO: generalize prepare for idle Currently, the GPIO 'prepare' hook is only called when going to off-mode, while the function is called 'prepare_for_retention.' This patch renames the function to 'prepare_for_idle' and calls it for any powersate != PWRDM_POWER_ON passing in the powerstate. The hook itself is then responsible for doing various preparation based on the powerstate. Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm24xx.c | 4 ++-- arch/arm/mach-omap2/pm34xx.c | 10 ++++------ arch/arm/plat-omap/gpio.c | 19 +++++++++++++------ arch/arm/plat-omap/include/plat/gpio.h | 4 ++-- 4 files changed, 21 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 374299ea7ade..7816c4e84a32 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -107,7 +107,7 @@ static void omap2_enter_full_retention(void) l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL; omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0); - omap2_gpio_prepare_for_retention(); + omap2_gpio_prepare_for_idle(PWRDM_POWER_RET); if (omap2_pm_debug) { omap2_pm_dump(0, 0, 0); @@ -141,7 +141,7 @@ no_sleep: tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC; omap2_pm_dump(0, 1, tmp); } - omap2_gpio_resume_after_retention(); + omap2_gpio_resume_after_idle(); clk_enable(osc_ck); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 5de07db636bd..468e1e3321e0 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -376,15 +376,14 @@ void omap_sram_idle(void) core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(2); + omap2_gpio_prepare_for_idle(per_next_state); if (per_next_state == PWRDM_POWER_OFF) { if (core_next_state == PWRDM_POWER_ON) { per_next_state = PWRDM_POWER_RET; pwrdm_set_next_pwrst(per_pwrdm, per_next_state); per_state_modified = 1; - } else { - omap2_gpio_prepare_for_retention(); + } else omap3_per_save_context(); - } } } @@ -455,10 +454,9 @@ void omap_sram_idle(void) /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); - if (per_prev_state == PWRDM_POWER_OFF) { + omap2_gpio_resume_after_idle(); + if (per_prev_state == PWRDM_POWER_OFF) omap3_per_restore_context(); - omap2_gpio_resume_after_retention(); - } omap_uart_resume_idle(2); if (per_state_modified) pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 2f185ffaca4a..1c81340ce65c 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -27,6 +27,7 @@ #include #include #include +#include /* * OMAP1510 GPIO registers @@ -2041,19 +2042,24 @@ static struct sys_device omap_gpio_device = { static int workaround_enabled; -void omap2_gpio_prepare_for_retention(void) +void omap2_gpio_prepare_for_idle(int power_state) { int i, c = 0; int min = 0; if (cpu_is_omap34xx()) min = 1; - /* Remove triggering for all non-wakeup GPIOs. Otherwise spurious - * IRQs will be generated. See OMAP2420 Errata item 1.101. */ + for (i = min; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; u32 l1, l2; + if (power_state > PWRDM_POWER_OFF) + continue; + + /* If going to OFF, remove triggering for all + * non-wakeup GPIOs. Otherwise spurious IRQs will be + * generated. See OMAP2420 Errata item 1.101. */ if (!(bank->enabled_non_wakeup_gpios)) continue; @@ -2101,19 +2107,20 @@ void omap2_gpio_prepare_for_retention(void) workaround_enabled = 1; } -void omap2_gpio_resume_after_retention(void) +void omap2_gpio_resume_after_idle(void) { int i; int min = 0; - if (!workaround_enabled) - return; if (cpu_is_omap34xx()) min = 1; for (i = min; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; u32 l, gen, gen0, gen1; + if (!workaround_enabled) + continue; + if (!(bank->enabled_non_wakeup_gpios)) continue; diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index de7c54731cbe..de1c604962eb 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -72,8 +72,8 @@ IH_GPIO_BASE + (nr)) extern int omap_gpio_init(void); /* Call from board init only */ -extern void omap2_gpio_prepare_for_retention(void); -extern void omap2_gpio_resume_after_retention(void); +extern void omap2_gpio_prepare_for_idle(int power_state); +extern void omap2_gpio_resume_after_idle(void); extern void omap_set_gpio_debounce(int gpio, int enable); extern void omap_set_gpio_debounce_time(int gpio, int enable); extern void omap_gpio_save_context(void); -- cgit v1.2.1 From 8865b9b6d5e1601453ea20c37eb981c6ccc3f4e9 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 27 Jan 2009 11:15:34 -0800 Subject: OMAP3: GPIO: disable GPIO debounce clocks on idle Ensure GPIO debounce clocks are disabled when idle. Otherwise, clocks will prevent PER powerdomain from entering retention. Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/gpio.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 1c81340ce65c..c6e1de527116 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -196,6 +196,7 @@ struct gpio_bank { struct gpio_chip chip; struct clk *dbck; u32 mod_usage; + u32 dbck_enable_mask; }; #define METHOD_MPUIO 0 @@ -647,6 +648,7 @@ void omap_set_gpio_debounce(int gpio, int enable) goto done; if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + bank->dbck_enable_mask = val; if (enable) clk_enable(bank->dbck); else @@ -2054,6 +2056,9 @@ void omap2_gpio_prepare_for_idle(int power_state) struct gpio_bank *bank = &gpio_bank[i]; u32 l1, l2; + if (bank->dbck_enable_mask) + clk_disable(bank->dbck); + if (power_state > PWRDM_POWER_OFF) continue; @@ -2118,6 +2123,9 @@ void omap2_gpio_resume_after_idle(void) struct gpio_bank *bank = &gpio_bank[i]; u32 l, gen, gen0, gen1; + if (bank->dbck_enable_mask) + clk_enable(bank->dbck); + if (!workaround_enabled) continue; -- cgit v1.2.1 From c872670799d5a41fe2c1f2ccf7c531b5661dcfba Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 3 May 2010 15:53:57 -0700 Subject: OMAP3: GPIO: Removed a couple of unneeded registers from context save/restore setwkuena and setdataout are covered already by wake_en and dataout fields. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/gpio.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index c6e1de527116..b895cc9c6b78 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -305,8 +305,6 @@ struct omap3_gpio_regs { u32 risingdetect; u32 fallingdetect; u32 dataout; - u32 setwkuena; - u32 setdataout; }; static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; @@ -2241,10 +2239,6 @@ void omap_gpio_save_context(void) __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); gpio_context[i].dataout = __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); - gpio_context[i].setwkuena = - __raw_readl(bank->base + OMAP24XX_GPIO_SETWKUENA); - gpio_context[i].setdataout = - __raw_readl(bank->base + OMAP24XX_GPIO_SETDATAOUT); } } @@ -2277,10 +2271,6 @@ void omap_gpio_restore_context(void) bank->base + OMAP24XX_GPIO_FALLINGDETECT); __raw_writel(gpio_context[i].dataout, bank->base + OMAP24XX_GPIO_DATAOUT); - __raw_writel(gpio_context[i].setwkuena, - bank->base + OMAP24XX_GPIO_SETWKUENA); - __raw_writel(gpio_context[i].setdataout, - bank->base + OMAP24XX_GPIO_SETDATAOUT); } } #endif -- cgit v1.2.1 From d009559a4215c71694b1a29ec0e520453087a9f6 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 14 Dec 2009 15:14:51 -0800 Subject: OMAP: GPIO: remove duplicate debugfs interface The generic gpiolib provides a debugfs interface to GPIOs which provides identical (but nicer looking) data as the OMAP specific one. This patch completely drops the OMAP specific interface (/debug/omap_gpio) in favor of using the generic one (/debug/gpio.) Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/gpio.c | 107 ---------------------------------------------- 1 file changed, 107 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index b895cc9c6b78..955597fd6d35 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -2310,110 +2310,3 @@ static int __init omap_gpio_sysinit(void) } arch_initcall(omap_gpio_sysinit); - - -#ifdef CONFIG_DEBUG_FS - -#include -#include - -static int dbg_gpio_show(struct seq_file *s, void *unused) -{ - unsigned i, j, gpio; - - for (i = 0, gpio = 0; i < gpio_bank_count; i++) { - struct gpio_bank *bank = gpio_bank + i; - unsigned bankwidth = 16; - u32 mask = 1; - - if (bank_is_mpuio(bank)) - gpio = OMAP_MPUIO(0); - else if (cpu_class_is_omap2() || cpu_is_omap7xx()) - bankwidth = 32; - - for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { - unsigned irq, value, is_in, irqstat; - const char *label; - - label = gpiochip_is_requested(&bank->chip, j); - if (!label) - continue; - - irq = bank->virtual_irq_start + j; - value = gpio_get_value(gpio); - is_in = gpio_is_input(bank, mask); - - if (bank_is_mpuio(bank)) - seq_printf(s, "MPUIO %2d ", j); - else - seq_printf(s, "GPIO %3d ", gpio); - seq_printf(s, "(%-20.20s): %s %s", - label, - is_in ? "in " : "out", - value ? "hi" : "lo"); - -/* FIXME for at least omap2, show pullup/pulldown state */ - - irqstat = irq_desc[irq].status; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) - if (is_in && ((bank->suspend_wakeup & mask) - || irqstat & IRQ_TYPE_SENSE_MASK)) { - char *trigger = NULL; - - switch (irqstat & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_FALLING: - trigger = "falling"; - break; - case IRQ_TYPE_EDGE_RISING: - trigger = "rising"; - break; - case IRQ_TYPE_EDGE_BOTH: - trigger = "bothedge"; - break; - case IRQ_TYPE_LEVEL_LOW: - trigger = "low"; - break; - case IRQ_TYPE_LEVEL_HIGH: - trigger = "high"; - break; - case IRQ_TYPE_NONE: - trigger = "(?)"; - break; - } - seq_printf(s, ", irq-%d %-8s%s", - irq, trigger, - (bank->suspend_wakeup & mask) - ? " wakeup" : ""); - } -#endif - seq_printf(s, "\n"); - } - - if (bank_is_mpuio(bank)) { - seq_printf(s, "\n"); - gpio = 0; - } - } - return 0; -} - -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, &inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init omap_gpio_debuginit(void) -{ - (void) debugfs_create_file("omap_gpio", S_IRUGO, - NULL, NULL, &debug_fops); - return 0; -} -late_initcall(omap_gpio_debuginit); -#endif -- cgit v1.2.1