Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / arch / m68k / atari / time.c
blob08b861c55acc8f936a357cee6e24c4595de17c2d
1 /*
2 * linux/arch/m68k/atari/time.c
4 * Atari time and real time clock stuff
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.
13 #include <linux/types.h>
14 #include <linux/mc146818rtc.h>
15 #include <linux/kd.h>
16 #include <linux/interrupt.h>
17 #include <linux/init.h>
20 void __init
21 atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
23 /* set Timer C data Register */
24 mfp.tim_dt_c = INT_TICKS;
25 /* start timer C, div = 1:100 */
26 mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
27 /* install interrupt service routine for MFP Timer C */
28 request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
29 "timer", timer_routine);
32 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
34 #define TICK_SIZE 10000
36 /* This is always executed with interrupts disabled. */
37 unsigned long atari_gettimeoffset (void)
39 unsigned long ticks, offset = 0;
41 /* read MFP timer C current value */
42 ticks = mfp.tim_dt_c;
43 /* The probability of underflow is less than 2% */
44 if (ticks > INT_TICKS - INT_TICKS / 50)
45 /* Check for pending timer interrupt */
46 if (mfp.int_pn_b & (1 << 5))
47 offset = TICK_SIZE;
49 ticks = INT_TICKS - ticks;
50 ticks = ticks * 10000L / INT_TICKS;
52 return ticks + offset;
56 static void mste_read(struct MSTE_RTC *val)
58 #define COPY(v) val->v=(mste_rtc.v & 0xf)
59 do {
60 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
61 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
62 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
63 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
64 COPY(year_tens) ;
65 /* prevent from reading the clock while it changed */
66 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
67 #undef COPY
70 static void mste_write(struct MSTE_RTC *val)
72 #define COPY(v) mste_rtc.v=val->v
73 do {
74 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
75 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
76 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
77 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
78 COPY(year_tens) ;
79 /* prevent from writing the clock while it changed */
80 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
81 #undef COPY
84 #define RTC_READ(reg) \
85 ({ unsigned char __val; \
86 (void) writeb(reg,&tt_rtc.regsel); \
87 __val = tt_rtc.data; \
88 __val; \
91 #define RTC_WRITE(reg,val) \
92 do { \
93 writeb(reg,&tt_rtc.regsel); \
94 tt_rtc.data = (val); \
95 } while(0)
98 void atari_mste_gettod (int *yearp, int *monp, int *dayp,
99 int *hourp, int *minp, int *secp)
101 int hr24=0, hour;
102 struct MSTE_RTC val;
104 mste_rtc.mode=(mste_rtc.mode | 1);
105 hr24=mste_rtc.mon_tens & 1;
106 mste_rtc.mode=(mste_rtc.mode & ~1);
108 mste_read(&val);
109 *secp = val.sec_ones + val.sec_tens * 10;
110 *minp = val.min_ones + val.min_tens * 10;
111 hour = val.hr_ones + val.hr_tens * 10;
112 if (!hr24) {
113 if (hour == 12 || hour == 12 + 20)
114 hour -= 12;
115 if (hour >= 20)
116 hour += 12 - 20;
118 *hourp = hour;
119 *dayp = val.day_ones + val.day_tens * 10;
120 *monp = val.mon_ones + val.mon_tens * 10;
121 *yearp = val.year_ones + val.year_tens * 10 + 80;
125 void atari_tt_gettod (int *yearp, int *monp, int *dayp,
126 int *hourp, int *minp, int *secp)
128 unsigned char ctrl;
129 int hour, pm;
131 while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
132 while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
134 *secp = RTC_READ(RTC_SECONDS);
135 *minp = RTC_READ(RTC_MINUTES);
136 hour = RTC_READ(RTC_HOURS);
137 *dayp = RTC_READ(RTC_DAY_OF_MONTH);
138 *monp = RTC_READ(RTC_MONTH);
139 *yearp = RTC_READ(RTC_YEAR);
140 pm = hour & 0x80;
141 hour &= ~0x80;
143 ctrl = RTC_READ(RTC_CONTROL);
145 if (!(ctrl & RTC_DM_BINARY)) {
146 BCD_TO_BIN(*secp);
147 BCD_TO_BIN(*minp);
148 BCD_TO_BIN(hour);
149 BCD_TO_BIN(*dayp);
150 BCD_TO_BIN(*monp);
151 BCD_TO_BIN(*yearp);
153 if (!(ctrl & RTC_24H)) {
154 if (!pm && hour == 12)
155 hour = 0;
156 else if (pm && hour != 12)
157 hour += 12;
159 *hourp = hour;
161 /* Adjust values (let the setup valid) */
162 *yearp += atari_rtc_year_offset;
165 #define HWCLK_POLL_INTERVAL 5
167 int atari_mste_hwclk( int op, struct hwclk_time *t )
169 int hour, year;
170 int hr24=0;
171 struct MSTE_RTC val;
173 mste_rtc.mode=(mste_rtc.mode | 1);
174 hr24=mste_rtc.mon_tens & 1;
175 mste_rtc.mode=(mste_rtc.mode & ~1);
177 if (op) {
178 /* write: prepare values */
180 val.sec_ones = t->sec % 10;
181 val.sec_tens = t->sec / 10;
182 val.min_ones = t->min % 10;
183 val.min_tens = t->min / 10;
184 hour = t->hour;
185 if (!hr24) {
186 if (hour > 11)
187 hour += 20 - 12;
188 if (hour == 0 || hour == 20)
189 hour += 12;
191 val.hr_ones = hour % 10;
192 val.hr_tens = hour / 10;
193 val.day_ones = t->day % 10;
194 val.day_tens = t->day / 10;
195 val.mon_ones = (t->mon+1) % 10;
196 val.mon_tens = (t->mon+1) / 10;
197 year = t->year - 80;
198 val.year_ones = year % 10;
199 val.year_tens = year / 10;
200 val.weekday = t->wday;
201 mste_write(&val);
202 mste_rtc.mode=(mste_rtc.mode | 1);
203 val.year_ones = (year % 4); /* leap year register */
204 mste_rtc.mode=(mste_rtc.mode & ~1);
206 else {
207 mste_read(&val);
208 t->sec = val.sec_ones + val.sec_tens * 10;
209 t->min = val.min_ones + val.min_tens * 10;
210 hour = val.hr_ones + val.hr_tens * 10;
211 if (!hr24) {
212 if (hour == 12 || hour == 12 + 20)
213 hour -= 12;
214 if (hour >= 20)
215 hour += 12 - 20;
217 t->hour = hour;
218 t->day = val.day_ones + val.day_tens * 10;
219 t->mon = val.mon_ones + val.mon_tens * 10 - 1;
220 t->year = val.year_ones + val.year_tens * 10 + 80;
221 t->wday = val.weekday;
223 return 0;
226 int atari_tt_hwclk( int op, struct hwclk_time *t )
228 int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
229 unsigned long flags;
230 unsigned char ctrl;
231 int pm = 0;
233 ctrl = RTC_READ(RTC_CONTROL); /* control registers are
234 * independent from the UIP */
236 if (op) {
237 /* write: prepare values */
239 sec = t->sec;
240 min = t->min;
241 hour = t->hour;
242 day = t->day;
243 mon = t->mon + 1;
244 year = t->year - atari_rtc_year_offset;
245 wday = t->wday + (t->wday >= 0);
247 if (!(ctrl & RTC_24H)) {
248 if (hour > 11) {
249 pm = 0x80;
250 if (hour != 12)
251 hour -= 12;
253 else if (hour == 0)
254 hour = 12;
257 if (!(ctrl & RTC_DM_BINARY)) {
258 BIN_TO_BCD(sec);
259 BIN_TO_BCD(min);
260 BIN_TO_BCD(hour);
261 BIN_TO_BCD(day);
262 BIN_TO_BCD(mon);
263 BIN_TO_BCD(year);
264 if (wday >= 0) BIN_TO_BCD(wday);
268 /* Reading/writing the clock registers is a bit critical due to
269 * the regular update cycle of the RTC. While an update is in
270 * progress, registers 0..9 shouldn't be touched.
271 * The problem is solved like that: If an update is currently in
272 * progress (the UIP bit is set), the process sleeps for a while
273 * (50ms). This really should be enough, since the update cycle
274 * normally needs 2 ms.
275 * If the UIP bit reads as 0, we have at least 244 usecs until the
276 * update starts. This should be enough... But to be sure,
277 * additionally the RTC_SET bit is set to prevent an update cycle.
280 while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
281 current->state = TASK_INTERRUPTIBLE;
282 schedule_timeout(HWCLK_POLL_INTERVAL);
285 save_flags(flags);
286 cli();
287 RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
288 if (!op) {
289 sec = RTC_READ( RTC_SECONDS );
290 min = RTC_READ( RTC_MINUTES );
291 hour = RTC_READ( RTC_HOURS );
292 day = RTC_READ( RTC_DAY_OF_MONTH );
293 mon = RTC_READ( RTC_MONTH );
294 year = RTC_READ( RTC_YEAR );
295 wday = RTC_READ( RTC_DAY_OF_WEEK );
297 else {
298 RTC_WRITE( RTC_SECONDS, sec );
299 RTC_WRITE( RTC_MINUTES, min );
300 RTC_WRITE( RTC_HOURS, hour + pm);
301 RTC_WRITE( RTC_DAY_OF_MONTH, day );
302 RTC_WRITE( RTC_MONTH, mon );
303 RTC_WRITE( RTC_YEAR, year );
304 if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
306 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
307 restore_flags(flags);
309 if (!op) {
310 /* read: adjust values */
312 if (hour & 0x80) {
313 hour &= ~0x80;
314 pm = 1;
317 if (!(ctrl & RTC_DM_BINARY)) {
318 BCD_TO_BIN(sec);
319 BCD_TO_BIN(min);
320 BCD_TO_BIN(hour);
321 BCD_TO_BIN(day);
322 BCD_TO_BIN(mon);
323 BCD_TO_BIN(year);
324 BCD_TO_BIN(wday);
327 if (!(ctrl & RTC_24H)) {
328 if (!pm && hour == 12)
329 hour = 0;
330 else if (pm && hour != 12)
331 hour += 12;
334 t->sec = sec;
335 t->min = min;
336 t->hour = hour;
337 t->day = day;
338 t->mon = mon - 1;
339 t->year = year + atari_rtc_year_offset;
340 t->wday = wday - 1;
343 return( 0 );
347 int atari_mste_set_clock_mmss (unsigned long nowtime)
349 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
350 struct MSTE_RTC val;
351 unsigned char rtc_minutes;
353 mste_read(&val);
354 rtc_minutes= val.min_ones + val.min_tens * 10;
355 if ((rtc_minutes < real_minutes
356 ? real_minutes - rtc_minutes
357 : rtc_minutes - real_minutes) < 30)
359 val.sec_ones = real_seconds % 10;
360 val.sec_tens = real_seconds / 10;
361 val.min_ones = real_minutes % 10;
362 val.min_tens = real_minutes / 10;
363 mste_write(&val);
365 else
366 return -1;
367 return 0;
370 int atari_tt_set_clock_mmss (unsigned long nowtime)
372 int retval = 0;
373 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
374 unsigned char save_control, save_freq_select, rtc_minutes;
376 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
377 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
379 save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
380 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
382 rtc_minutes = RTC_READ (RTC_MINUTES);
383 if (!(save_control & RTC_DM_BINARY))
384 BCD_TO_BIN (rtc_minutes);
386 /* Since we're only adjusting minutes and seconds, don't interfere
387 with hour overflow. This avoids messing with unknown time zones
388 but requires your RTC not to be off by more than 30 minutes. */
389 if ((rtc_minutes < real_minutes
390 ? real_minutes - rtc_minutes
391 : rtc_minutes - real_minutes) < 30)
393 if (!(save_control & RTC_DM_BINARY))
395 BIN_TO_BCD (real_seconds);
396 BIN_TO_BCD (real_minutes);
398 RTC_WRITE (RTC_SECONDS, real_seconds);
399 RTC_WRITE (RTC_MINUTES, real_minutes);
401 else
402 retval = -1;
404 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
405 RTC_WRITE (RTC_CONTROL, save_control);
406 return retval;
410 * Local variables:
411 * c-indent-level: 4
412 * tab-width: 8
413 * End: