]> bbs.cooldavid.org Git - net-next-2.6.git/blame - arch/arm/mach-integrator/core.c
ARM: Integrator: convert to generic clockevent support
[net-next-2.6.git] / arch / arm / mach-integrator / core.c
CommitLineData
1da177e4
LT
1/*
2 * linux/arch/arm/mach-integrator/core.c
3 *
4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 */
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/device.h>
14#include <linux/spinlock.h>
15#include <linux/interrupt.h>
a03d4d27 16#include <linux/irq.h>
1da177e4 17#include <linux/sched.h>
20cf33ea 18#include <linux/smp.h>
fbb18a27 19#include <linux/termios.h>
a62c80e5 20#include <linux/amba/bus.h>
fbb18a27 21#include <linux/amba/serial.h>
b9cedda2 22#include <linux/clocksource.h>
13edd86d 23#include <linux/clockchips.h>
fced80c7 24#include <linux/io.h>
1da177e4 25
d72fbdf0
RK
26#include <asm/clkdev.h>
27#include <mach/clkdev.h>
a09e64fb 28#include <mach/hardware.h>
a285edcf 29#include <mach/platform.h>
1da177e4 30#include <asm/irq.h>
b720f732 31#include <asm/hardware/arm_timer.h>
a09e64fb 32#include <mach/cm.h>
1da177e4
LT
33#include <asm/system.h>
34#include <asm/leds.h>
35#include <asm/mach/time.h>
36
37#include "common.h"
38
fbb18a27
RK
39static struct amba_pl010_data integrator_uart_data;
40
1da177e4
LT
41static struct amba_device rtc_device = {
42 .dev = {
1d559e29 43 .init_name = "mb:15",
1da177e4
LT
44 },
45 .res = {
46 .start = INTEGRATOR_RTC_BASE,
47 .end = INTEGRATOR_RTC_BASE + SZ_4K - 1,
48 .flags = IORESOURCE_MEM,
49 },
50 .irq = { IRQ_RTCINT, NO_IRQ },
51 .periphid = 0x00041030,
52};
53
54static struct amba_device uart0_device = {
55 .dev = {
1d559e29 56 .init_name = "mb:16",
fbb18a27 57 .platform_data = &integrator_uart_data,
1da177e4
LT
58 },
59 .res = {
60 .start = INTEGRATOR_UART0_BASE,
61 .end = INTEGRATOR_UART0_BASE + SZ_4K - 1,
62 .flags = IORESOURCE_MEM,
63 },
64 .irq = { IRQ_UARTINT0, NO_IRQ },
65 .periphid = 0x0041010,
66};
67
68static struct amba_device uart1_device = {
69 .dev = {
1d559e29 70 .init_name = "mb:17",
fbb18a27 71 .platform_data = &integrator_uart_data,
1da177e4
LT
72 },
73 .res = {
74 .start = INTEGRATOR_UART1_BASE,
75 .end = INTEGRATOR_UART1_BASE + SZ_4K - 1,
76 .flags = IORESOURCE_MEM,
77 },
78 .irq = { IRQ_UARTINT1, NO_IRQ },
79 .periphid = 0x0041010,
80};
81
82static struct amba_device kmi0_device = {
83 .dev = {
1d559e29 84 .init_name = "mb:18",
1da177e4
LT
85 },
86 .res = {
87 .start = KMI0_BASE,
88 .end = KMI0_BASE + SZ_4K - 1,
89 .flags = IORESOURCE_MEM,
90 },
91 .irq = { IRQ_KMIINT0, NO_IRQ },
92 .periphid = 0x00041050,
93};
94
95static struct amba_device kmi1_device = {
96 .dev = {
1d559e29 97 .init_name = "mb:19",
1da177e4
LT
98 },
99 .res = {
100 .start = KMI1_BASE,
101 .end = KMI1_BASE + SZ_4K - 1,
102 .flags = IORESOURCE_MEM,
103 },
104 .irq = { IRQ_KMIINT1, NO_IRQ },
105 .periphid = 0x00041050,
106};
107
108static struct amba_device *amba_devs[] __initdata = {
109 &rtc_device,
110 &uart0_device,
111 &uart1_device,
112 &kmi0_device,
113 &kmi1_device,
114};
115
d72fbdf0
RK
116/*
117 * These are fixed clocks.
118 */
119static struct clk clk24mhz = {
120 .rate = 24000000,
121};
122
123static struct clk uartclk = {
124 .rate = 14745600,
125};
126
a93ea9b3 127static struct clk_lookup lookups[] = {
d72fbdf0
RK
128 { /* UART0 */
129 .dev_id = "mb:16",
130 .clk = &uartclk,
131 }, { /* UART1 */
132 .dev_id = "mb:17",
133 .clk = &uartclk,
134 }, { /* KMI0 */
135 .dev_id = "mb:18",
136 .clk = &clk24mhz,
137 }, { /* KMI1 */
138 .dev_id = "mb:19",
139 .clk = &clk24mhz,
140 }, { /* MMCI - IntegratorCP */
141 .dev_id = "mb:1c",
142 .clk = &uartclk,
143 }
144};
145
1da177e4
LT
146static int __init integrator_init(void)
147{
148 int i;
149
0a0300dc 150 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
d72fbdf0 151
1da177e4
LT
152 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
153 struct amba_device *d = amba_devs[i];
154 amba_device_register(d, &iomem_resource);
155 }
156
157 return 0;
158}
159
160arch_initcall(integrator_init);
161
fbb18a27
RK
162/*
163 * On the Integrator platform, the port RTS and DTR are provided by
164 * bits in the following SC_CTRLS register bits:
165 * RTS DTR
166 * UART0 7 6
167 * UART1 5 4
168 */
169#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
170#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
171
172static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
173{
174 unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
175
176 if (dev == &uart0_device) {
177 rts_mask = 1 << 4;
178 dtr_mask = 1 << 5;
179 } else {
180 rts_mask = 1 << 6;
181 dtr_mask = 1 << 7;
182 }
183
184 if (mctrl & TIOCM_RTS)
185 ctrlc |= rts_mask;
186 else
187 ctrls |= rts_mask;
188
189 if (mctrl & TIOCM_DTR)
190 ctrlc |= dtr_mask;
191 else
192 ctrls |= dtr_mask;
193
194 __raw_writel(ctrls, SC_CTRLS);
195 __raw_writel(ctrlc, SC_CTRLC);
196}
197
198static struct amba_pl010_data integrator_uart_data = {
199 .set_mctrl = integrator_uart_set_mctrl,
200};
201
1da177e4
LT
202#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
203
204static DEFINE_SPINLOCK(cm_lock);
205
206/**
207 * cm_control - update the CM_CTRL register.
208 * @mask: bits to change
209 * @set: bits to set
210 */
211void cm_control(u32 mask, u32 set)
212{
213 unsigned long flags;
214 u32 val;
215
216 spin_lock_irqsave(&cm_lock, flags);
217 val = readl(CM_CTRL) & ~mask;
218 writel(val | set, CM_CTRL);
219 spin_unlock_irqrestore(&cm_lock, flags);
220}
221
222EXPORT_SYMBOL(cm_control);
223
224/*
225 * Where is the timer (VA)?
226 */
227#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
228#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
229#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
1da177e4
LT
230
231/*
232 * How long is the timer interval?
233 */
234#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
235#if TIMER_INTERVAL >= 0x100000
236#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
237#elif TIMER_INTERVAL >= 0x10000
238#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
239#else
240#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
241#endif
242
1da177e4
LT
243static unsigned long timer_reload;
244
b9cedda2
RK
245static void __iomem * const clksrc_base = (void __iomem *)TIMER2_VA_BASE;
246
247static cycle_t timersp_read(struct clocksource *cs)
1da177e4 248{
b9cedda2
RK
249 return ~(readl(clksrc_base + TIMER_VALUE) & 0xffff);
250}
1da177e4 251
b9cedda2
RK
252static struct clocksource clocksource_timersp = {
253 .name = "timer2",
254 .rating = 200,
255 .read = timersp_read,
256 .mask = CLOCKSOURCE_MASK(16),
257 .shift = 16,
258 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
259};
1da177e4 260
b9cedda2
RK
261static void integrator_clocksource_init(u32 khz)
262{
263 struct clocksource *cs = &clocksource_timersp;
264 void __iomem *base = clksrc_base;
265 u32 ctrl = TIMER_CTRL_ENABLE;
1da177e4 266
b9cedda2
RK
267 if (khz >= 1500) {
268 khz /= 16;
269 ctrl = TIMER_CTRL_DIV16;
270 }
1da177e4 271
b9cedda2
RK
272 writel(ctrl, base + TIMER_CTRL);
273 writel(0xffff, base + TIMER_LOAD);
274
275 cs->mult = clocksource_khz2mult(khz, cs->shift);
276 clocksource_register(cs);
1da177e4
LT
277}
278
13edd86d
RK
279static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
280
1da177e4
LT
281/*
282 * IRQ handler for the timer
283 */
13edd86d 284static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
1da177e4 285{
13edd86d
RK
286 struct clock_event_device *evt = dev_id;
287
288 /* clear the interrupt */
289 writel(1, clkevt_base + TIMER_INTCLR);
1da177e4 290
13edd86d 291 evt->event_handler(evt);
1da177e4 292
1da177e4
LT
293 return IRQ_HANDLED;
294}
295
13edd86d
RK
296static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
297{
298 u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
299
300 BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT);
301
302 if (mode == CLOCK_EVT_MODE_PERIODIC) {
303 writel(ctrl, clkevt_base + TIMER_CTRL);
304 writel(timer_reload, clkevt_base + TIMER_LOAD);
305 ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
306 }
307
308 writel(ctrl, clkevt_base + TIMER_CTRL);
309}
310
311static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
312{
313 unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
314
315 writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
316 writel(next, clkevt_base + TIMER_LOAD);
317 writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
318
319 return 0;
320}
321
322static struct clock_event_device integrator_clockevent = {
323 .name = "timer1",
324 .shift = 34,
325 .features = CLOCK_EVT_FEAT_PERIODIC,
326 .set_mode = clkevt_set_mode,
327 .set_next_event = clkevt_set_next_event,
328 .rating = 300,
329 .cpumask = cpu_all_mask,
330};
331
1da177e4 332static struct irqaction integrator_timer_irq = {
13edd86d 333 .name = "timer",
b30fabad 334 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
09b8b5f8 335 .handler = integrator_timer_interrupt,
13edd86d 336 .dev_id = &integrator_clockevent,
1da177e4
LT
337};
338
13edd86d 339static void integrator_clockevent_init(u32 khz, unsigned int ctrl)
1da177e4 340{
13edd86d 341 struct clock_event_device *evt = &integrator_clockevent;
1da177e4 342
13edd86d
RK
343 if (khz * 1000 > 0x100000 * HZ) {
344 khz /= 256;
345 ctrl |= TIMER_CTRL_DIV256;
346 } else if (khz * 1000 > 0x10000 * HZ) {
347 khz /= 16;
348 ctrl |= TIMER_CTRL_DIV16;
349 }
b9cedda2 350
13edd86d
RK
351 timer_reload = khz * 1000 / HZ;
352 writel(ctrl, clkevt_base + TIMER_CTRL);
1da177e4 353
13edd86d
RK
354 evt->irq = IRQ_TIMERINT1;
355 evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);
356 evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);
357 evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
1da177e4 358
13edd86d
RK
359 setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
360 clockevents_register_device(evt);
361}
362
363/*
364 * Set up timer(s).
365 */
366void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
367{
b720f732
RK
368 writel(0, TIMER0_VA_BASE + TIMER_CTRL);
369 writel(0, TIMER1_VA_BASE + TIMER_CTRL);
370 writel(0, TIMER2_VA_BASE + TIMER_CTRL);
1da177e4 371
13edd86d
RK
372 integrator_clocksource_init(reload * HZ / 1000);
373 integrator_clockevent_init(reload * HZ / 1000, ctrl);
1da177e4 374}