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>
This commit is contained in:
parent
aa8e87ca61
commit
02a00cf672
8 changed files with 496 additions and 1 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue