diff options
Diffstat (limited to 'arch/arm/mach-ns9xxx/time.c')
-rw-r--r-- | arch/arm/mach-ns9xxx/time.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c new file mode 100644 index 000000000000..eec05f18714a --- /dev/null +++ b/arch/arm/mach-ns9xxx/time.c | |||
@@ -0,0 +1,88 @@ | |||
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 <asm/arch-ns9xxx/regs-sys.h> | ||
15 | #include <asm/arch-ns9xxx/clock.h> | ||
16 | #include <asm/arch-ns9xxx/irqs.h> | ||
17 | #include <asm/arch/system.h> | ||
18 | #include "generic.h" | ||
19 | |||
20 | #define TIMERCLOCKSELECT 64 | ||
21 | |||
22 | static u32 usecs_per_tick; | ||
23 | |||
24 | static irqreturn_t | ||
25 | ns9xxx_timer_interrupt(int irq, void *dev_id) | ||
26 | { | ||
27 | write_seqlock(&xtime_lock); | ||
28 | timer_tick(); | ||
29 | write_sequnlock(&xtime_lock); | ||
30 | |||
31 | return IRQ_HANDLED; | ||
32 | } | ||
33 | |||
34 | static unsigned long ns9xxx_timer_gettimeoffset(void) | ||
35 | { | ||
36 | /* return the microseconds which have passed since the last interrupt | ||
37 | * was _serviced_. That is, if an interrupt is pending or the counter | ||
38 | * reloads, return one periode more. */ | ||
39 | |||
40 | u32 counter1 = SYS_TR(0); | ||
41 | int pending = SYS_ISR & (1 << IRQ_TIMER0); | ||
42 | u32 counter2 = SYS_TR(0); | ||
43 | u32 elapsed; | ||
44 | |||
45 | if (pending || counter2 > counter1) | ||
46 | elapsed = 2 * SYS_TRC(0) - counter2; | ||
47 | else | ||
48 | elapsed = SYS_TRC(0) - counter1; | ||
49 | |||
50 | return (elapsed * usecs_per_tick) >> 16; | ||
51 | |||
52 | } | ||
53 | |||
54 | static struct irqaction ns9xxx_timer_irq = { | ||
55 | .name = "NS9xxx Timer Tick", | ||
56 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
57 | .handler = ns9xxx_timer_interrupt, | ||
58 | }; | ||
59 | |||
60 | static void __init ns9xxx_timer_init(void) | ||
61 | { | ||
62 | int tc; | ||
63 | |||
64 | usecs_per_tick = | ||
65 | SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); | ||
66 | |||
67 | /* disable timer */ | ||
68 | if ((tc = SYS_TC(0)) & SYS_TCx_TEN) | ||
69 | SYS_TC(0) = tc & ~SYS_TCx_TEN; | ||
70 | |||
71 | SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0); | ||
72 | |||
73 | REGSET(tc, SYS_TCx, TEN, EN); | ||
74 | REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */ | ||
75 | REGSET(tc, SYS_TCx, INTS, EN); | ||
76 | REGSET(tc, SYS_TCx, UDS, DOWN); | ||
77 | REGSET(tc, SYS_TCx, TDBG, STOP); | ||
78 | REGSET(tc, SYS_TCx, TSZ, 32); | ||
79 | REGSET(tc, SYS_TCx, REN, EN); | ||
80 | SYS_TC(0) = tc; | ||
81 | |||
82 | setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); | ||
83 | } | ||
84 | |||
85 | struct sys_timer ns9xxx_timer = { | ||
86 | .init = ns9xxx_timer_init, | ||
87 | .offset = ns9xxx_timer_gettimeoffset, | ||
88 | }; | ||