1 /* linux/include/asm-arm/arch-s3c2410/time.h
3 * Copyright (C) 2003 Simtec Electronics <linux@simtec.co.uk>
4 * Ben Dooks, <ben@simtec.co.uk>
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.
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.
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
21 #include <linux/config.h>
22 #include <linux/kernel.h>
23 #include <linux/sched.h>
24 #include <linux/init.h>
25 #include <linux/interrupt.h>
26 #include <asm/system.h>
28 #include <asm/mach-types.h>
32 #include <asm/arch/map.h>
33 #include <asm/arch/regs-timer.h>
34 #include <asm/mach/time.h>
36 static unsigned long timer_startval;
37 static unsigned long timer_ticks_usec;
39 #ifdef CONFIG_S3C2410_RTC
40 extern void s3c2410_rtc_check();
43 /* with an 12MHz clock, we get 12 ticks per-usec
48 * Returns microsecond since last clock interrupt. Note that interrupts
49 * will have been disabled by do_gettimeoffset()
50 * IRQs are disabled before entering here from do_gettimeofday()
52 static unsigned long s3c2410_gettimeoffset (void)
57 /* work out how many ticks have gone since last timer interrupt */
59 tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4));
61 /* currently, tcnt is in 12MHz units, but this may change
62 * for non-bast machines...
65 usec = tdone / timer_ticks_usec;
72 * IRQ handler for the timer
75 s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
82 static struct irqaction s3c2410_timer_irq = {
83 .name = "S32410 Timer Tick",
84 .flags = SA_INTERRUPT,
85 .handler = s3c2410_timer_interrupt
89 * Set up timer interrupt, and return the current time in seconds.
91 * Currently we only use timer4, as it is the only timer which has no
92 * other function that can be exploited externally
94 void __init s3c2410_init_time (void)
101 gettimeoffset = s3c2410_gettimeoffset;
103 tcnt = 0xffff; /* default value for tcnt */
105 /* read the current timer configuration bits */
107 tcon = __raw_readl(S3C2410_TCON);
108 tcfg1 = __raw_readl(S3C2410_TCFG1);
109 tcfg0 = __raw_readl(S3C2410_TCFG0);
111 /* configure the system for whichever machine is in use */
113 if (machine_is_bast() || machine_is_vr1000()) {
114 timer_ticks_usec = 12; /* timer is at 12MHz */
115 tcnt = (timer_ticks_usec * (1000*1000)) / HZ;
118 /* for the h1940, we use the pclk from the core to generate
119 * the timer values. since 67.5MHz is not a value we can directly
120 * generate the timer value from, we need to pre-scale and
121 * divied before using it.
123 * overall divsior to get 200Hz is 337500
124 * we can fit tcnt if we pre-scale by 6, producing a tick rate
125 * of 11.25MHz, and a tcnt of 56250.
128 if (machine_is_h1940() || machine_is_smdk2410() ) {
129 timer_ticks_usec = s3c2410_pclk / (1000*1000);
130 timer_ticks_usec /= 6;
132 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
133 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
135 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
136 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
138 tcnt = (s3c2410_pclk / 6) / HZ;
142 printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n",
143 tcon, tcnt, tcfg0, tcfg1);
145 /* check to see if timer is within 16bit range... */
147 panic("setup_timer: HZ is too small, cannot configure timer!");
151 __raw_writel(tcfg1, S3C2410_TCFG1);
152 __raw_writel(tcfg0, S3C2410_TCFG0);
154 timer_startval = tcnt;
155 __raw_writel(tcnt, S3C2410_TCNTB(4));
157 /* ensure timer is stopped... */
160 tcon |= S3C2410_TCON_T4RELOAD;
161 tcon |= S3C2410_TCON_T4MANUALUPD;
163 __raw_writel(tcon, S3C2410_TCON);
164 __raw_writel(tcnt, S3C2410_TCNTB(4));
165 __raw_writel(tcnt, S3C2410_TCMPB(4));
167 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
169 /* start the timer running */
170 tcon |= S3C2410_TCON_T4START;
171 tcon &= ~S3C2410_TCON_T4MANUALUPD;
172 __raw_writel(tcon, S3C2410_TCON);