a858ce0930a66c5d5a718f8a1439789f4c4583f6
[openwrt/openwrt.git] / target / linux / coldfire / files-2.6.31 / arch / m68k / coldfire / common / time.c
1 /*
2 * linux/arch/m68k/coldfire/time.c
3 *
4 * This file contains the coldfire specific time handling pieces.
5 *
6 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Kurt Mahan <kmahan@freescale.com>
8 * Jason Jin Jason.Jin@freescale.com
9 * Shrek Wu B16972@freescale.com
10 *
11 * based on linux/arch/m68k/kernel/time.c
12 */
13 #include <linux/clk.h>
14 #include <linux/clk.h>
15 #include <linux/clocksource.h>
16 #include <linux/clockchips.h>
17 #include <linux/time.h>
18 #include <linux/timex.h>
19 #include <linux/errno.h>
20 #include <linux/module.h>
21 #include <linux/sysdev.h>
22 #include <linux/sched.h>
23 #include <linux/kernel.h>
24 #include <linux/param.h>
25 #include <linux/string.h>
26 #include <linux/mm.h>
27 #include <linux/rtc.h>
28
29 #include <asm/machdep.h>
30 #include <linux/io.h>
31 #include <asm/irq_regs.h>
32
33 #include <linux/profile.h>
34 #include <asm/mcfsim.h>
35 #ifdef CONFIG_GENERIC_CLOCKEVENTS
36 /*extern unsigned long long sys_dtim0_read(void);
37 extern void sys_dtim_init(void);*/
38 extern unsigned long long sys_dtim2_read(void);
39 extern void sys_dtim2_init(void);
40 static int cfv4_set_next_event(unsigned long evt,
41 struct clock_event_device *dev);
42 static void cfv4_set_mode(enum clock_event_mode mode,
43 struct clock_event_device *dev);
44 #if defined(CONFIG_M5445X)
45 #define FREQ (MCF_BUSCLK / 16)
46 #else
47 #define FREQ (MCF_BUSCLK)
48 #endif
49 /*
50 * realtime clock dummy code
51 */
52
53 static unsigned long null_rtc_get_time(void)
54 {
55 return mktime(2008, 1, 1, 0, 0, 0);
56 }
57
58 static int null_rtc_set_time(unsigned long sec)
59 {
60 return 0;
61 }
62
63 static unsigned long (*cf_rtc_get_time)(void) = null_rtc_get_time;
64 static int (*cf_rtc_set_time)(unsigned long) = null_rtc_set_time;
65 #endif /* CONFIG_GENERIC_CLOCKEVENTS */
66
67 /*
68 * old pre-GENERIC clock code
69 */
70
71 #ifndef CONFIG_GENERIC_CLOCKEVENTS
72 /*
73 * timer_interrupt() needs to keep up the real-time clock,
74 * as well as call the "do_timer()" routine every clocktick
75 */
76 static irqreturn_t timer_interrupt(int irq, void *dummy)
77 {
78 #ifdef CONFIG_COLDFIRE
79 /* kick hardware timer if necessary */
80 if (mach_tick)
81 mach_tick();
82 #endif
83 do_timer(1);
84 #ifndef CONFIG_SMP
85 update_process_times(user_mode(get_irq_regs()));
86 #endif
87 profile_tick(CPU_PROFILING);
88
89 #ifdef CONFIG_HEARTBEAT
90 /* use power LED as a heartbeat instead -- much more useful
91 for debugging -- based on the version for PReP by Cort */
92 /* acts like an actual heart beat -- ie thump-thump-pause... */
93 if (mach_heartbeat) {
94 unsigned cnt = 0, period = 0, dist = 0;
95
96 if (cnt == 0 || cnt == dist)
97 mach_heartbeat(1);
98 else if (cnt == 7 || cnt == dist+7)
99 mach_heartbeat(0);
100
101 if (++cnt > period) {
102 cnt = 0;
103 /* The hyperbolic function below modifies
104 * the heartbeat period length in dependency
105 * of the current (5min) load. It goes through
106 * the points f(0)=126, f(1)=86, f(5)=51,
107 * f(inf)->30. */
108 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT)))
109 + 30;
110 dist = period / 4;
111 }
112 }
113 #endif /* CONFIG_HEARTBEAT */
114 return IRQ_HANDLED;
115 }
116
117 void __init time_init(void)
118 {
119 struct rtc_time time;
120
121 if (mach_hwclk) {
122 mach_hwclk(0, &time);
123 time.tm_year += 1900;
124 if (time.tm_year < 1970)
125 time.tm_year += 100;
126 xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
127 time.tm_hour, time.tm_min, time.tm_sec);
128 xtime.tv_nsec = 0;
129 }
130 wall_to_monotonic.tv_sec = -xtime.tv_sec;
131
132 mach_sched_init(timer_interrupt);
133 }
134 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
135
136 #ifndef CONFIG_GENERIC_TIME
137 /*
138 * This version of gettimeofday has near microsecond resolution.
139 */
140 void do_gettimeofday(struct timeval *tv)
141 {
142 unsigned long flags;
143 unsigned long seq;
144 unsigned long usec, sec;
145 unsigned long max_ntp_tick = tick_usec - tickadj;
146
147 do {
148 seq = read_seqbegin_irqsave(&xtime_lock, flags);
149
150 usec = mach_gettimeoffset();
151
152 /*
153 * If time_adjust is negative then NTP is slowing the clock
154 * so make sure not to go into next possible interval.
155 * Better to lose some accuracy than have time go backwards..
156 */
157 if (unlikely(time_adjust < 0))
158 usec = min(usec, max_ntp_tick);
159
160 sec = xtime.tv_sec;
161 usec += xtime.tv_nsec/1000;
162 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
163
164
165 while (usec >= 1000000) {
166 usec -= 1000000;
167 sec++;
168 }
169
170 tv->tv_sec = sec;
171 tv->tv_usec = usec;
172 }
173 EXPORT_SYMBOL(do_gettimeofday);
174
175 int do_settimeofday(struct timespec *tv)
176 {
177 time_t wtm_sec, sec = tv->tv_sec;
178 long wtm_nsec, nsec = tv->tv_nsec;
179
180 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
181 return -EINVAL;
182
183 write_seqlock_irq(&xtime_lock);
184 /* This is revolting. We need to set the xtime.tv_nsec
185 * correctly. However, the value in this location is
186 * is value at the last tick.
187 * Discover what correction gettimeofday
188 * would have done, and then undo it!
189 */
190 nsec -= 1000 * mach_gettimeoffset();
191
192 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
193 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
194
195 set_normalized_timespec(&xtime, sec, nsec);
196 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
197
198 ntp_clear();
199 write_sequnlock_irq(&xtime_lock);
200 clock_was_set();
201 return 0;
202 }
203 EXPORT_SYMBOL(do_settimeofday);
204 #endif /* !CONFIG_GENERIC_TIME */
205
206 #ifdef CONFIG_GENERIC_CLOCKEVENTS
207 /*
208 * Clock Evnt setup
209 */
210 static struct clock_event_device clockevent_cfv4 = {
211 .name = "CFV4 timer2even",
212 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
213 .rating = 200,
214 .shift = 20,
215 .set_mode = cfv4_set_mode,
216 .set_next_event = cfv4_set_next_event,
217 };
218
219 static int cfv4_set_next_event(unsigned long evt,
220 struct clock_event_device *dev)
221 {
222 return 0;
223 }
224
225 static void cfv4_set_mode(enum clock_event_mode mode,
226 struct clock_event_device *dev)
227 {
228 if (mode != CLOCK_EVT_MODE_ONESHOT)
229 cfv4_set_next_event((FREQ / HZ), dev);
230 }
231
232 static int __init cfv4_clockevent_init(void)
233 {
234 clockevent_cfv4.mult =
235 div_sc(FREQ, NSEC_PER_SEC,
236 clockevent_cfv4.shift);
237 clockevent_cfv4.max_delta_ns =
238 clockevent_delta2ns((FREQ / HZ),
239 &clockevent_cfv4);
240 clockevent_cfv4.min_delta_ns =
241 clockevent_delta2ns(1, &clockevent_cfv4);
242
243 clockevent_cfv4.cpumask = &cpumask_of_cpu(0);
244
245 printk(KERN_INFO "timer: register clockevent\n");
246 clockevents_register_device(&clockevent_cfv4);
247
248 return 0;
249 }
250
251 /*
252 * clocksource setup
253 */
254
255 struct clocksource clocksource_cfv4 = {
256 .name = "ColdfireV4",
257 .rating = 250,
258 .mask = CLOCKSOURCE_MASK(32),
259 .read = sys_dtim2_read,
260 .shift = 20,
261 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
262 };
263
264 /*
265 * Initialize time subsystem. Called from linux/init/main.c
266 */
267 void __init time_init(void)
268 {
269 int ret;
270
271 printk(KERN_INFO "Initializing time\n");
272 #if 0
273 /* initialize system clocks */
274 clk_init();
275 #endif
276 cfv4_clockevent_init();
277 /* initialize the system timer */
278 /*sys_dtim_init();*/
279 sys_dtim2_init();
280 /* setup initial system time */
281 xtime.tv_sec = cf_rtc_get_time();
282 xtime.tv_nsec = 0;
283 set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec,
284 -xtime.tv_nsec);
285
286 /* JKM */
287 clocksource_cfv4.mult = clocksource_hz2mult(FREQ,
288 clocksource_cfv4.shift);
289
290 /* register our clocksource */
291 ret = clocksource_register(&clocksource_cfv4);
292 if (ret)
293 printk(KERN_ERR "timer: unable to "
294 "register clocksource - %d\n", ret);
295 }
296
297 /*
298 * sysfs pieces
299 */
300
301 static struct sysdev_class timer_class = {
302 .name = "timer",
303 };
304
305 static struct sys_device timer_device = {
306 .id = 0,
307 .cls = &timer_class,
308 };
309
310 static int __init timer_init_sysfs(void)
311 {
312 int err = sysdev_class_register(&timer_class);
313 if (!err)
314 err = sysdev_register(&timer_device);
315 return err;
316 }
317 device_initcall(timer_init_sysfs);
318 #endif /* CONFIG_GENERIC_CLOCKEVENTS */