1 /*
2 * linux/arch/m68k/atari/time.c
3 *
4 * Atari time and real time clock stuff
5 *
6 * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive
10 * for more details.
11 */
12
13 #include <linux/types.h>
14 #include <linux/mc146818rtc.h>
15 #include <linux/interrupt.h>
16 #include <linux/init.h>
17 #include <linux/rtc.h>
18
19 #include <asm/atariints.h>
20
21 void __init
atari_sched_init(void (* timer_routine)(int,void *,struct pt_regs *))22 atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
23 {
24 /* set Timer C data Register */
25 mfp.tim_dt_c = INT_TICKS;
26 /* start timer C, div = 1:100 */
27 mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
28 /* install interrupt service routine for MFP Timer C */
29 request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
30 "timer", timer_routine);
31 }
32
33 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
34
35 #define TICK_SIZE 10000
36
37 /* This is always executed with interrupts disabled. */
atari_gettimeoffset(void)38 unsigned long atari_gettimeoffset (void)
39 {
40 unsigned long ticks, offset = 0;
41
42 /* read MFP timer C current value */
43 ticks = mfp.tim_dt_c;
44 /* The probability of underflow is less than 2% */
45 if (ticks > INT_TICKS - INT_TICKS / 50)
46 /* Check for pending timer interrupt */
47 if (mfp.int_pn_b & (1 << 5))
48 offset = TICK_SIZE;
49
50 ticks = INT_TICKS - ticks;
51 ticks = ticks * 10000L / INT_TICKS;
52
53 return ticks + offset;
54 }
55
56
mste_read(struct MSTE_RTC * val)57 static void mste_read(struct MSTE_RTC *val)
58 {
59 #define COPY(v) val->v=(mste_rtc.v & 0xf)
60 do {
61 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
62 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
63 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
64 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
65 COPY(year_tens) ;
66 /* prevent from reading the clock while it changed */
67 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
68 #undef COPY
69 }
70
mste_write(struct MSTE_RTC * val)71 static void mste_write(struct MSTE_RTC *val)
72 {
73 #define COPY(v) mste_rtc.v=val->v
74 do {
75 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
76 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
77 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
78 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
79 COPY(year_tens) ;
80 /* prevent from writing the clock while it changed */
81 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
82 #undef COPY
83 }
84
85 #define RTC_READ(reg) \
86 ({ unsigned char __val; \
87 (void) atari_writeb(reg,&tt_rtc.regsel); \
88 __val = tt_rtc.data; \
89 __val; \
90 })
91
92 #define RTC_WRITE(reg,val) \
93 do { \
94 atari_writeb(reg,&tt_rtc.regsel); \
95 tt_rtc.data = (val); \
96 } while(0)
97
98
atari_mste_gettod(int * yearp,int * monp,int * dayp,int * hourp,int * minp,int * secp)99 void atari_mste_gettod (int *yearp, int *monp, int *dayp,
100 int *hourp, int *minp, int *secp)
101 {
102 int hr24=0, hour;
103 struct MSTE_RTC val;
104
105 mste_rtc.mode=(mste_rtc.mode | 1);
106 hr24=mste_rtc.mon_tens & 1;
107 mste_rtc.mode=(mste_rtc.mode & ~1);
108
109 mste_read(&val);
110 *secp = val.sec_ones + val.sec_tens * 10;
111 *minp = val.min_ones + val.min_tens * 10;
112 hour = val.hr_ones + val.hr_tens * 10;
113 if (!hr24) {
114 if (hour == 12 || hour == 12 + 20)
115 hour -= 12;
116 if (hour >= 20)
117 hour += 12 - 20;
118 }
119 *hourp = hour;
120 *dayp = val.day_ones + val.day_tens * 10;
121 *monp = val.mon_ones + val.mon_tens * 10;
122 *yearp = val.year_ones + val.year_tens * 10 + 80;
123 }
124
125
atari_tt_gettod(int * yearp,int * monp,int * dayp,int * hourp,int * minp,int * secp)126 void atari_tt_gettod (int *yearp, int *monp, int *dayp,
127 int *hourp, int *minp, int *secp)
128 {
129 unsigned char ctrl;
130 int hour, pm;
131
132 while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
133 while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
134
135 *secp = RTC_READ(RTC_SECONDS);
136 *minp = RTC_READ(RTC_MINUTES);
137 hour = RTC_READ(RTC_HOURS);
138 *dayp = RTC_READ(RTC_DAY_OF_MONTH);
139 *monp = RTC_READ(RTC_MONTH);
140 *yearp = RTC_READ(RTC_YEAR);
141 pm = hour & 0x80;
142 hour &= ~0x80;
143
144 ctrl = RTC_READ(RTC_CONTROL);
145
146 if (!(ctrl & RTC_DM_BINARY)) {
147 BCD_TO_BIN(*secp);
148 BCD_TO_BIN(*minp);
149 BCD_TO_BIN(hour);
150 BCD_TO_BIN(*dayp);
151 BCD_TO_BIN(*monp);
152 BCD_TO_BIN(*yearp);
153 }
154 if (!(ctrl & RTC_24H)) {
155 if (!pm && hour == 12)
156 hour = 0;
157 else if (pm && hour != 12)
158 hour += 12;
159 }
160 *hourp = hour;
161
162 /* Adjust values (let the setup valid) */
163 *yearp += atari_rtc_year_offset;
164 }
165
166 #define HWCLK_POLL_INTERVAL 5
167
atari_mste_hwclk(int op,struct rtc_time * t)168 int atari_mste_hwclk( int op, struct rtc_time *t )
169 {
170 int hour, year;
171 int hr24=0;
172 struct MSTE_RTC val;
173
174 mste_rtc.mode=(mste_rtc.mode | 1);
175 hr24=mste_rtc.mon_tens & 1;
176 mste_rtc.mode=(mste_rtc.mode & ~1);
177
178 if (op) {
179 /* write: prepare values */
180
181 val.sec_ones = t->tm_sec % 10;
182 val.sec_tens = t->tm_sec / 10;
183 val.min_ones = t->tm_min % 10;
184 val.min_tens = t->tm_min / 10;
185 hour = t->tm_hour;
186 if (!hr24) {
187 if (hour > 11)
188 hour += 20 - 12;
189 if (hour == 0 || hour == 20)
190 hour += 12;
191 }
192 val.hr_ones = hour % 10;
193 val.hr_tens = hour / 10;
194 val.day_ones = t->tm_mday % 10;
195 val.day_tens = t->tm_mday / 10;
196 val.mon_ones = (t->tm_mon+1) % 10;
197 val.mon_tens = (t->tm_mon+1) / 10;
198 year = t->tm_year - 80;
199 val.year_ones = year % 10;
200 val.year_tens = year / 10;
201 val.weekday = t->tm_wday;
202 mste_write(&val);
203 mste_rtc.mode=(mste_rtc.mode | 1);
204 val.year_ones = (year % 4); /* leap year register */
205 mste_rtc.mode=(mste_rtc.mode & ~1);
206 }
207 else {
208 mste_read(&val);
209 t->tm_sec = val.sec_ones + val.sec_tens * 10;
210 t->tm_min = val.min_ones + val.min_tens * 10;
211 hour = val.hr_ones + val.hr_tens * 10;
212 if (!hr24) {
213 if (hour == 12 || hour == 12 + 20)
214 hour -= 12;
215 if (hour >= 20)
216 hour += 12 - 20;
217 }
218 t->tm_hour = hour;
219 t->tm_mday = val.day_ones + val.day_tens * 10;
220 t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
221 t->tm_year = val.year_ones + val.year_tens * 10 + 80;
222 t->tm_wday = val.weekday;
223 }
224 return 0;
225 }
226
atari_tt_hwclk(int op,struct rtc_time * t)227 int atari_tt_hwclk( int op, struct rtc_time *t )
228 {
229 int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
230 unsigned long flags;
231 unsigned char ctrl;
232 int pm = 0;
233
234 ctrl = RTC_READ(RTC_CONTROL); /* control registers are
235 * independent from the UIP */
236
237 if (op) {
238 /* write: prepare values */
239
240 sec = t->tm_sec;
241 min = t->tm_min;
242 hour = t->tm_hour;
243 day = t->tm_mday;
244 mon = t->tm_mon + 1;
245 year = t->tm_year - atari_rtc_year_offset;
246 wday = t->tm_wday + (t->tm_wday >= 0);
247
248 if (!(ctrl & RTC_24H)) {
249 if (hour > 11) {
250 pm = 0x80;
251 if (hour != 12)
252 hour -= 12;
253 }
254 else if (hour == 0)
255 hour = 12;
256 }
257
258 if (!(ctrl & RTC_DM_BINARY)) {
259 BIN_TO_BCD(sec);
260 BIN_TO_BCD(min);
261 BIN_TO_BCD(hour);
262 BIN_TO_BCD(day);
263 BIN_TO_BCD(mon);
264 BIN_TO_BCD(year);
265 if (wday >= 0) BIN_TO_BCD(wday);
266 }
267 }
268
269 /* Reading/writing the clock registers is a bit critical due to
270 * the regular update cycle of the RTC. While an update is in
271 * progress, registers 0..9 shouldn't be touched.
272 * The problem is solved like that: If an update is currently in
273 * progress (the UIP bit is set), the process sleeps for a while
274 * (50ms). This really should be enough, since the update cycle
275 * normally needs 2 ms.
276 * If the UIP bit reads as 0, we have at least 244 usecs until the
277 * update starts. This should be enough... But to be sure,
278 * additionally the RTC_SET bit is set to prevent an update cycle.
279 */
280
281 while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
282 current->state = TASK_INTERRUPTIBLE;
283 schedule_timeout(HWCLK_POLL_INTERVAL);
284 }
285
286 save_flags(flags);
287 cli();
288 RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
289 if (!op) {
290 sec = RTC_READ( RTC_SECONDS );
291 min = RTC_READ( RTC_MINUTES );
292 hour = RTC_READ( RTC_HOURS );
293 day = RTC_READ( RTC_DAY_OF_MONTH );
294 mon = RTC_READ( RTC_MONTH );
295 year = RTC_READ( RTC_YEAR );
296 wday = RTC_READ( RTC_DAY_OF_WEEK );
297 }
298 else {
299 RTC_WRITE( RTC_SECONDS, sec );
300 RTC_WRITE( RTC_MINUTES, min );
301 RTC_WRITE( RTC_HOURS, hour + pm);
302 RTC_WRITE( RTC_DAY_OF_MONTH, day );
303 RTC_WRITE( RTC_MONTH, mon );
304 RTC_WRITE( RTC_YEAR, year );
305 if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
306 }
307 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
308 restore_flags(flags);
309
310 if (!op) {
311 /* read: adjust values */
312
313 if (hour & 0x80) {
314 hour &= ~0x80;
315 pm = 1;
316 }
317
318 if (!(ctrl & RTC_DM_BINARY)) {
319 BCD_TO_BIN(sec);
320 BCD_TO_BIN(min);
321 BCD_TO_BIN(hour);
322 BCD_TO_BIN(day);
323 BCD_TO_BIN(mon);
324 BCD_TO_BIN(year);
325 BCD_TO_BIN(wday);
326 }
327
328 if (!(ctrl & RTC_24H)) {
329 if (!pm && hour == 12)
330 hour = 0;
331 else if (pm && hour != 12)
332 hour += 12;
333 }
334
335 t->tm_sec = sec;
336 t->tm_min = min;
337 t->tm_hour = hour;
338 t->tm_mday = day;
339 t->tm_mon = mon - 1;
340 t->tm_year = year + atari_rtc_year_offset;
341 t->tm_wday = wday - 1;
342 }
343
344 return( 0 );
345 }
346
347
atari_mste_set_clock_mmss(unsigned long nowtime)348 int atari_mste_set_clock_mmss (unsigned long nowtime)
349 {
350 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
351 struct MSTE_RTC val;
352 unsigned char rtc_minutes;
353
354 mste_read(&val);
355 rtc_minutes= val.min_ones + val.min_tens * 10;
356 if ((rtc_minutes < real_minutes
357 ? real_minutes - rtc_minutes
358 : rtc_minutes - real_minutes) < 30)
359 {
360 val.sec_ones = real_seconds % 10;
361 val.sec_tens = real_seconds / 10;
362 val.min_ones = real_minutes % 10;
363 val.min_tens = real_minutes / 10;
364 mste_write(&val);
365 }
366 else
367 return -1;
368 return 0;
369 }
370
atari_tt_set_clock_mmss(unsigned long nowtime)371 int atari_tt_set_clock_mmss (unsigned long nowtime)
372 {
373 int retval = 0;
374 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
375 unsigned char save_control, save_freq_select, rtc_minutes;
376
377 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
378 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
379
380 save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
381 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
382
383 rtc_minutes = RTC_READ (RTC_MINUTES);
384 if (!(save_control & RTC_DM_BINARY))
385 BCD_TO_BIN (rtc_minutes);
386
387 /* Since we're only adjusting minutes and seconds, don't interfere
388 with hour overflow. This avoids messing with unknown time zones
389 but requires your RTC not to be off by more than 30 minutes. */
390 if ((rtc_minutes < real_minutes
391 ? real_minutes - rtc_minutes
392 : rtc_minutes - real_minutes) < 30)
393 {
394 if (!(save_control & RTC_DM_BINARY))
395 {
396 BIN_TO_BCD (real_seconds);
397 BIN_TO_BCD (real_minutes);
398 }
399 RTC_WRITE (RTC_SECONDS, real_seconds);
400 RTC_WRITE (RTC_MINUTES, real_minutes);
401 }
402 else
403 retval = -1;
404
405 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
406 RTC_WRITE (RTC_CONTROL, save_control);
407 return retval;
408 }
409
410 /*
411 * Local variables:
412 * c-indent-level: 4
413 * tab-width: 8
414 * End:
415 */
416