Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[pandora-kernel.git] / arch / arm / mach-pxa / time.c
1 /*
2  * arch/arm/mach-pxa/time.c
3  *
4  * Author:      Nicolas Pitre
5  * Created:     Jun 15, 2001
6  * Copyright:   MontaVista Software Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/delay.h>
16 #include <linux/interrupt.h>
17 #include <linux/time.h>
18 #include <linux/signal.h>
19 #include <linux/errno.h>
20 #include <linux/sched.h>
21 #include <linux/clocksource.h>
22
23 #include <asm/system.h>
24 #include <asm/hardware.h>
25 #include <asm/io.h>
26 #include <asm/leds.h>
27 #include <asm/irq.h>
28 #include <asm/mach/irq.h>
29 #include <asm/mach/time.h>
30 #include <asm/arch/pxa-regs.h>
31
32
33 static int pxa_set_rtc(void)
34 {
35         unsigned long current_time = xtime.tv_sec;
36
37         if (RTSR & RTSR_ALE) {
38                 /* make sure not to forward the clock over an alarm */
39                 unsigned long alarm = RTAR;
40                 if (current_time >= alarm && alarm >= RCNR)
41                         return -ERESTARTSYS;
42         }
43         RCNR = current_time;
44         return 0;
45 }
46
47 #ifdef CONFIG_NO_IDLE_HZ
48 static unsigned long initial_match;
49 static int match_posponed;
50 #endif
51
52 static irqreturn_t
53 pxa_timer_interrupt(int irq, void *dev_id)
54 {
55         int next_match;
56
57         write_seqlock(&xtime_lock);
58
59 #ifdef CONFIG_NO_IDLE_HZ
60         if (match_posponed) {
61                 match_posponed = 0;
62                 OSMR0 = initial_match;
63         }
64 #endif
65
66         /* Loop until we get ahead of the free running timer.
67          * This ensures an exact clock tick count and time accuracy.
68          * Since IRQs are disabled at this point, coherence between
69          * lost_ticks(updated in do_timer()) and the match reg value is
70          * ensured, hence we can use do_gettimeofday() from interrupt
71          * handlers.
72          *
73          * HACK ALERT: it seems that the PXA timer regs aren't updated right
74          * away in all cases when a write occurs.  We therefore compare with
75          * 8 instead of 0 in the while() condition below to avoid missing a
76          * match if OSCR has already reached the next OSMR value.
77          * Experience has shown that up to 6 ticks are needed to work around
78          * this problem, but let's use 8 to be conservative.  Note that this
79          * affect things only when the timer IRQ has been delayed by nearly
80          * exactly one tick period which should be a pretty rare event.
81          */
82         do {
83                 timer_tick();
84                 OSSR = OSSR_M0;  /* Clear match on timer 0 */
85                 next_match = (OSMR0 += LATCH);
86         } while( (signed long)(next_match - OSCR) <= 8 );
87
88         write_sequnlock(&xtime_lock);
89
90         return IRQ_HANDLED;
91 }
92
93 static struct irqaction pxa_timer_irq = {
94         .name           = "PXA Timer Tick",
95         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
96         .handler        = pxa_timer_interrupt,
97 };
98
99 static cycle_t pxa_get_cycles(void)
100 {
101         return OSCR;
102 }
103
104 static struct clocksource clocksource_pxa = {
105         .name           = "pxa_timer",
106         .rating         = 200,
107         .read           = pxa_get_cycles,
108         .mask           = CLOCKSOURCE_MASK(32),
109         .shift          = 20,
110         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
111 };
112
113 static void __init pxa_timer_init(void)
114 {
115         struct timespec tv;
116         unsigned long flags;
117
118         set_rtc = pxa_set_rtc;
119
120         OIER = 0;               /* disable any timer interrupts */
121         OSSR = 0xf;             /* clear status on all timers */
122         setup_irq(IRQ_OST0, &pxa_timer_irq);
123         local_irq_save(flags);
124         OIER = OIER_E0;         /* enable match on timer 0 to cause interrupts */
125         OSMR0 = OSCR + LATCH;   /* set initial match */
126         local_irq_restore(flags);
127
128         /*
129          * OSCR runs continuously on PXA and is not written to,
130          * so we can use it as clock source directly.
131          */
132         clocksource_pxa.mult =
133                 clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift);
134         clocksource_register(&clocksource_pxa);
135 }
136
137 #ifdef CONFIG_NO_IDLE_HZ
138 static int pxa_dyn_tick_enable_disable(void)
139 {
140         /* nothing to do */
141         return 0;
142 }
143
144 static void pxa_dyn_tick_reprogram(unsigned long ticks)
145 {
146         if (ticks > 1) {
147                 initial_match = OSMR0;
148                 OSMR0 = initial_match + ticks * LATCH;
149                 match_posponed = 1;
150         }
151 }
152
153 static irqreturn_t
154 pxa_dyn_tick_handler(int irq, void *dev_id)
155 {
156         if (match_posponed) {
157                 match_posponed = 0;
158                 OSMR0 = initial_match;
159                 if ( (signed long)(initial_match - OSCR) <= 8 )
160                         return pxa_timer_interrupt(irq, dev_id);
161         }
162         return IRQ_NONE;
163 }
164
165 static struct dyn_tick_timer pxa_dyn_tick = {
166         .enable         = pxa_dyn_tick_enable_disable,
167         .disable        = pxa_dyn_tick_enable_disable,
168         .reprogram      = pxa_dyn_tick_reprogram,
169         .handler        = pxa_dyn_tick_handler,
170 };
171 #endif
172
173 #ifdef CONFIG_PM
174 static unsigned long osmr[4], oier;
175
176 static void pxa_timer_suspend(void)
177 {
178         osmr[0] = OSMR0;
179         osmr[1] = OSMR1;
180         osmr[2] = OSMR2;
181         osmr[3] = OSMR3;
182         oier = OIER;
183 }
184
185 static void pxa_timer_resume(void)
186 {
187         OSMR0 = osmr[0];
188         OSMR1 = osmr[1];
189         OSMR2 = osmr[2];
190         OSMR3 = osmr[3];
191         OIER = oier;
192
193         /*
194          * OSMR0 is the system timer: make sure OSCR is sufficiently behind
195          */
196         OSCR = OSMR0 - LATCH;
197 }
198 #else
199 #define pxa_timer_suspend NULL
200 #define pxa_timer_resume NULL
201 #endif
202
203 struct sys_timer pxa_timer = {
204         .init           = pxa_timer_init,
205         .suspend        = pxa_timer_suspend,
206         .resume         = pxa_timer_resume,
207 #ifdef CONFIG_NO_IDLE_HZ
208         .dyn_tick       = &pxa_dyn_tick,
209 #endif
210 };