diff options
author | Tony Lindgren <tony@atomide.com> | 2011-12-16 17:00:23 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2011-12-16 17:00:23 -0500 |
commit | 9d297f5ee1b92a84e2cd6c547c3ac1f893128359 (patch) | |
tree | cff90b5421967f17d11a7611a9c5f0fca0be4d67 /arch/arm/mach-omap2/pm34xx.c | |
parent | aacf094128759cfb29a3ce88f92d08b79b74a4e8 (diff) | |
parent | 2f31b51659c2d8315ea2888ba5b93076febe672b (diff) |
Merge branch 'tk_prm_chain_handler_devel_3.3' of git://git.pwsan.com/linux-2.6 into prcm
Conflicts:
arch/arm/mach-omap2/Makefile
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 115 |
1 files changed, 44 insertions, 71 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fa637dfdda53..53b5b1a71e0e 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -195,7 +195,7 @@ static void omap3_save_secure_ram_context(void) | |||
195 | * that any peripheral wake-up events occurring while attempting to | 195 | * that any peripheral wake-up events occurring while attempting to |
196 | * clear the PM_WKST_x are detected and cleared. | 196 | * clear the PM_WKST_x are detected and cleared. |
197 | */ | 197 | */ |
198 | static int prcm_clear_mod_irqs(s16 module, u8 regs) | 198 | static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits) |
199 | { | 199 | { |
200 | u32 wkst, fclk, iclk, clken; | 200 | u32 wkst, fclk, iclk, clken; |
201 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; | 201 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; |
@@ -207,6 +207,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
207 | 207 | ||
208 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 208 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
209 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); | 209 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); |
210 | wkst &= ~ignore_bits; | ||
210 | if (wkst) { | 211 | if (wkst) { |
211 | iclk = omap2_cm_read_mod_reg(module, iclk_off); | 212 | iclk = omap2_cm_read_mod_reg(module, iclk_off); |
212 | fclk = omap2_cm_read_mod_reg(module, fclk_off); | 213 | fclk = omap2_cm_read_mod_reg(module, fclk_off); |
@@ -222,6 +223,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
222 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); | 223 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); |
223 | omap2_prm_write_mod_reg(wkst, module, wkst_off); | 224 | omap2_prm_write_mod_reg(wkst, module, wkst_off); |
224 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | 225 | wkst = omap2_prm_read_mod_reg(module, wkst_off); |
226 | wkst &= ~ignore_bits; | ||
225 | c++; | 227 | c++; |
226 | } | 228 | } |
227 | omap2_cm_write_mod_reg(iclk, module, iclk_off); | 229 | omap2_cm_write_mod_reg(iclk, module, iclk_off); |
@@ -231,76 +233,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) | |||
231 | return c; | 233 | return c; |
232 | } | 234 | } |
233 | 235 | ||
234 | static int _prcm_int_handle_wakeup(void) | 236 | static irqreturn_t _prcm_int_handle_io(int irq, void *unused) |
235 | { | 237 | { |
236 | int c; | 238 | int c; |
237 | 239 | ||
238 | c = prcm_clear_mod_irqs(WKUP_MOD, 1); | 240 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, |
239 | c += prcm_clear_mod_irqs(CORE_MOD, 1); | 241 | ~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK)); |
240 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1); | ||
241 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
242 | c += prcm_clear_mod_irqs(CORE_MOD, 3); | ||
243 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1); | ||
244 | } | ||
245 | 242 | ||
246 | return c; | 243 | return c ? IRQ_HANDLED : IRQ_NONE; |
247 | } | 244 | } |
248 | 245 | ||
249 | /* | 246 | static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused) |
250 | * PRCM Interrupt Handler | ||
251 | * | ||
252 | * The PRM_IRQSTATUS_MPU register indicates if there are any pending | ||
253 | * interrupts from the PRCM for the MPU. These bits must be cleared in | ||
254 | * order to clear the PRCM interrupt. The PRCM interrupt handler is | ||
255 | * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear | ||
256 | * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU | ||
257 | * register indicates that a wake-up event is pending for the MPU and | ||
258 | * this bit can only be cleared if the all the wake-up events latched | ||
259 | * in the various PM_WKST_x registers have been cleared. The interrupt | ||
260 | * handler is implemented using a do-while loop so that if a wake-up | ||
261 | * event occurred during the processing of the prcm interrupt handler | ||
262 | * (setting a bit in the corresponding PM_WKST_x register and thus | ||
263 | * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) | ||
264 | * this would be handled. | ||
265 | */ | ||
266 | static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | ||
267 | { | 247 | { |
268 | u32 irqenable_mpu, irqstatus_mpu; | 248 | int c; |
269 | int c = 0; | ||
270 | |||
271 | irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
272 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
273 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
274 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
275 | irqstatus_mpu &= irqenable_mpu; | ||
276 | |||
277 | do { | ||
278 | if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK | | ||
279 | OMAP3430_IO_ST_MASK)) { | ||
280 | c = _prcm_int_handle_wakeup(); | ||
281 | |||
282 | /* | ||
283 | * Is the MPU PRCM interrupt handler racing with the | ||
284 | * IVA2 PRCM interrupt handler ? | ||
285 | */ | ||
286 | WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup " | ||
287 | "but no wakeup sources are marked\n"); | ||
288 | } else { | ||
289 | /* XXX we need to expand our PRCM interrupt handler */ | ||
290 | WARN(1, "prcm: WARNING: PRCM interrupt received, but " | ||
291 | "no code to handle it (%08x)\n", irqstatus_mpu); | ||
292 | } | ||
293 | |||
294 | omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD, | ||
295 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
296 | |||
297 | irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD, | ||
298 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | ||
299 | irqstatus_mpu &= irqenable_mpu; | ||
300 | 249 | ||
301 | } while (irqstatus_mpu); | 250 | /* |
251 | * Clear all except ST_IO and ST_IO_CHAIN for wkup module, | ||
252 | * these are handled in a separate handler to avoid acking | ||
253 | * IO events before parsing in mux code | ||
254 | */ | ||
255 | c = prcm_clear_mod_irqs(WKUP_MOD, 1, | ||
256 | OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK); | ||
257 | c += prcm_clear_mod_irqs(CORE_MOD, 1, 0); | ||
258 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0); | ||
259 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
260 | c += prcm_clear_mod_irqs(CORE_MOD, 3, 0); | ||
261 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0); | ||
262 | } | ||
302 | 263 | ||
303 | return IRQ_HANDLED; | 264 | return c ? IRQ_HANDLED : IRQ_NONE; |
304 | } | 265 | } |
305 | 266 | ||
306 | static void omap34xx_save_context(u32 *save) | 267 | static void omap34xx_save_context(u32 *save) |
@@ -581,6 +542,7 @@ static int omap3_pm_begin(suspend_state_t state) | |||
581 | disable_hlt(); | 542 | disable_hlt(); |
582 | suspend_state = state; | 543 | suspend_state = state; |
583 | omap_uart_enable_irqs(0); | 544 | omap_uart_enable_irqs(0); |
545 | omap_prcm_irq_prepare(); | ||
584 | return 0; | 546 | return 0; |
585 | } | 547 | } |
586 | 548 | ||
@@ -592,10 +554,16 @@ static void omap3_pm_end(void) | |||
592 | return; | 554 | return; |
593 | } | 555 | } |
594 | 556 | ||
557 | static void omap3_pm_finish(void) | ||
558 | { | ||
559 | omap_prcm_irq_complete(); | ||
560 | } | ||
561 | |||
595 | static const struct platform_suspend_ops omap_pm_ops = { | 562 | static const struct platform_suspend_ops omap_pm_ops = { |
596 | .begin = omap3_pm_begin, | 563 | .begin = omap3_pm_begin, |
597 | .end = omap3_pm_end, | 564 | .end = omap3_pm_end, |
598 | .enter = omap3_pm_enter, | 565 | .enter = omap3_pm_enter, |
566 | .finish = omap3_pm_finish, | ||
599 | .valid = suspend_valid_only_mem, | 567 | .valid = suspend_valid_only_mem, |
600 | }; | 568 | }; |
601 | #endif /* CONFIG_SUSPEND */ | 569 | #endif /* CONFIG_SUSPEND */ |
@@ -701,10 +669,6 @@ static void __init prcm_setup_regs(void) | |||
701 | OMAP3430_GRPSEL_GPT1_MASK | | 669 | OMAP3430_GRPSEL_GPT1_MASK | |
702 | OMAP3430_GRPSEL_GPT12_MASK, | 670 | OMAP3430_GRPSEL_GPT12_MASK, |
703 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); | 671 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); |
704 | /* For some reason IO doesn't generate wakeup event even if | ||
705 | * it is selected to mpu wakeup goup */ | ||
706 | omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK, | ||
707 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | ||
708 | 672 | ||
709 | /* Enable PM_WKEN to support DSS LPR */ | 673 | /* Enable PM_WKEN to support DSS LPR */ |
710 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, | 674 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, |
@@ -881,12 +845,21 @@ static int __init omap3_pm_init(void) | |||
881 | * supervised mode for powerdomains */ | 845 | * supervised mode for powerdomains */ |
882 | prcm_setup_regs(); | 846 | prcm_setup_regs(); |
883 | 847 | ||
884 | ret = request_irq(INT_34XX_PRCM_MPU_IRQ, | 848 | ret = request_irq(omap_prcm_event_to_irq("wkup"), |
885 | (irq_handler_t)prcm_interrupt_handler, | 849 | _prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL); |
886 | IRQF_DISABLED, "prcm", NULL); | 850 | |
851 | if (ret) { | ||
852 | pr_err("pm: Failed to request pm_wkup irq\n"); | ||
853 | goto err1; | ||
854 | } | ||
855 | |||
856 | /* IO interrupt is shared with mux code */ | ||
857 | ret = request_irq(omap_prcm_event_to_irq("io"), | ||
858 | _prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io", | ||
859 | omap3_pm_init); | ||
860 | |||
887 | if (ret) { | 861 | if (ret) { |
888 | printk(KERN_ERR "request_irq failed to register for 0x%x\n", | 862 | pr_err("pm: Failed to request pm_io irq\n"); |
889 | INT_34XX_PRCM_MPU_IRQ); | ||
890 | goto err1; | 863 | goto err1; |
891 | } | 864 | } |
892 | 865 | ||