Commit 25e9b4db authored by Russell King's avatar Russell King

[ARM] Add better PM support to SA1111 and SA11x0.

This follows our existing PM interfaces.
parent 7725cb81
......@@ -743,18 +743,11 @@ struct sa1111_save_data {
static int sa1111_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1111 *sachip = dev_get_drvdata(dev);
struct sa1111_save_data *save;
unsigned long flags;
char *base;
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE ||
level == SUSPEND_DISABLE ||
level == SUSPEND_POWER_DOWN) {
struct sa1111_save_data *save;
if (!dev->saved_state)
if (!dev->saved_state && level == SUSPEND_NOTIFY)
dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
......@@ -762,6 +755,11 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level)
save = (struct sa1111_save_data *)dev->saved_state;
spin_lock_irqsave(&sachip->lock, flags);
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE) {
base = sachip->base;
save->skcr = sa1111_readl(base + SA1111_SKCR);
save->skpcr = sa1111_readl(base + SA1111_SKPCR);
......@@ -779,25 +777,20 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level)
save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0);
save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/*
* Disable.
*/
if (level == SUSPEND_DISABLE && state == 4) {
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
base = sachip->base;
if (level == SUSPEND_POWER_DOWN && state == 4) {
unsigned int val = sa1111_readl(sachip->base + SA1111_SKCR);
sa1111_writel(0, base + SA1111_SKPWM0);
sa1111_writel(0, base + SA1111_SKPWM1);
val = sa1111_readl(base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
sa1111_writel(0, sachip->base + SA1111_SKPWM0);
sa1111_writel(0, sachip->base + SA1111_SKPWM1);
}
spin_unlock_irqrestore(&sachip->lock, flags);
}
return 0;
}
......@@ -819,17 +812,15 @@ static int sa1111_resume(struct device *dev, u32 level)
unsigned long flags, id;
char *base;
if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
return 0;
save = (struct sa1111_save_data *)dev->saved_state;
if (!save)
return 0;
dev->saved_state = NULL;
spin_lock_irqsave(&sachip->lock, flags);
/*
* Ensure that the SA1111 is still here.
* FIXME: shouldn't do this here.
*/
id = sa1111_readl(sachip->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
......@@ -839,9 +830,17 @@ static int sa1111_resume(struct device *dev, u32 level)
return 0;
}
spin_lock_irqsave(&sachip->lock, flags);
/*
* First of all, wake up the chip.
*/
if (level == RESUME_POWER_ON) {
sa1111_wake(sachip);
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0);
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1);
}
if (level == RESUME_RESTORE_STATE) {
base = sachip->base;
sa1111_writel(save->skcr, base + SA1111_SKCR);
sa1111_writel(save->skpcr, base + SA1111_SKPCR);
......@@ -859,9 +858,14 @@ static int sa1111_resume(struct device *dev, u32 level)
sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0);
sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1);
}
spin_unlock_irqrestore(&sachip->lock, flags);
if (level == RESUME_ENABLE) {
dev->saved_state = NULL;
kfree(save);
}
return 0;
}
......
......@@ -68,7 +68,7 @@ static int sa1100_gpio_type(unsigned int irq, unsigned int type)
}
/*
* GPIO IRQs must be acknoledged. This is for IRQs from 0 to 10.
* GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10.
*/
static void sa1100_low_gpio_ack(unsigned int irq)
{
......@@ -211,6 +211,99 @@ static struct resource irq_resource = {
.end = 0x9005ffff,
};
struct sa1100irq_state {
unsigned int saved;
unsigned int icmr;
unsigned int iclr;
unsigned int iccr;
};
static int sa1100irq_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1100irq_state *st;
if (!dev->saved_state && level == SUSPEND_NOTIFY)
dev->saved_state = kmalloc(sizeof(struct sa1100irq_state),
GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
if (level == SUSPEND_POWER_DOWN) {
st = (struct sa1100irq_state *)dev->saved_state;
st->saved = 1;
st->icmr = ICMR;
st->iclr = ICLR;
st->iccr = ICCR;
/*
* Disable all GPIO-based interrupts.
*/
ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7|
IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2|
IC_GPIO1|IC_GPIO0);
/*
* Set the appropriate edges for wakeup.
*/
GRER = PWER & GPIO_IRQ_rising_edge;
GFER = PWER & GPIO_IRQ_falling_edge;
/*
* Clear any pending GPIO interrupts.
*/
GEDR = GEDR;
}
return 0;
}
static int sa1100irq_resume(struct device *dev, u32 level)
{
struct sa1100irq_state *st;
if (level == RESUME_POWER_ON) {
st = (struct sa1100irq_state *)dev->saved_state;
dev->saved_state = NULL;
if (st->saved) {
ICCR = st->iccr;
ICLR = st->iclr;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
ICMR = st->icmr;
}
kfree(st);
}
return 0;
}
static struct device_driver sa1100irq_driver = {
.name = "sa11x0-irq",
.bus = &system_bus_type,
.suspend = sa1100irq_suspend,
.resume = sa1100irq_resume,
};
static struct sys_device sa1100irq_device = {
.name = "irq",
.id = 0,
.dev = {
.name = "Intel SA11x0 [Interrupt Controller]",
.driver = &sa1100irq_driver,
},
};
static int __init sa1100irq_init_devicefs(void)
{
driver_register(&sa1100irq_driver);
return sys_device_register(&sa1100irq_device);
}
device_initcall(sa1100irq_init_devicefs);
void __init sa1100_init_irq(void)
{
unsigned int irq;
......
......@@ -45,10 +45,9 @@ enum { SLEEP_SAVE_SP = 0,
SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
SLEEP_SAVE_ICMR,
SLEEP_SAVE_Ser1SDCR0,
SLEEP_SAVE_SIZE
......@@ -71,8 +70,6 @@ int pm_do_suspend(void)
SAVE(OIER);
SAVE(GPDR);
SAVE(GRER);
SAVE(GFER);
SAVE(GAFR);
SAVE(PPDR);
......@@ -82,13 +79,6 @@ int pm_do_suspend(void)
SAVE(Ser1SDCR0);
SAVE(ICMR);
/* ... maybe a global variable initialized by arch code to set this? */
GRER = PWER;
GFER = 0;
GEDR = GEDR;
/* Clear previous reset status */
RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
......@@ -98,22 +88,23 @@ int pm_do_suspend(void)
/* go zzz */
sa1100_cpu_suspend();
/* ensure not to come back here if it wasn't intended */
/*
* Ensure not to come back here if it wasn't intended
*/
PSPR = 0;
#ifdef DEBUG
printk(KERN_DEBUG "*** made it back from resume\n");
#endif
/*
* Ensure interrupt sources are disabled; we will re-init
* the interrupt subsystem via the device manager.
*/
ICLR = 0;
ICCR = 1;
ICMR = 0;
/* restore registers */
RESTORE(GPDR);
RESTORE(GRER);
RESTORE(GFER);
RESTORE(GAFR);
/* clear any edge detect bit */
GEDR = GEDR;
RESTORE(PPDR);
RESTORE(PPSR);
RESTORE(PPAR);
......@@ -121,6 +112,9 @@ int pm_do_suspend(void)
RESTORE(Ser1SDCR0);
/*
* Clear the peripheral sleep-hold bit.
*/
PSSR = PSSR_PH;
RESTORE(OSMR0);
......@@ -130,10 +124,6 @@ int pm_do_suspend(void)
RESTORE(OSCR);
RESTORE(OIER);
ICLR = 0;
ICCR = 1;
RESTORE(ICMR);
/* restore current time */
xtime.tv_sec = RCNR;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment