2 * linux/arch/m68k/coldfire/time.c
4 * This file contains the coldfire specific time handling pieces.
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
11 * based on linux/arch/m68k/kernel/time.c
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>
27 #include <linux/rtc.h>
29 #include <asm/machdep.h>
31 #include <asm/irq_regs.h>
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)
47 #define FREQ (MCF_BUSCLK)
50 * realtime clock dummy code
53 static unsigned long null_rtc_get_time(void)
55 return mktime(2008, 1, 1, 0, 0, 0);
58 static int null_rtc_set_time(unsigned long sec)
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 */
68 * old pre-GENERIC clock code
71 #ifndef CONFIG_GENERIC_CLOCKEVENTS
73 * timer_interrupt() needs to keep up the real-time clock,
74 * as well as call the "do_timer()" routine every clocktick
76 static irqreturn_t timer_interrupt(int irq, void *dummy)
78 #ifdef CONFIG_COLDFIRE
79 /* kick hardware timer if necessary */
85 update_process_times(user_mode(get_irq_regs()));
87 profile_tick(CPU_PROFILING);
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... */
94 unsigned cnt = 0, period = 0, dist = 0;
96 if (cnt == 0 || cnt == dist)
98 else if (cnt == 7 || cnt == dist+7)
101 if (++cnt > period) {
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,
108 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT)))
113 #endif /* CONFIG_HEARTBEAT */
117 void __init time_init(void)
119 struct rtc_time time;
122 mach_hwclk(0, &time);
123 time.tm_year += 1900;
124 if (time.tm_year < 1970)
126 xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
127 time.tm_hour, time.tm_min, time.tm_sec);
130 wall_to_monotonic.tv_sec = -xtime.tv_sec;
132 mach_sched_init(timer_interrupt);
134 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
136 #ifndef CONFIG_GENERIC_TIME
138 * This version of gettimeofday has near microsecond resolution.
140 void do_gettimeofday(struct timeval *tv)
144 unsigned long usec, sec;
145 unsigned long max_ntp_tick = tick_usec - tickadj;
148 seq = read_seqbegin_irqsave(&xtime_lock, flags);
150 usec = mach_gettimeoffset();
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..
157 if (unlikely(time_adjust < 0))
158 usec = min(usec, max_ntp_tick);
161 usec += xtime.tv_nsec/1000;
162 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
165 while (usec >= 1000000) {
173 EXPORT_SYMBOL(do_gettimeofday);
175 int do_settimeofday(struct timespec *tv)
177 time_t wtm_sec, sec = tv->tv_sec;
178 long wtm_nsec, nsec = tv->tv_nsec;
180 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
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!
190 nsec -= 1000 * mach_gettimeoffset();
192 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
193 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
195 set_normalized_timespec(&xtime, sec, nsec);
196 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
199 write_sequnlock_irq(&xtime_lock);
203 EXPORT_SYMBOL(do_settimeofday);
204 #endif /* !CONFIG_GENERIC_TIME */
206 #ifdef CONFIG_GENERIC_CLOCKEVENTS
210 static struct clock_event_device clockevent_cfv4 = {
211 .name = "CFV4 timer2even",
212 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
215 .set_mode = cfv4_set_mode,
216 .set_next_event = cfv4_set_next_event,
219 static int cfv4_set_next_event(unsigned long evt,
220 struct clock_event_device *dev)
225 static void cfv4_set_mode(enum clock_event_mode mode,
226 struct clock_event_device *dev)
228 if (mode != CLOCK_EVT_MODE_ONESHOT)
229 cfv4_set_next_event((FREQ / HZ), dev);
232 static int __init cfv4_clockevent_init(void)
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),
240 clockevent_cfv4.min_delta_ns =
241 clockevent_delta2ns(1, &clockevent_cfv4);
243 clockevent_cfv4.cpumask = &cpumask_of_cpu(0);
245 printk(KERN_INFO "timer: register clockevent\n");
246 clockevents_register_device(&clockevent_cfv4);
255 struct clocksource clocksource_cfv4 = {
256 .name = "ColdfireV4",
258 .mask = CLOCKSOURCE_MASK(32),
259 .read = sys_dtim2_read,
261 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
265 * Initialize time subsystem. Called from linux/init/main.c
267 void __init time_init(void)
271 printk(KERN_INFO "Initializing time\n");
273 /* initialize system clocks */
276 cfv4_clockevent_init();
277 /* initialize the system timer */
280 /* setup initial system time */
281 xtime.tv_sec = cf_rtc_get_time();
283 set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec,
287 clocksource_cfv4.mult = clocksource_hz2mult(FREQ,
288 clocksource_cfv4.shift);
290 /* register our clocksource */
291 ret = clocksource_register(&clocksource_cfv4);
293 printk(KERN_ERR "timer: unable to "
294 "register clocksource - %d\n", ret);
301 static struct sysdev_class timer_class = {
305 static struct sys_device timer_device = {
310 static int __init timer_init_sysfs(void)
312 int err = sysdev_class_register(&timer_class);
314 err = sysdev_register(&timer_device);
317 device_initcall(timer_init_sysfs);
318 #endif /* CONFIG_GENERIC_CLOCKEVENTS */