Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[pandora-kernel.git] / arch / arm / plat-orion / time.c
1 /*
2  * arch/arm/plat-orion/time.c
3  *
4  * Marvell Orion SoC timer handling.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  *
10  * Timer 0 is used as free-running clocksource, while timer 1 is
11  * used as clock_event_device.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/timer.h>
17 #include <linux/clockchips.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <asm/sched_clock.h>
21 #include <asm/mach/time.h>
22 #include <mach/bridge-regs.h>
23 #include <mach/hardware.h>
24
25 /*
26  * Number of timer ticks per jiffy.
27  */
28 static u32 ticks_per_jiffy;
29
30
31 /*
32  * Timer block registers.
33  */
34 #define TIMER_CTRL              (TIMER_VIRT_BASE + 0x0000)
35 #define  TIMER0_EN              0x0001
36 #define  TIMER0_RELOAD_EN       0x0002
37 #define  TIMER1_EN              0x0004
38 #define  TIMER1_RELOAD_EN       0x0008
39 #define TIMER0_RELOAD           (TIMER_VIRT_BASE + 0x0010)
40 #define TIMER0_VAL              (TIMER_VIRT_BASE + 0x0014)
41 #define TIMER1_RELOAD           (TIMER_VIRT_BASE + 0x0018)
42 #define TIMER1_VAL              (TIMER_VIRT_BASE + 0x001c)
43
44
45 /*
46  * Orion's sched_clock implementation. It has a resolution of
47  * at least 7.5ns (133MHz TCLK).
48  */
49 static DEFINE_CLOCK_DATA(cd);
50
51 unsigned long long notrace sched_clock(void)
52 {
53         u32 cyc = 0xffffffff - readl(TIMER0_VAL);
54         return cyc_to_sched_clock(&cd, cyc, (u32)~0);
55 }
56
57
58 static void notrace orion_update_sched_clock(void)
59 {
60         u32 cyc = 0xffffffff - readl(TIMER0_VAL);
61         update_sched_clock(&cd, cyc, (u32)~0);
62 }
63
64 static void __init setup_sched_clock(unsigned long tclk)
65 {
66         init_sched_clock(&cd, orion_update_sched_clock, 32, tclk);
67 }
68
69 /*
70  * Clocksource handling.
71  */
72 static cycle_t orion_clksrc_read(struct clocksource *cs)
73 {
74         return 0xffffffff - readl(TIMER0_VAL);
75 }
76
77 static struct clocksource orion_clksrc = {
78         .name           = "orion_clocksource",
79         .rating         = 300,
80         .read           = orion_clksrc_read,
81         .mask           = CLOCKSOURCE_MASK(32),
82         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
83 };
84
85
86
87 /*
88  * Clockevent handling.
89  */
90 static int
91 orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
92 {
93         unsigned long flags;
94         u32 u;
95
96         if (delta == 0)
97                 return -ETIME;
98
99         local_irq_save(flags);
100
101         /*
102          * Clear and enable clockevent timer interrupt.
103          */
104         writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
105
106         u = readl(BRIDGE_MASK);
107         u |= BRIDGE_INT_TIMER1;
108         writel(u, BRIDGE_MASK);
109
110         /*
111          * Setup new clockevent timer value.
112          */
113         writel(delta, TIMER1_VAL);
114
115         /*
116          * Enable the timer.
117          */
118         u = readl(TIMER_CTRL);
119         u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN;
120         writel(u, TIMER_CTRL);
121
122         local_irq_restore(flags);
123
124         return 0;
125 }
126
127 static void
128 orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
129 {
130         unsigned long flags;
131         u32 u;
132
133         local_irq_save(flags);
134         if (mode == CLOCK_EVT_MODE_PERIODIC) {
135                 /*
136                  * Setup timer to fire at 1/HZ intervals.
137                  */
138                 writel(ticks_per_jiffy - 1, TIMER1_RELOAD);
139                 writel(ticks_per_jiffy - 1, TIMER1_VAL);
140
141                 /*
142                  * Enable timer interrupt.
143                  */
144                 u = readl(BRIDGE_MASK);
145                 writel(u | BRIDGE_INT_TIMER1, BRIDGE_MASK);
146
147                 /*
148                  * Enable timer.
149                  */
150                 u = readl(TIMER_CTRL);
151                 writel(u | TIMER1_EN | TIMER1_RELOAD_EN, TIMER_CTRL);
152         } else {
153                 /*
154                  * Disable timer.
155                  */
156                 u = readl(TIMER_CTRL);
157                 writel(u & ~TIMER1_EN, TIMER_CTRL);
158
159                 /*
160                  * Disable timer interrupt.
161                  */
162                 u = readl(BRIDGE_MASK);
163                 writel(u & ~BRIDGE_INT_TIMER1, BRIDGE_MASK);
164
165                 /*
166                  * ACK pending timer interrupt.
167                  */
168                 writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
169
170         }
171         local_irq_restore(flags);
172 }
173
174 static struct clock_event_device orion_clkevt = {
175         .name           = "orion_tick",
176         .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
177         .shift          = 32,
178         .rating         = 300,
179         .set_next_event = orion_clkevt_next_event,
180         .set_mode       = orion_clkevt_mode,
181 };
182
183 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
184 {
185         /*
186          * ACK timer interrupt and call event handler.
187          */
188         writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
189         orion_clkevt.event_handler(&orion_clkevt);
190
191         return IRQ_HANDLED;
192 }
193
194 static struct irqaction orion_timer_irq = {
195         .name           = "orion_tick",
196         .flags          = IRQF_DISABLED | IRQF_TIMER,
197         .handler        = orion_timer_interrupt
198 };
199
200 void __init orion_time_init(unsigned int irq, unsigned int tclk)
201 {
202         u32 u;
203
204         ticks_per_jiffy = (tclk + HZ/2) / HZ;
205
206         /*
207          * Set scale and timer for sched_clock
208          */
209         setup_sched_clock(tclk);
210
211         /*
212          * Setup free-running clocksource timer (interrupts
213          * disabled.)
214          */
215         writel(0xffffffff, TIMER0_VAL);
216         writel(0xffffffff, TIMER0_RELOAD);
217         u = readl(BRIDGE_MASK);
218         writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK);
219         u = readl(TIMER_CTRL);
220         writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL);
221         clocksource_register_hz(&orion_clksrc, tclk);
222
223         /*
224          * Setup clockevent timer (interrupt-driven.)
225          */
226         setup_irq(irq, &orion_timer_irq);
227         orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift);
228         orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt);
229         orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt);
230         orion_clkevt.cpumask = cpumask_of(0);
231         clockevents_register_device(&orion_clkevt);
232 }