]> git.hungrycats.org Git - linux/commitdiff
[ARM] Add better PM support to SA1111 and SA11x0.
authorRussell King <rmk@flint.arm.linux.org.uk>
Thu, 6 Mar 2003 16:09:12 +0000 (16:09 +0000)
committerRussell King <rmk@flint.arm.linux.org.uk>
Thu, 6 Mar 2003 16:09:12 +0000 (16:09 +0000)
This follows our existing PM interfaces.

arch/arm/common/sa1111.c
arch/arm/mach-sa1100/irq.c
arch/arm/mach-sa1100/pm.c

index 1121b4919ea24d06cf46698e82eff6432a6a30d9..d0e22f3ac2aa8d262c55fc82400440d6f26f155e 100644 (file)
@@ -743,25 +743,23 @@ 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 && 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);
@@ -779,26 +777,21 @@ 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);
-
-               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;
 }
 
@@ -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,29 +830,42 @@ static int sa1111_resume(struct device *dev, u32 level)
                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;
 }
index 87e4f29511a9361cdf38fa5d50f99d841780c9a5..0827af01742a0bed6b814d1d95f9f44cf1203e88 100644 (file)
@@ -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;
index 0283e4d4191f373b2bd70bf8f0603a7b2a9def53..ca55d99f678ed20b3887dbccd6ff3c0da9609cc8 100644 (file)
@@ -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;