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 && level == SUSPEND_NOTIFY)
+ dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
+ if (!dev->saved_state)
+ return -ENOMEM;
- if (!dev->saved_state)
- dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
- if (!dev->saved_state)
- return -ENOMEM;
+ save = (struct sa1111_save_data *)dev->saved_state;
- save = (struct sa1111_save_data *)dev->saved_state;
+ spin_lock_irqsave(&sachip->lock, flags);
- 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);
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);
-
- spin_unlock_irqrestore(&sachip->lock, flags);
+ 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;
}
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) {
return 0;
}
- spin_lock_irqsave(&sachip->lock, flags);
- sa1111_wake(sachip);
+ /*
+ * 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);
+ sa1111_writel(save->skcdr, base + SA1111_SKCDR);
+ sa1111_writel(save->skaud, base + SA1111_SKAUD);
+ sa1111_writel(save->skpwm0, base + SA1111_SKPWM0);
+ sa1111_writel(save->skpwm1, base + SA1111_SKPWM1);
+
+ base = sachip->base + SA1111_INTC;
+ sa1111_writel(save->intpol0, base + SA1111_INTPOL0);
+ sa1111_writel(save->intpol1, base + SA1111_INTPOL1);
+ sa1111_writel(save->inten0, base + SA1111_INTEN0);
+ sa1111_writel(save->inten1, base + SA1111_INTEN1);
+ sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
+ sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
+ sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0);
+ sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1);
+ }
- base = sachip->base;
- sa1111_writel(save->skcr, base + SA1111_SKCR);
- sa1111_writel(save->skpcr, base + SA1111_SKPCR);
- sa1111_writel(save->skcdr, base + SA1111_SKCDR);
- sa1111_writel(save->skaud, base + SA1111_SKAUD);
- sa1111_writel(save->skpwm0, base + SA1111_SKPWM0);
- sa1111_writel(save->skpwm1, base + SA1111_SKPWM1);
-
- base = sachip->base + SA1111_INTC;
- sa1111_writel(save->intpol0, base + SA1111_INTPOL0);
- sa1111_writel(save->intpol1, base + SA1111_INTPOL1);
- sa1111_writel(save->inten0, base + SA1111_INTEN0);
- sa1111_writel(save->inten1, base + SA1111_INTEN1);
- sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
- 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);
- kfree(save);
+ if (level == RESUME_ENABLE) {
+ dev->saved_state = NULL;
+ kfree(save);
+ }
return 0;
}
}
/*
- * 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)
{
.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;
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
SAVE(OIER);
SAVE(GPDR);
- SAVE(GRER);
- SAVE(GFER);
SAVE(GAFR);
SAVE(PPDR);
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;
/* 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);
RESTORE(Ser1SDCR0);
+ /*
+ * Clear the peripheral sleep-hold bit.
+ */
PSSR = PSSR_PH;
RESTORE(OSMR0);
RESTORE(OSCR);
RESTORE(OIER);
- ICLR = 0;
- ICCR = 1;
- RESTORE(ICMR);
-
/* restore current time */
xtime.tv_sec = RCNR;