File: /usr/src/linux/arch/arm/mach-ebsa110/time.c

1     /*
2      *  linux/arch/arm/mach-ebsa110/time.c
3      *
4      *  Copyright (C) 2001 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     #include <linux/sched.h>
11     #include <linux/init.h>
12     
13     #include <asm/io.h>
14     
15     #define PIT_CTRL		(PIT_BASE + 0x0d)
16     #define PIT_T2			(PIT_BASE + 0x09)
17     #define PIT_T1			(PIT_BASE + 0x05)
18     #define PIT_T0			(PIT_BASE + 0x01)
19     
20     /*
21      * This is the rate at which your MCLK signal toggles (in Hz)
22      * This was measured on a 10 digit frequency counter sampling
23      * over 1 second.
24      */
25     #define MCLK	47894000
26     
27     /*
28      * This is the rate at which the PIT timers get clocked
29      */
30     #define CLKBY7	(MCLK / 7)
31     
32     /*
33      * If CLKBY7 is larger than this, then we must do software
34      * division of the timer interrupt.
35      */
36     #if CLKBY7 > 6553500
37     #define DIVISOR	2
38     #else
39     #define DIVISOR 1
40     #endif
41     
42     /*
43      * This is the counter value
44      */
45     #define COUNT	((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ))
46     
47     extern unsigned long (*gettimeoffset)(void);
48     
49     static unsigned long divisor;
50     
51     /*
52      * Get the time offset from the system PIT.  Note that if we have missed an
53      * interrupt, then the PIT counter will roll over (ie, be negative).
54      * This actually works out to be convenient.
55      */
56     static unsigned long ebsa110_gettimeoffset(void)
57     {
58     	unsigned long offset, count;
59     
60     	__raw_writeb(0x40, PIT_CTRL);
61     	count = __raw_readb(PIT_T1);
62     	count |= __raw_readb(PIT_T1) << 8;
63     
64     	/*
65     	 * If count > COUNT, make the number negative.
66     	 */
67     	if (count > COUNT)
68     		count |= 0xffff0000;
69     
70     	offset = COUNT * (DIVISOR - divisor);
71     	offset -= count;
72     
73     	/*
74     	 * `offset' is in units of timer counts.  Convert
75     	 * offset to units of microseconds.
76     	 */
77     	offset = offset * (1000000 / HZ) / (COUNT * DIVISOR);
78     
79     	return offset;
80     }
81     
82     int ebsa110_reset_timer(void)
83     {
84     	u32 count;
85     
86     	/* latch and read timer 1 */
87     	__raw_writeb(0x40, PIT_CTRL);
88     	count = __raw_readb(PIT_T1);
89     	count |= __raw_readb(PIT_T1) << 8;
90     
91     	count += COUNT;
92     
93     	__raw_writeb(count & 0xff, PIT_T1);
94     	__raw_writeb(count >> 8, PIT_T1);
95     
96     	if (divisor == 0)
97     		divisor = DIVISOR;
98     	divisor -= 1;
99     	return divisor;
100     }
101     
102     void __init ebsa110_setup_timer(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     	divisor = DIVISOR - 1;
111     
112     	gettimeoffset = ebsa110_gettimeoffset;
113     }
114