summaryrefslogtreecommitdiffstats
path: root/arch/avr32/mach-at32ap/intc.c
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2008-02-24 13:51:38 +0100
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-02 11:05:01 +0200
commit02a00cf672a37292c31bbdde191712bfa40a4f1d (patch)
tree5588f7cd600056861fe1313abe7b47b9c051eab6 /arch/avr32/mach-at32ap/intc.c
parentaa8e87ca619a3d1944874e85d74fda90607c73b9 (diff)
avr32: Power Management support ("standby" and "mem" modes)
Implement Standby support. In this mode, we'll suspend all drivers, put the SDRAM in self-refresh mode and switch off the HSB bus ("frozen" mode.) Implement Suspend-to-mem support. In this mode, we suspend all drivers, put the SDRAM into self-refresh mode and switch off all internal clocks except the 32 kHz oscillator ("stop" mode.) The lowest-level suspend code runs from a small portion of SRAM allocated at startup time. This gets rid of a small potential race with the SDRAM where we might try to enter self-refresh mode in the middle of an icache burst. We also relocate all interrupt and exception handlers to SRAM during the small window when we enter and exit the low-power modes. We don't need to do any special tricks to start and stop the PLL. The main clock is automatically gated by hardware until the PLL is stable. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/mach-at32ap/intc.c')
-rw-r--r--arch/avr32/mach-at32ap/intc.c54
1 files changed, 53 insertions, 1 deletions
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index 644a3fb8c16..994c4545e2b 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -22,6 +22,10 @@ struct intc {
void __iomem *regs;
struct irq_chip chip;
struct sys_device sysdev;
+#ifdef CONFIG_PM
+ unsigned long suspend_ipr;
+ unsigned long saved_ipr[64];
+#endif
};
extern struct platform_device at32_intc0_device;
@@ -138,8 +142,56 @@ fail:
panic("Interrupt controller initialization failed!\n");
}
+#ifdef CONFIG_PM
+void intc_set_suspend_handler(unsigned long offset)
+{
+ intc0.suspend_ipr = offset;
+}
+
+static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+{
+ struct intc *intc = container_of(sdev, struct intc, sysdev);
+ int i;
+
+ if (unlikely(!irqs_disabled())) {
+ pr_err("intc_suspend: called with interrupts enabled\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!intc->suspend_ipr)) {
+ pr_err("intc_suspend: suspend_ipr not initialized\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 64; i++) {
+ intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
+ intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+ }
+
+ return 0;
+}
+
+static int intc_resume(struct sys_device *sdev)
+{
+ struct intc *intc = container_of(sdev, struct intc, sysdev);
+ int i;
+
+ WARN_ON(!irqs_disabled());
+
+ for (i = 0; i < 64; i++)
+ intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+
+ return 0;
+}
+#else
+#define intc_suspend NULL
+#define intc_resume NULL
+#endif
+
static struct sysdev_class intc_class = {
- .name = "intc",
+ .name = "intc",
+ .suspend = intc_suspend,
+ .resume = intc_resume,
};
static int __init intc_init_sysdev(void)