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 */