]>
Commit | Line | Data |
---|---|---|
85d0b3a5 RH |
1 | /* |
2 | * linux/arch/alpha/kernel/rtc.c | |
3 | * | |
4 | * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds | |
5 | * | |
6 | * This file contains date handling. | |
7 | */ | |
8 | #include <linux/errno.h> | |
9 | #include <linux/init.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/param.h> | |
12 | #include <linux/string.h> | |
13 | #include <linux/mc146818rtc.h> | |
14 | #include <linux/bcd.h> | |
15 | #include <linux/rtc.h> | |
16 | #include <linux/platform_device.h> | |
17 | ||
85d0b3a5 RH |
18 | #include "proto.h" |
19 | ||
20 | ||
21 | /* | |
22 | * Support for the RTC device. | |
23 | * | |
24 | * We don't want to use the rtc-cmos driver, because we don't want to support | |
25 | * alarms, as that would be indistinguishable from timer interrupts. | |
26 | * | |
27 | * Further, generic code is really, really tied to a 1900 epoch. This is | |
28 | * true in __get_rtc_time as well as the users of struct rtc_time e.g. | |
29 | * rtc_tm_to_time. Thankfully all of the other epochs in use are later | |
30 | * than 1900, and so it's easy to adjust. | |
31 | */ | |
32 | ||
33 | static unsigned long rtc_epoch; | |
34 | ||
35 | static int __init | |
36 | specifiy_epoch(char *str) | |
37 | { | |
38 | unsigned long epoch = simple_strtoul(str, NULL, 0); | |
39 | if (epoch < 1900) | |
40 | printk("Ignoring invalid user specified epoch %lu\n", epoch); | |
41 | else | |
42 | rtc_epoch = epoch; | |
43 | return 1; | |
44 | } | |
45 | __setup("epoch=", specifiy_epoch); | |
46 | ||
47 | static void __init | |
48 | init_rtc_epoch(void) | |
49 | { | |
50 | int epoch, year, ctrl; | |
51 | ||
52 | if (rtc_epoch != 0) { | |
53 | /* The epoch was specified on the command-line. */ | |
54 | return; | |
55 | } | |
56 | ||
57 | /* Detect the epoch in use on this computer. */ | |
58 | ctrl = CMOS_READ(RTC_CONTROL); | |
59 | year = CMOS_READ(RTC_YEAR); | |
60 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | |
61 | year = bcd2bin(year); | |
62 | ||
63 | /* PC-like is standard; used for year >= 70 */ | |
64 | epoch = 1900; | |
65 | if (year < 20) { | |
66 | epoch = 2000; | |
67 | } else if (year >= 20 && year < 48) { | |
68 | /* NT epoch */ | |
69 | epoch = 1980; | |
70 | } else if (year >= 48 && year < 70) { | |
71 | /* Digital UNIX epoch */ | |
72 | epoch = 1952; | |
73 | } | |
74 | rtc_epoch = epoch; | |
75 | ||
76 | printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year); | |
77 | } | |
78 | ||
79 | static int | |
80 | alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) | |
81 | { | |
5ab788d7 | 82 | mc146818_get_time(tm); |
85d0b3a5 RH |
83 | |
84 | /* Adjust for non-default epochs. It's easier to depend on the | |
85 | generic __get_rtc_time and adjust the epoch here than create | |
86 | a copy of __get_rtc_time with the edits we need. */ | |
87 | if (rtc_epoch != 1900) { | |
88 | int year = tm->tm_year; | |
89 | /* Undo the century adjustment made in __get_rtc_time. */ | |
90 | if (year >= 100) | |
91 | year -= 100; | |
92 | year += rtc_epoch - 1900; | |
93 | /* Redo the century adjustment with the epoch in place. */ | |
94 | if (year <= 69) | |
95 | year += 100; | |
96 | tm->tm_year = year; | |
97 | } | |
98 | ||
99 | return rtc_valid_tm(tm); | |
100 | } | |
101 | ||
102 | static int | |
103 | alpha_rtc_set_time(struct device *dev, struct rtc_time *tm) | |
104 | { | |
105 | struct rtc_time xtm; | |
106 | ||
107 | if (rtc_epoch != 1900) { | |
108 | xtm = *tm; | |
109 | xtm.tm_year -= rtc_epoch - 1900; | |
110 | tm = &xtm; | |
111 | } | |
112 | ||
5ab788d7 | 113 | return mc146818_set_time(tm); |
85d0b3a5 RH |
114 | } |
115 | ||
116 | static int | |
a5312f56 | 117 | alpha_rtc_set_mmss(struct device *dev, time64_t nowtime) |
85d0b3a5 RH |
118 | { |
119 | int retval = 0; | |
120 | int real_seconds, real_minutes, cmos_minutes; | |
121 | unsigned char save_control, save_freq_select; | |
122 | ||
123 | /* Note: This code only updates minutes and seconds. Comments | |
124 | indicate this was to avoid messing with unknown time zones, | |
125 | and with the epoch nonsense described above. In order for | |
126 | this to work, the existing clock cannot be off by more than | |
127 | 15 minutes. | |
128 | ||
129 | ??? This choice is may be out of date. The x86 port does | |
130 | not have problems with timezones, and the epoch processing has | |
131 | now been fixed in alpha_set_rtc_time. | |
132 | ||
133 | In either case, one can always force a full rtc update with | |
134 | the userland hwclock program, so surely 15 minute accuracy | |
135 | is no real burden. */ | |
136 | ||
137 | /* In order to set the CMOS clock precisely, we have to be called | |
138 | 500 ms after the second nowtime has started, because when | |
139 | nowtime is written into the registers of the CMOS clock, it will | |
140 | jump to the next second precisely 500 ms later. Check the Motorola | |
141 | MC146818A or Dallas DS12887 data sheet for details. */ | |
142 | ||
143 | /* irq are locally disabled here */ | |
144 | spin_lock(&rtc_lock); | |
145 | /* Tell the clock it's being set */ | |
146 | save_control = CMOS_READ(RTC_CONTROL); | |
147 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | |
148 | ||
149 | /* Stop and reset prescaler */ | |
150 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | |
151 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | |
152 | ||
153 | cmos_minutes = CMOS_READ(RTC_MINUTES); | |
154 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | |
155 | cmos_minutes = bcd2bin(cmos_minutes); | |
156 | ||
157 | real_seconds = nowtime % 60; | |
158 | real_minutes = nowtime / 60; | |
159 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) { | |
160 | /* correct for half hour time zone */ | |
161 | real_minutes += 30; | |
162 | } | |
163 | real_minutes %= 60; | |
164 | ||
165 | if (abs(real_minutes - cmos_minutes) < 30) { | |
166 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | |
167 | real_seconds = bin2bcd(real_seconds); | |
168 | real_minutes = bin2bcd(real_minutes); | |
169 | } | |
170 | CMOS_WRITE(real_seconds,RTC_SECONDS); | |
171 | CMOS_WRITE(real_minutes,RTC_MINUTES); | |
172 | } else { | |
173 | printk_once(KERN_NOTICE | |
174 | "set_rtc_mmss: can't update from %d to %d\n", | |
175 | cmos_minutes, real_minutes); | |
176 | retval = -1; | |
177 | } | |
178 | ||
179 | /* The following flags have to be released exactly in this order, | |
180 | * otherwise the DS12887 (popular MC146818A clone with integrated | |
181 | * battery and quartz) will not reset the oscillator and will not | |
182 | * update precisely 500 ms later. You won't find this mentioned in | |
183 | * the Dallas Semiconductor data sheets, but who believes data | |
184 | * sheets anyway ... -- Markus Kuhn | |
185 | */ | |
186 | CMOS_WRITE(save_control, RTC_CONTROL); | |
187 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | |
188 | spin_unlock(&rtc_lock); | |
189 | ||
190 | return retval; | |
191 | } | |
192 | ||
193 | static int | |
194 | alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |
195 | { | |
196 | switch (cmd) { | |
197 | case RTC_EPOCH_READ: | |
198 | return put_user(rtc_epoch, (unsigned long __user *)arg); | |
199 | case RTC_EPOCH_SET: | |
200 | if (arg < 1900) | |
201 | return -EINVAL; | |
202 | rtc_epoch = arg; | |
203 | return 0; | |
204 | default: | |
205 | return -ENOIOCTLCMD; | |
206 | } | |
207 | } | |
208 | ||
209 | static const struct rtc_class_ops alpha_rtc_ops = { | |
210 | .read_time = alpha_rtc_read_time, | |
211 | .set_time = alpha_rtc_set_time, | |
a5312f56 | 212 | .set_mmss64 = alpha_rtc_set_mmss, |
85d0b3a5 RH |
213 | .ioctl = alpha_rtc_ioctl, |
214 | }; | |
215 | ||
216 | /* | |
217 | * Similarly, except do the actual CMOS access on the boot cpu only. | |
218 | * This requires marshalling the data across an interprocessor call. | |
219 | */ | |
220 | ||
221 | #if defined(CONFIG_SMP) && \ | |
222 | (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL)) | |
223 | # define HAVE_REMOTE_RTC 1 | |
224 | ||
225 | union remote_data { | |
226 | struct rtc_time *tm; | |
227 | unsigned long now; | |
228 | long retval; | |
229 | }; | |
230 | ||
231 | static void | |
232 | do_remote_read(void *data) | |
233 | { | |
234 | union remote_data *x = data; | |
235 | x->retval = alpha_rtc_read_time(NULL, x->tm); | |
236 | } | |
237 | ||
238 | static int | |
239 | remote_read_time(struct device *dev, struct rtc_time *tm) | |
240 | { | |
241 | union remote_data x; | |
242 | if (smp_processor_id() != boot_cpuid) { | |
243 | x.tm = tm; | |
244 | smp_call_function_single(boot_cpuid, do_remote_read, &x, 1); | |
245 | return x.retval; | |
246 | } | |
247 | return alpha_rtc_read_time(NULL, tm); | |
248 | } | |
249 | ||
250 | static void | |
251 | do_remote_set(void *data) | |
252 | { | |
253 | union remote_data *x = data; | |
254 | x->retval = alpha_rtc_set_time(NULL, x->tm); | |
255 | } | |
256 | ||
257 | static int | |
258 | remote_set_time(struct device *dev, struct rtc_time *tm) | |
259 | { | |
260 | union remote_data x; | |
261 | if (smp_processor_id() != boot_cpuid) { | |
262 | x.tm = tm; | |
263 | smp_call_function_single(boot_cpuid, do_remote_set, &x, 1); | |
264 | return x.retval; | |
265 | } | |
266 | return alpha_rtc_set_time(NULL, tm); | |
267 | } | |
268 | ||
269 | static void | |
270 | do_remote_mmss(void *data) | |
271 | { | |
272 | union remote_data *x = data; | |
273 | x->retval = alpha_rtc_set_mmss(NULL, x->now); | |
274 | } | |
275 | ||
276 | static int | |
a5312f56 | 277 | remote_set_mmss(struct device *dev, time64_t now) |
85d0b3a5 RH |
278 | { |
279 | union remote_data x; | |
280 | if (smp_processor_id() != boot_cpuid) { | |
281 | x.now = now; | |
282 | smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1); | |
283 | return x.retval; | |
284 | } | |
285 | return alpha_rtc_set_mmss(NULL, now); | |
286 | } | |
287 | ||
288 | static const struct rtc_class_ops remote_rtc_ops = { | |
289 | .read_time = remote_read_time, | |
290 | .set_time = remote_set_time, | |
a5312f56 | 291 | .set_mmss64 = remote_set_mmss, |
85d0b3a5 RH |
292 | .ioctl = alpha_rtc_ioctl, |
293 | }; | |
294 | #endif | |
295 | ||
296 | static int __init | |
297 | alpha_rtc_init(void) | |
298 | { | |
299 | const struct rtc_class_ops *ops; | |
300 | struct platform_device *pdev; | |
301 | struct rtc_device *rtc; | |
302 | const char *name; | |
303 | ||
304 | init_rtc_epoch(); | |
305 | name = "rtc-alpha"; | |
306 | ops = &alpha_rtc_ops; | |
307 | ||
308 | #ifdef HAVE_REMOTE_RTC | |
309 | if (alpha_mv.rtc_boot_cpu_only) | |
310 | ops = &remote_rtc_ops; | |
311 | #endif | |
312 | ||
313 | pdev = platform_device_register_simple(name, -1, NULL, 0); | |
314 | rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE); | |
315 | if (IS_ERR(rtc)) | |
316 | return PTR_ERR(rtc); | |
317 | ||
318 | platform_set_drvdata(pdev, rtc); | |
319 | return 0; | |
320 | } | |
321 | device_initcall(alpha_rtc_init); |