ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-arm / arch-ebsa110 / time.h
1 /*
2  *  linux/include/asm-arm/arch-ebsa110/time.h
3  *
4  *  Copyright (C) 1996,1997,1998 Russell King.
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  * No real time clock on the evalulation board!
11  *
12  * Changelog:
13  *  10-Oct-1996 RMK     Created
14  *  04-Dec-1997 RMK     Updated for new arch/arm/kernel/time.c
15  *  07-Aug-1998 RMK     Updated for arch/arm/kernel/leds.c
16  *  28-Dec-1998 APH     Made leds code optional
17  */
18
19 #include <asm/leds.h>
20 #include <asm/io.h>
21
22 extern unsigned long (*gettimeoffset)(void);
23
24 #define PIT_CTRL                (PIT_BASE + 0x0d)
25 #define PIT_T2                  (PIT_BASE + 0x09)
26 #define PIT_T1                  (PIT_BASE + 0x05)
27 #define PIT_T0                  (PIT_BASE + 0x01)
28
29 /*
30  * This is the rate at which your MCLK signal toggles (in Hz)
31  * This was measured on a 10 digit frequency counter sampling
32  * over 1 second.
33  */
34 #define MCLK    47894000
35
36 /*
37  * This is the rate at which the PIT timers get clocked
38  */
39 #define CLKBY7  (MCLK / 7)
40
41 /*
42  * This is the counter value.  We tick at 200Hz on this platform.
43  */
44 #define COUNT   ((CLKBY7 + (HZ / 2)) / HZ)
45
46 /*
47  * Get the time offset from the system PIT.  Note that if we have missed an
48  * interrupt, then the PIT counter will roll over (ie, be negative).
49  * This actually works out to be convenient.
50  */
51 static unsigned long ebsa110_gettimeoffset(void)
52 {
53         unsigned long offset, count;
54
55         __raw_writeb(0x40, PIT_CTRL);
56         count = __raw_readb(PIT_T1);
57         count |= __raw_readb(PIT_T1) << 8;
58
59         /*
60          * If count > COUNT, make the number negative.
61          */
62         if (count > COUNT)
63                 count |= 0xffff0000;
64
65         offset = COUNT;
66         offset -= count;
67
68         /*
69          * `offset' is in units of timer counts.  Convert
70          * offset to units of microseconds.
71          */
72         offset = offset * (1000000 / HZ) / COUNT;
73
74         return offset;
75 }
76
77 static irqreturn_t
78 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
79 {
80         u32 count;
81
82         /* latch and read timer 1 */
83         __raw_writeb(0x40, PIT_CTRL);
84         count = __raw_readb(PIT_T1);
85         count |= __raw_readb(PIT_T1) << 8;
86
87         count += COUNT;
88
89         __raw_writeb(count & 0xff, PIT_T1);
90         __raw_writeb(count >> 8, PIT_T1);
91
92         do_leds();
93         do_timer(regs);
94         do_profile(regs);
95
96         return IRQ_HANDLED;
97 }
98
99 /*
100  * Set up timer interrupt.
101  */
102 void __init time_init(void)
103 {
104         /*
105          * Timer 1, mode 2, LSB/MSB
106          */
107         __raw_writeb(0x70, PIT_CTRL);
108         __raw_writeb(COUNT & 0xff, PIT_T1);
109         __raw_writeb(COUNT >> 8, PIT_T1);
110
111         gettimeoffset = ebsa110_gettimeoffset;
112
113         timer_irq.handler = timer_interrupt;
114
115         setup_irq(IRQ_EBSA110_TIMER0, &timer_irq);
116 }
117
118