aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s3c/time.c
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:04 -0500
committerBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:04 -0500
commit7f2754378f3522a42daafdbb9d2385f341008454 (patch)
tree7a6223f270cdf53067a70c2e86b2190d3577c23d /arch/arm/plat-s3c/time.c
parentc6ad115876763e4f15055982ecb9579cb7abab5f (diff)
parenta9c5d23ac724a3b908833cafbbbd49abe4741b86 (diff)
Merge branch 'next-s3c64xx' into next-merged
Diffstat (limited to 'arch/arm/plat-s3c/time.c')
-rw-r--r--arch/arm/plat-s3c/time.c81
1 files changed, 53 insertions, 28 deletions
diff --git a/arch/arm/plat-s3c/time.c b/arch/arm/plat-s3c/time.c
index c6861a05a29..3b27b29da47 100644
--- a/arch/arm/plat-s3c/time.c
+++ b/arch/arm/plat-s3c/time.c
@@ -26,6 +26,7 @@
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/platform_device.h>
29 30
30#include <asm/system.h> 31#include <asm/system.h>
31#include <asm/leds.h> 32#include <asm/leds.h>
@@ -36,6 +37,7 @@
36#include <plat/regs-timer.h> 37#include <plat/regs-timer.h>
37#include <mach/regs-irq.h> 38#include <mach/regs-irq.h>
38#include <asm/mach/time.h> 39#include <asm/mach/time.h>
40#include <mach/tick.h>
39 41
40#include <plat/clock.h> 42#include <plat/clock.h>
41#include <plat/cpu.h> 43#include <plat/cpu.h>
@@ -43,6 +45,10 @@
43static unsigned long timer_startval; 45static unsigned long timer_startval;
44static unsigned long timer_usec_ticks; 46static unsigned long timer_usec_ticks;
45 47
48#ifndef TICK_MAX
49#define TICK_MAX (0xffff)
50#endif
51
46#define TIMER_USEC_SHIFT 16 52#define TIMER_USEC_SHIFT 16
47 53
48/* we use the shifted arithmetic to work out the ratio of timer ticks 54/* we use the shifted arithmetic to work out the ratio of timer ticks
@@ -91,12 +97,9 @@ static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
91 * IRQs are disabled before entering here from do_gettimeofday() 97 * IRQs are disabled before entering here from do_gettimeofday()
92 */ 98 */
93 99
94#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
95
96static unsigned long s3c2410_gettimeoffset (void) 100static unsigned long s3c2410_gettimeoffset (void)
97{ 101{
98 unsigned long tdone; 102 unsigned long tdone;
99 unsigned long irqpend;
100 unsigned long tval; 103 unsigned long tval;
101 104
102 /* work out how many ticks have gone since last timer interrupt */ 105 /* work out how many ticks have gone since last timer interrupt */
@@ -106,8 +109,7 @@ static unsigned long s3c2410_gettimeoffset (void)
106 109
107 /* check to see if there is an interrupt pending */ 110 /* check to see if there is an interrupt pending */
108 111
109 irqpend = __raw_readl(S3C2410_SRCPND); 112 if (s3c24xx_ostimer_pending()) {
110 if (irqpend & SRCPND_TIMER4) {
111 /* re-read the timer, and try and fix up for the missed 113 /* re-read the timer, and try and fix up for the missed
112 * interrupt. Note, the interrupt may go off before the 114 * interrupt. Note, the interrupt may go off before the
113 * timer has re-loaded from wrapping. 115 * timer has re-loaded from wrapping.
@@ -146,6 +148,10 @@ static struct irqaction s3c2410_timer_irq = {
146 machine_is_anubis() || \ 148 machine_is_anubis() || \
147 machine_is_osiris()) 149 machine_is_osiris())
148 150
151static struct clk *tin;
152static struct clk *tdiv;
153static struct clk *timerclk;
154
149/* 155/*
150 * Set up timer interrupt, and return the current time in seconds. 156 * Set up timer interrupt, and return the current time in seconds.
151 * 157 *
@@ -159,13 +165,7 @@ static void s3c2410_timer_setup (void)
159 unsigned long tcfg1; 165 unsigned long tcfg1;
160 unsigned long tcfg0; 166 unsigned long tcfg0;
161 167
162 tcnt = 0xffff; /* default value for tcnt */ 168 tcnt = TICK_MAX; /* default value for tcnt */
163
164 /* read the current timer configuration bits */
165
166 tcon = __raw_readl(S3C2410_TCON);
167 tcfg1 = __raw_readl(S3C2410_TCFG1);
168 tcfg0 = __raw_readl(S3C2410_TCFG0);
169 169
170 /* configure the system for whichever machine is in use */ 170 /* configure the system for whichever machine is in use */
171 171
@@ -174,11 +174,13 @@ static void s3c2410_timer_setup (void)
174 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); 174 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
175 tcnt = 12000000 / HZ; 175 tcnt = 12000000 / HZ;
176 176
177 tcfg1 = __raw_readl(S3C2410_TCFG1);
177 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; 178 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
178 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; 179 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
180 __raw_writel(tcfg1, S3C2410_TCFG1);
179 } else { 181 } else {
180 unsigned long pclk; 182 unsigned long pclk;
181 struct clk *clk; 183 struct clk *tscaler;
182 184
183 /* for the h1940 (and others), we use the pclk from the core 185 /* for the h1940 (and others), we use the pclk from the core
184 * to generate the timer values. since values around 50 to 186 * to generate the timer values. since values around 50 to
@@ -189,29 +191,25 @@ static void s3c2410_timer_setup (void)
189 * (8.45 ticks per usec) 191 * (8.45 ticks per usec)
190 */ 192 */
191 193
192 /* this is used as default if no other timer can be found */ 194 pclk = clk_get_rate(timerclk);
193
194 clk = clk_get(NULL, "timers");
195 if (IS_ERR(clk))
196 panic("failed to get clock for system timer");
197
198 clk_enable(clk);
199
200 pclk = clk_get_rate(clk);
201 195
202 /* configure clock tick */ 196 /* configure clock tick */
203 197
204 timer_usec_ticks = timer_mask_usec_ticks(6, pclk); 198 timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
205 199
206 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; 200 tscaler = clk_get_parent(tdiv);
207 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
208 201
209 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; 202 clk_set_rate(tscaler, pclk / 3);
210 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; 203 clk_set_rate(tdiv, pclk / 6);
204 clk_set_parent(tin, tdiv);
211 205
212 tcnt = (pclk / 6) / HZ; 206 tcnt = clk_get_rate(tin) / HZ;
213 } 207 }
214 208
209 tcon = __raw_readl(S3C2410_TCON);
210 tcfg0 = __raw_readl(S3C2410_TCFG0);
211 tcfg1 = __raw_readl(S3C2410_TCFG1);
212
215 /* timers reload after counting zero, so reduce the count by 1 */ 213 /* timers reload after counting zero, so reduce the count by 1 */
216 214
217 tcnt--; 215 tcnt--;
@@ -220,7 +218,7 @@ static void s3c2410_timer_setup (void)
220 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); 218 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
221 219
222 /* check to see if timer is within 16bit range... */ 220 /* check to see if timer is within 16bit range... */
223 if (tcnt > 0xffff) { 221 if (tcnt > TICK_MAX) {
224 panic("setup_timer: HZ is too small, cannot configure timer!"); 222 panic("setup_timer: HZ is too small, cannot configure timer!");
225 return; 223 return;
226 } 224 }
@@ -247,8 +245,35 @@ static void s3c2410_timer_setup (void)
247 __raw_writel(tcon, S3C2410_TCON); 245 __raw_writel(tcon, S3C2410_TCON);
248} 246}
249 247
248static void __init s3c2410_timer_resources(void)
249{
250 struct platform_device tmpdev;
251
252 tmpdev.dev.bus = &platform_bus_type;
253 tmpdev.id = 4;
254
255 timerclk = clk_get(NULL, "timers");
256 if (IS_ERR(timerclk))
257 panic("failed to get clock for system timer");
258
259 clk_enable(timerclk);
260
261 if (!use_tclk1_12()) {
262 tin = clk_get(&tmpdev.dev, "pwm-tin");
263 if (IS_ERR(tin))
264 panic("failed to get pwm-tin clock for system timer");
265
266 tdiv = clk_get(&tmpdev.dev, "pwm-tdiv");
267 if (IS_ERR(tdiv))
268 panic("failed to get pwm-tdiv clock for system timer");
269 }
270
271 clk_enable(tin);
272}
273
250static void __init s3c2410_timer_init(void) 274static void __init s3c2410_timer_init(void)
251{ 275{
276 s3c2410_timer_resources();
252 s3c2410_timer_setup(); 277 s3c2410_timer_setup();
253 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); 278 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
254} 279}