[ARM] 4507/1: pxa2xx clock_event_device
[safe/jmp/linux-2.6] / arch / arm / mach-pxa / time.c
1 /*
2  * arch/arm/mach-pxa/time.c
3  *
4  * PXA clocksource, clockevents, and OST interrupt handlers.
5  * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
6  *
7  * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
8  * by MontaVista Software, Inc.  (Nico, your code rocks!)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/interrupt.h>
18 #include <linux/clockchips.h>
19
20 #include <asm/mach/irq.h>
21 #include <asm/mach/time.h>
22 #include <asm/arch/pxa-regs.h>
23
24 static irqreturn_t
25 pxa_ost0_interrupt(int irq, void *dev_id)
26 {
27         int next_match;
28         struct clock_event_device *c = dev_id;
29
30         if (c->mode == CLOCK_EVT_MODE_ONESHOT) {
31                 /* Disarm the compare/match, signal the event. */
32                 OIER &= ~OIER_E0;
33                 c->event_handler(c);
34         } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
35                 /* Call the event handler as many times as necessary
36                  * to recover missed events, if any (if we update
37                  * OSMR0 and OSCR0 is still ahead of us, we've missed
38                  * the event).  As we're dealing with that, re-arm the
39                  * compare/match for the next event.
40                  *
41                  * HACK ALERT:
42                  *
43                  * There's a latency between the instruction that
44                  * writes to OSMR0 and the actual commit to the
45                  * physical hardware, because the CPU doesn't (have
46                  * to) run at bus speed, there's a write buffer
47                  * between the CPU and the bus, etc. etc.  So if the
48                  * target OSCR0 is "very close", to the OSMR0 load
49                  * value, the update to OSMR0 might not get to the
50                  * hardware in time and we'll miss that interrupt.
51                  *
52                  * To be safe, if the new OSMR0 is "very close" to the
53                  * target OSCR0 value, we call the event_handler as
54                  * though the event actually happened.  According to
55                  * Nico's comment in the previous version of this
56                  * code, experience has shown that 6 OSCR ticks is
57                  * "very close" but he went with 8.  We will use 16,
58                  * based on the results of testing on PXA270.
59                  *
60                  * To be doubly sure, we also tell clkevt via
61                  * clockevents_register_device() not to ask for
62                  * anything that might put us "very close".
63          */
64 #define MIN_OSCR_DELTA 16
65         do {
66                         OSSR = OSSR_M0;
67                 next_match = (OSMR0 += LATCH);
68                         c->event_handler(c);
69                 } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
70                          && (c->mode == CLOCK_EVT_MODE_PERIODIC));
71         }
72
73         return IRQ_HANDLED;
74 }
75
76 static int
77 pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
78 {
79         unsigned long irqflags;
80
81         raw_local_irq_save(irqflags);
82         OSMR0 = OSCR + delta;
83         OSSR = OSSR_M0;
84         OIER |= OIER_E0;
85         raw_local_irq_restore(irqflags);
86         return 0;
87 }
88
89 static void
90 pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
91 {
92         unsigned long irqflags;
93
94         switch (mode) {
95         case CLOCK_EVT_MODE_PERIODIC:
96                 raw_local_irq_save(irqflags);
97                 OSMR0 = OSCR + LATCH;
98                 OSSR = OSSR_M0;
99                 OIER |= OIER_E0;
100                 raw_local_irq_restore(irqflags);
101                 break;
102
103         case CLOCK_EVT_MODE_ONESHOT:
104                 raw_local_irq_save(irqflags);
105                 OIER &= ~OIER_E0;
106                 raw_local_irq_restore(irqflags);
107                 break;
108
109         case CLOCK_EVT_MODE_UNUSED:
110         case CLOCK_EVT_MODE_SHUTDOWN:
111                 /* initializing, released, or preparing for suspend */
112                 raw_local_irq_save(irqflags);
113                 OIER &= ~OIER_E0;
114                 raw_local_irq_restore(irqflags);
115                 break;
116         }
117 }
118
119 static struct clock_event_device ckevt_pxa_osmr0 = {
120         .name           = "osmr0",
121         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
122         .shift          = 32,
123         .rating         = 200,
124         .cpumask        = CPU_MASK_CPU0,
125         .set_next_event = pxa_osmr0_set_next_event,
126         .set_mode       = pxa_osmr0_set_mode,
127 };
128
129 static cycle_t pxa_read_oscr(void)
130 {
131         return OSCR;
132 }
133
134 static struct clocksource cksrc_pxa_oscr0 = {
135         .name           = "oscr0",
136         .rating         = 200,
137         .read           = pxa_read_oscr,
138         .mask           = CLOCKSOURCE_MASK(32),
139         .shift          = 20,
140         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
141 };
142
143 static struct irqaction pxa_ost0_irq = {
144         .name           = "ost0",
145         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
146         .handler        = pxa_ost0_interrupt,
147         .dev_id         = &ckevt_pxa_osmr0,
148 };
149
150 static void __init pxa_timer_init(void)
151 {
152         OIER = 0;
153         OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
154
155         ckevt_pxa_osmr0.mult =
156                 div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift);
157         ckevt_pxa_osmr0.max_delta_ns =
158                 clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
159         ckevt_pxa_osmr0.min_delta_ns =
160                 clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1;
161
162         cksrc_pxa_oscr0.mult =
163                 clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift);
164
165         setup_irq(IRQ_OST0, &pxa_ost0_irq);
166
167         clocksource_register(&cksrc_pxa_oscr0);
168         clockevents_register_device(&ckevt_pxa_osmr0);
169 }
170
171 #ifdef CONFIG_PM
172 static unsigned long osmr[4], oier;
173
174 static void pxa_timer_suspend(void)
175 {
176         osmr[0] = OSMR0;
177         osmr[1] = OSMR1;
178         osmr[2] = OSMR2;
179         osmr[3] = OSMR3;
180         oier = OIER;
181 }
182
183 static void pxa_timer_resume(void)
184 {
185         OSMR0 = osmr[0];
186         OSMR1 = osmr[1];
187         OSMR2 = osmr[2];
188         OSMR3 = osmr[3];
189         OIER = oier;
190
191         /*
192          * OSCR0 is the system timer, which has to increase
193          * monotonically until it rolls over in hardware.  The value
194          * (OSMR0 - LATCH) is OSCR0 at the most recent system tick,
195          * which is a handy value to restore to OSCR0.
196          */
197         OSCR = OSMR0 - LATCH;
198 }
199 #else
200 #define pxa_timer_suspend NULL
201 #define pxa_timer_resume NULL
202 #endif
203
204 struct sys_timer pxa_timer = {
205         .init           = pxa_timer_init,
206         .suspend        = pxa_timer_suspend,
207         .resume         = pxa_timer_resume,
208 };