Commit | Line | Data |
---|---|---|
daa00b9c | 1 | /* |
1da177e4 LT |
2 | * linux/arch/cris/kernel/time.c |
3 | * | |
4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | |
5 | * Copyright (C) 1999, 2000, 2001 Axis Communications AB | |
6 | * | |
7 | * 1994-07-02 Alan Modra | |
8 | * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime | |
9 | * 1995-03-26 Markus Kuhn | |
10 | * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 | |
11 | * precision CMOS clock update | |
12 | * 1996-05-03 Ingo Molnar | |
13 | * fixed time warps in do_[slow|fast]_gettimeoffset() | |
14 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | |
15 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | |
16 | * | |
17 | * Linux/CRIS specific code: | |
18 | * | |
19 | * Authors: Bjorn Wesen | |
daa00b9c | 20 | * Johan Adolfsson |
1da177e4 LT |
21 | * |
22 | */ | |
23 | ||
24 | #include <asm/rtc.h> | |
25 | #include <linux/errno.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/param.h> | |
28 | #include <linux/jiffies.h> | |
29 | #include <linux/bcd.h> | |
30 | #include <linux/timex.h> | |
31 | #include <linux/init.h> | |
21783c97 | 32 | #include <linux/profile.h> |
4e57b681 | 33 | #include <linux/sched.h> /* just for sched_clock() - funny that */ |
1da177e4 | 34 | |
1da177e4 LT |
35 | int have_rtc; /* used to remember if we have an RTC or not */; |
36 | ||
37 | #define TICK_SIZE tick | |
38 | ||
1da177e4 LT |
39 | extern unsigned long loops_per_jiffy; /* init/main.c */ |
40 | unsigned long loops_per_usec; | |
41 | ||
42 | extern unsigned long do_slow_gettimeoffset(void); | |
43 | static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; | |
44 | ||
ba875ba6 | 45 | u32 arch_gettimeoffset(void) |
1da177e4 | 46 | { |
ba875ba6 | 47 | return do_gettimeoffset() * 1000; |
1da177e4 LT |
48 | } |
49 | ||
1da177e4 LT |
50 | /* |
51 | * BUG: This routine does not handle hour overflow properly; it just | |
52 | * sets the minutes. Usually you'll only notice that after reboot! | |
53 | */ | |
54 | ||
55 | int set_rtc_mmss(unsigned long nowtime) | |
56 | { | |
57 | int retval = 0; | |
58 | int real_seconds, real_minutes, cmos_minutes; | |
59 | ||
60 | printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime); | |
61 | ||
62 | if(!have_rtc) | |
63 | return 0; | |
64 | ||
65 | cmos_minutes = CMOS_READ(RTC_MINUTES); | |
4110a0d6 | 66 | cmos_minutes = bcd2bin(cmos_minutes); |
1da177e4 LT |
67 | |
68 | /* | |
69 | * since we're only adjusting minutes and seconds, | |
70 | * don't interfere with hour overflow. This avoids | |
71 | * messing with unknown time zones but requires your | |
72 | * RTC not to be off by more than 15 minutes | |
73 | */ | |
74 | real_seconds = nowtime % 60; | |
75 | real_minutes = nowtime / 60; | |
76 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | |
77 | real_minutes += 30; /* correct for half hour time zone */ | |
78 | real_minutes %= 60; | |
79 | ||
80 | if (abs(real_minutes - cmos_minutes) < 30) { | |
4110a0d6 AB |
81 | real_seconds = bin2bcd(real_seconds); |
82 | real_minutes = bin2bcd(real_minutes); | |
1da177e4 LT |
83 | CMOS_WRITE(real_seconds,RTC_SECONDS); |
84 | CMOS_WRITE(real_minutes,RTC_MINUTES); | |
85 | } else { | |
86 | printk(KERN_WARNING | |
87 | "set_rtc_mmss: can't update from %d to %d\n", | |
88 | cmos_minutes, real_minutes); | |
89 | retval = -1; | |
90 | } | |
91 | ||
92 | return retval; | |
93 | } | |
94 | ||
95 | /* grab the time from the RTC chip */ | |
96 | ||
97 | unsigned long | |
98 | get_cmos_time(void) | |
99 | { | |
100 | unsigned int year, mon, day, hour, min, sec; | |
8eff8a5c JS |
101 | if(!have_rtc) |
102 | return 0; | |
1da177e4 LT |
103 | |
104 | sec = CMOS_READ(RTC_SECONDS); | |
105 | min = CMOS_READ(RTC_MINUTES); | |
106 | hour = CMOS_READ(RTC_HOURS); | |
107 | day = CMOS_READ(RTC_DAY_OF_MONTH); | |
108 | mon = CMOS_READ(RTC_MONTH); | |
109 | year = CMOS_READ(RTC_YEAR); | |
110 | ||
4110a0d6 AB |
111 | sec = bcd2bin(sec); |
112 | min = bcd2bin(min); | |
113 | hour = bcd2bin(hour); | |
114 | day = bcd2bin(day); | |
115 | mon = bcd2bin(mon); | |
116 | year = bcd2bin(year); | |
1da177e4 LT |
117 | |
118 | if ((year += 1900) < 1970) | |
119 | year += 100; | |
120 | ||
121 | return mktime(year, mon, day, hour, min, sec); | |
122 | } | |
123 | ||
1da177e4 | 124 | |
8eff8a5c | 125 | int update_persistent_clock(struct timespec now) |
1da177e4 | 126 | { |
8eff8a5c | 127 | return set_rtc_mmss(now.tv_sec); |
1da177e4 LT |
128 | } |
129 | ||
8eff8a5c JS |
130 | void read_persistent_clock(struct timespec *ts) |
131 | { | |
132 | ts->tv_sec = get_cmos_time(); | |
133 | ts->tv_nsec = 0; | |
134 | } | |
135 | ||
136 | ||
21783c97 MS |
137 | extern void cris_profile_sample(struct pt_regs* regs); |
138 | ||
139 | void | |
140 | cris_do_profile(struct pt_regs* regs) | |
141 | { | |
142 | ||
0188e603 | 143 | #ifdef CONFIG_SYSTEM_PROFILER |
21783c97 MS |
144 | cris_profile_sample(regs); |
145 | #endif | |
146 | ||
0188e603 | 147 | #ifdef CONFIG_PROFILING |
c2610381 | 148 | profile_tick(CPU_PROFILING); |
21783c97 MS |
149 | #endif |
150 | } | |
151 | ||
daa00b9c JN |
152 | unsigned long long sched_clock(void) |
153 | { | |
154 | return (unsigned long long)jiffies * (1000000000 / HZ) + | |
155 | get_ns_in_jiffie(); | |
156 | } | |
157 | ||
1da177e4 LT |
158 | static int |
159 | __init init_udelay(void) | |
160 | { | |
161 | loops_per_usec = (loops_per_jiffy * HZ) / 1000000; | |
162 | return 0; | |
163 | } | |
164 | ||
165 | __initcall(init_udelay); |