patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / include / asm-arm / arch-s3c2410 / time.h
1 /* linux/include/asm-arm/arch-s3c2410/time.h
2  *
3  *  Copyright (C) 2003 Simtec Electronics <linux@simtec.co.uk>
4  *    Ben Dooks, <ben@simtec.co.uk>
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 as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <asm/system.h>
22 #include <asm/leds.h>
23 #include <asm/mach-types.h>
24
25 #include <asm/io.h>
26 #include <asm/arch/map.h>
27 #include <asm/arch/regs-timer.h>
28
29 extern unsigned long (*gettimeoffset)(void);
30
31 static unsigned long timer_startval;
32 static unsigned long timer_ticks_usec;
33
34 #ifdef CONFIG_S3C2410_RTC
35 extern void s3c2410_rtc_check();
36 #endif
37
38 /* with an 12MHz clock, we get 12 ticks per-usec
39  */
40
41
42 /***
43  * Returns microsecond  since last clock interrupt.  Note that interrupts
44  * will have been disabled by do_gettimeoffset()
45  * IRQs are disabled before entering here from do_gettimeofday()
46  */
47 static unsigned long s3c2410_gettimeoffset (void)
48 {
49         unsigned long tdone;
50         unsigned long usec;
51
52         /* work out how many ticks have gone since last timer interrupt */
53
54         tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4));
55
56         /* currently, tcnt is in 12MHz units, but this may change
57          * for non-bast machines...
58          */
59
60         usec = tdone / timer_ticks_usec;
61
62         return usec;
63 }
64
65
66 /*
67  * IRQ handler for the timer
68  */
69 static irqreturn_t
70 s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
71 {
72         do_leds();
73         do_timer(regs);
74
75         do_set_rtc();
76         //s3c2410_rtc_check();
77         do_profile(regs);
78
79         return IRQ_HANDLED;
80 }
81
82 /*
83  * Set up timer interrupt, and return the current time in seconds.
84  */
85
86 /* currently we only use timer4, as it is the only timer which has no
87  * other function that can be exploited externally
88 */
89
90 void __init time_init (void)
91 {
92         unsigned long tcon;
93         unsigned long tcnt;
94         unsigned long tcfg1;
95         unsigned long tcfg0;
96
97         gettimeoffset = s3c2410_gettimeoffset;
98         timer_irq.handler = s3c2410_timer_interrupt;
99
100         tcnt = 0xffff;  /* default value for tcnt */
101
102         /* read the current timer configuration bits */
103
104         tcon = __raw_readl(S3C2410_TCON);
105         tcfg1 = __raw_readl(S3C2410_TCFG1);
106         tcfg0 = __raw_readl(S3C2410_TCFG0);
107
108         /* configure the system for whichever machine is in use */
109
110         if (machine_is_bast() || machine_is_vr1000()) {
111                 timer_ticks_usec = 12;        /* timer is at 12MHz */
112                 tcnt = (timer_ticks_usec * (1000*1000)) / HZ;
113         }
114
115         /* for the h1940, we use the pclk from the core to generate
116          * the timer values. since 67.5MHz is not a value we can directly
117          * generate the timer value from, we need to pre-scale and
118          * divied before using it.
119          *
120          * overall divsior to get 200Hz is 337500
121          *   we can fit tcnt if we pre-scale by 6, producing a tick rate
122          *   of 11.25MHz, and a tcnt of 56250.
123          */
124
125         if (machine_is_h1940() || machine_is_smdk2410() ) {
126                 timer_ticks_usec = s3c2410_pclk / (1000*1000);
127                 timer_ticks_usec /= 6;
128
129                 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
130                 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
131
132                 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
133                 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
134
135                 tcnt = (s3c2410_pclk / 6) / HZ;
136         }
137
138
139         printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n",
140                tcon, tcnt, tcfg0, tcfg1);
141
142         /* check to see if timer is within 16bit range... */
143         if (tcnt > 0xffff) {
144                 panic("setup_timer: HZ is too small, cannot configure timer!");
145                 return;
146         }
147
148         __raw_writel(tcfg1, S3C2410_TCFG1);
149         __raw_writel(tcfg0, S3C2410_TCFG0);
150
151         timer_startval = tcnt;
152         __raw_writel(tcnt, S3C2410_TCNTB(4));
153
154         /* ensure timer is stopped... */
155
156         tcon &= ~(7<<20);
157         tcon |= S3C2410_TCON_T4RELOAD;
158         tcon |= S3C2410_TCON_T4MANUALUPD;
159
160         __raw_writel(tcon, S3C2410_TCON);
161         __raw_writel(tcnt, S3C2410_TCNTB(4));
162         __raw_writel(tcnt, S3C2410_TCMPB(4));
163
164         setup_irq(IRQ_TIMER4, &timer_irq);
165
166         /* start the timer running */
167         tcon |= S3C2410_TCON_T4START;
168         tcon &= ~S3C2410_TCON_T4MANUALUPD;
169         __raw_writel(tcon, S3C2410_TCON);
170 }
171
172
173