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
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
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 #include <linux/bcd.h>
19 #include <linux/delay.h>
21 #include <asm/atariints.h>
23 DEFINE_SPINLOCK(rtc_lock);
24 EXPORT_SYMBOL_GPL(rtc_lock);
27 atari_sched_init(irq_handler_t timer_routine)
29 /* set Timer C data Register */
30 mfp.tim_dt_c = INT_TICKS;
31 /* start timer C, div = 1:100 */
32 mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
33 /* install interrupt service routine for MFP Timer C */
34 request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
35 "timer", timer_routine);
38 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
40 #define TICK_SIZE 10000
42 /* This is always executed with interrupts disabled. */
43 unsigned long atari_gettimeoffset (void)
45 unsigned long ticks, offset = 0;
47 /* read MFP timer C current value */
49 /* The probability of underflow is less than 2% */
50 if (ticks > INT_TICKS - INT_TICKS / 50)
51 /* Check for pending timer interrupt */
52 if (mfp.int_pn_b & (1 << 5))
55 ticks = INT_TICKS - ticks;
56 ticks = ticks * 10000L / INT_TICKS;
58 return ticks + offset;
62 static void mste_read(struct MSTE_RTC *val)
64 #define COPY(v) val->v=(mste_rtc.v & 0xf)
66 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
67 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
68 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
69 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
71 /* prevent from reading the clock while it changed */
72 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
76 static void mste_write(struct MSTE_RTC *val)
78 #define COPY(v) mste_rtc.v=val->v
80 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
81 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
82 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
83 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
85 /* prevent from writing the clock while it changed */
86 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
90 #define RTC_READ(reg) \
91 ({ unsigned char __val; \
92 (void) atari_writeb(reg,&tt_rtc.regsel); \
93 __val = tt_rtc.data; \
97 #define RTC_WRITE(reg,val) \
99 atari_writeb(reg,&tt_rtc.regsel); \
100 tt_rtc.data = (val); \
104 #define HWCLK_POLL_INTERVAL 5
106 int atari_mste_hwclk( int op, struct rtc_time *t )
112 mste_rtc.mode=(mste_rtc.mode | 1);
113 hr24=mste_rtc.mon_tens & 1;
114 mste_rtc.mode=(mste_rtc.mode & ~1);
117 /* write: prepare values */
119 val.sec_ones = t->tm_sec % 10;
120 val.sec_tens = t->tm_sec / 10;
121 val.min_ones = t->tm_min % 10;
122 val.min_tens = t->tm_min / 10;
127 if (hour == 0 || hour == 20)
130 val.hr_ones = hour % 10;
131 val.hr_tens = hour / 10;
132 val.day_ones = t->tm_mday % 10;
133 val.day_tens = t->tm_mday / 10;
134 val.mon_ones = (t->tm_mon+1) % 10;
135 val.mon_tens = (t->tm_mon+1) / 10;
136 year = t->tm_year - 80;
137 val.year_ones = year % 10;
138 val.year_tens = year / 10;
139 val.weekday = t->tm_wday;
141 mste_rtc.mode=(mste_rtc.mode | 1);
142 val.year_ones = (year % 4); /* leap year register */
143 mste_rtc.mode=(mste_rtc.mode & ~1);
147 t->tm_sec = val.sec_ones + val.sec_tens * 10;
148 t->tm_min = val.min_ones + val.min_tens * 10;
149 hour = val.hr_ones + val.hr_tens * 10;
151 if (hour == 12 || hour == 12 + 20)
157 t->tm_mday = val.day_ones + val.day_tens * 10;
158 t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
159 t->tm_year = val.year_ones + val.year_tens * 10 + 80;
160 t->tm_wday = val.weekday;
165 int atari_tt_hwclk( int op, struct rtc_time *t )
167 int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
172 ctrl = RTC_READ(RTC_CONTROL); /* control registers are
173 * independent from the UIP */
176 /* write: prepare values */
183 year = t->tm_year - atari_rtc_year_offset;
184 wday = t->tm_wday + (t->tm_wday >= 0);
186 if (!(ctrl & RTC_24H)) {
196 if (!(ctrl & RTC_DM_BINARY)) {
199 hour = bin2bcd(hour);
202 year = bin2bcd(year);
204 wday = bin2bcd(wday);
208 /* Reading/writing the clock registers is a bit critical due to
209 * the regular update cycle of the RTC. While an update is in
210 * progress, registers 0..9 shouldn't be touched.
211 * The problem is solved like that: If an update is currently in
212 * progress (the UIP bit is set), the process sleeps for a while
213 * (50ms). This really should be enough, since the update cycle
214 * normally needs 2 ms.
215 * If the UIP bit reads as 0, we have at least 244 usecs until the
216 * update starts. This should be enough... But to be sure,
217 * additionally the RTC_SET bit is set to prevent an update cycle.
220 while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
221 if (in_atomic() || irqs_disabled())
224 schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
227 local_irq_save(flags);
228 RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
230 sec = RTC_READ( RTC_SECONDS );
231 min = RTC_READ( RTC_MINUTES );
232 hour = RTC_READ( RTC_HOURS );
233 day = RTC_READ( RTC_DAY_OF_MONTH );
234 mon = RTC_READ( RTC_MONTH );
235 year = RTC_READ( RTC_YEAR );
236 wday = RTC_READ( RTC_DAY_OF_WEEK );
239 RTC_WRITE( RTC_SECONDS, sec );
240 RTC_WRITE( RTC_MINUTES, min );
241 RTC_WRITE( RTC_HOURS, hour + pm);
242 RTC_WRITE( RTC_DAY_OF_MONTH, day );
243 RTC_WRITE( RTC_MONTH, mon );
244 RTC_WRITE( RTC_YEAR, year );
245 if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
247 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
248 local_irq_restore(flags);
251 /* read: adjust values */
258 if (!(ctrl & RTC_DM_BINARY)) {
261 hour = bcd2bin(hour);
264 year = bcd2bin(year);
265 wday = bcd2bin(wday);
268 if (!(ctrl & RTC_24H)) {
269 if (!pm && hour == 12)
271 else if (pm && hour != 12)
280 t->tm_year = year + atari_rtc_year_offset;
281 t->tm_wday = wday - 1;
288 int atari_mste_set_clock_mmss (unsigned long nowtime)
290 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
292 unsigned char rtc_minutes;
295 rtc_minutes= val.min_ones + val.min_tens * 10;
296 if ((rtc_minutes < real_minutes
297 ? real_minutes - rtc_minutes
298 : rtc_minutes - real_minutes) < 30)
300 val.sec_ones = real_seconds % 10;
301 val.sec_tens = real_seconds / 10;
302 val.min_ones = real_minutes % 10;
303 val.min_tens = real_minutes / 10;
311 int atari_tt_set_clock_mmss (unsigned long nowtime)
314 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
315 unsigned char save_control, save_freq_select, rtc_minutes;
317 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
318 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
320 save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
321 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
323 rtc_minutes = RTC_READ (RTC_MINUTES);
324 if (!(save_control & RTC_DM_BINARY))
325 rtc_minutes = bcd2bin(rtc_minutes);
327 /* Since we're only adjusting minutes and seconds, don't interfere
328 with hour overflow. This avoids messing with unknown time zones
329 but requires your RTC not to be off by more than 30 minutes. */
330 if ((rtc_minutes < real_minutes
331 ? real_minutes - rtc_minutes
332 : rtc_minutes - real_minutes) < 30)
334 if (!(save_control & RTC_DM_BINARY))
336 real_seconds = bin2bcd(real_seconds);
337 real_minutes = bin2bcd(real_minutes);
339 RTC_WRITE (RTC_SECONDS, real_seconds);
340 RTC_WRITE (RTC_MINUTES, real_minutes);
345 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
346 RTC_WRITE (RTC_CONTROL, save_control);