]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-ns9xxx/time.c
d293455017622aa6783a19ef0f3edd38d3cdb1f6
[linux-2.6-omap-h63xx.git] / arch / arm / mach-ns9xxx / time.c
1 /*
2  * arch/arm/mach-ns9xxx/time.c
3  *
4  * Copyright (C) 2006 by Digi International Inc.
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  */
11 #include <linux/jiffies.h>
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/stringify.h>
15 #include <linux/clocksource.h>
16
17 #include <asm/arch-ns9xxx/regs-sys.h>
18 #include <asm/arch-ns9xxx/clock.h>
19 #include <asm/arch-ns9xxx/irqs.h>
20 #include <asm/arch/system.h>
21 #include "generic.h"
22
23 #define TIMERCLOCKSELECT 64
24 #define TIMER_CLOCKSOURCE 1
25
26 static irqreturn_t
27 ns9xxx_timer_interrupt(int irq, void *dev_id)
28 {
29         int timerno = irq - IRQ_TIMER0;
30         u32 tc;
31
32         write_seqlock(&xtime_lock);
33         timer_tick();
34         write_sequnlock(&xtime_lock);
35
36         /* clear irq */
37         tc = SYS_TC(timerno);
38         if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) {
39                 REGSET(tc, SYS_TCx, TEN, DIS);
40                 SYS_TC(timerno) = tc;
41         }
42         REGSET(tc, SYS_TCx, INTC, SET);
43         SYS_TC(timerno) = tc;
44         REGSET(tc, SYS_TCx, INTC, UNSET);
45         SYS_TC(timerno) = tc;
46
47         return IRQ_HANDLED;
48 }
49
50 static struct irqaction ns9xxx_timer_irq = {
51         .name = "NS9xxx Timer Tick",
52         .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
53         .handler = ns9xxx_timer_interrupt,
54 };
55
56 static cycle_t ns9xxx_clocksource_read(void)
57 {
58         return SYS_TR(TIMER_CLOCKSOURCE);
59 }
60
61 static struct clocksource ns9xxx_clocksource = {
62         .name   = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE),
63         .rating = 300,
64         .read   = ns9xxx_clocksource_read,
65         .mask   = CLOCKSOURCE_MASK(32),
66         .shift  = 20,
67         .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
68 };
69
70 static void __init ns9xxx_timer_init(void)
71 {
72         int tc;
73
74         /* disable timer */
75         if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
76                 SYS_TC(0) = tc & ~SYS_TCx_TEN;
77
78         SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
79
80         REGSET(tc, SYS_TCx, TEN, EN);
81         REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
82         REGSET(tc, SYS_TCx, INTS, EN);
83         REGSET(tc, SYS_TCx, UDS, DOWN);
84         REGSET(tc, SYS_TCx, TDBG, STOP);
85         REGSET(tc, SYS_TCx, TSZ, 32);
86         REGSET(tc, SYS_TCx, REN, EN);
87         SYS_TC(0) = tc;
88
89         setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq);
90
91         tc = SYS_TC(TIMER_CLOCKSOURCE);
92         if (REGGET(tc, SYS_TCx, TEN)) {
93                 REGSET(tc, SYS_TCx, TEN, DIS);
94                 SYS_TC(TIMER_CLOCKSOURCE) = tc;
95         }
96
97         SYS_TRC(TIMER_CLOCKSOURCE) = 0;
98
99         REGSET(tc, SYS_TCx, TEN, EN);
100         REGSET(tc, SYS_TCx, TDBG, STOP);
101         REGSET(tc, SYS_TCx, TLCS, CPU);
102         REGSET(tc, SYS_TCx, TM, IEE);
103         REGSET(tc, SYS_TCx, INTS, DIS);
104         REGSET(tc, SYS_TCx, UDS, UP);
105         REGSET(tc, SYS_TCx, TSZ, 32);
106         REGSET(tc, SYS_TCx, REN, EN);
107
108         SYS_TC(TIMER_CLOCKSOURCE) = tc;
109
110         ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(),
111                         ns9xxx_clocksource.shift);
112
113         clocksource_register(&ns9xxx_clocksource);
114 }
115
116 struct sys_timer ns9xxx_timer = {
117         .init = ns9xxx_timer_init,
118 };