vserver 1.9.5.x5
[linux-2.6.git] / arch / arm / mach-pxa / time.c
index a49fc02..473fb61 100644 (file)
@@ -75,6 +75,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        int next_match;
 
+       write_seqlock(&xtime_lock);
+
        /* Loop until we get ahead of the free running timer.
         * This ensures an exact clock tick count and time accuracy.
         * IRQs are disabled inside the loop to ensure coherence between
@@ -96,6 +98,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                next_match = (OSMR0 += LATCH);
        } while( (signed long)(next_match - OSCR) <= 8 );
 
+       write_sequnlock(&xtime_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -105,11 +109,10 @@ static struct irqaction pxa_timer_irq = {
        .handler        = pxa_timer_interrupt
 };
 
-void __init pxa_init_time(void)
+static void __init pxa_timer_init(void)
 {
        struct timespec tv;
 
-       gettimeoffset = pxa_gettimeoffset;
        set_rtc = pxa_set_rtc;
 
        tv.tv_nsec = 0;
@@ -123,3 +126,39 @@ void __init pxa_init_time(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_PM
+static unsigned long osmr[4], oier;
+
+static void pxa_timer_suspend(void)
+{
+       osmr[0] = OSMR0;
+       osmr[1] = OSMR1;
+       osmr[2] = OSMR2;
+       osmr[3] = OSMR3;
+       oier = OIER;
+}
+
+static void pxa_timer_resume(void)
+{
+       OSMR0 = osmr[0];
+       OSMR1 = osmr[1];
+       OSMR2 = osmr[2];
+       OSMR3 = osmr[3];
+       OIER = oier;
+
+       /*
+        * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+        */
+       OSCR = OSMR0 - LATCH;
+}
+#else
+#define pxa_timer_suspend NULL
+#define pxa_timer_resume NULL
+#endif
+
+struct sys_timer pxa_timer = {
+       .init           = pxa_timer_init,
+       .suspend        = pxa_timer_suspend,
+       .resume         = pxa_timer_resume,
+       .offset         = pxa_gettimeoffset,
+};