Root/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);
37extern void sys_dtim_init(void);*/
38extern unsigned long long sys_dtim2_read(void);
39extern void sys_dtim2_init(void);
40static int cfv4_set_next_event(unsigned long evt,
41    struct clock_event_device *dev);
42static 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
53static unsigned long null_rtc_get_time(void)
54{
55    return mktime(2008, 1, 1, 0, 0, 0);
56}
57
58static int null_rtc_set_time(unsigned long sec)
59{
60    return 0;
61}
62
63static unsigned long (*cf_rtc_get_time)(void) = null_rtc_get_time;
64static 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 */
76static 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
117void __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 */
140void 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}
173EXPORT_SYMBOL(do_gettimeofday);
174
175int 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}
203EXPORT_SYMBOL(do_settimeofday);
204#endif /* !CONFIG_GENERIC_TIME */
205
206#ifdef CONFIG_GENERIC_CLOCKEVENTS
207/*
208 * Clock Evnt setup
209 */
210static 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
219static int cfv4_set_next_event(unsigned long evt,
220    struct clock_event_device *dev)
221{
222    return 0;
223}
224
225static 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
232static 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
255struct 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 */
267void __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
301static struct sysdev_class timer_class = {
302    .name = "timer",
303};
304
305static struct sys_device timer_device = {
306    .id = 0,
307    .cls = &timer_class,
308};
309
310static 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}
317device_initcall(timer_init_sysfs);
318#endif /* CONFIG_GENERIC_CLOCKEVENTS */
319

Archive Download this file



interactive