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>
20 #include <linux/export.h>
22 #include <asm/atariints.h>
24 DEFINE_SPINLOCK(rtc_lock);
25 EXPORT_SYMBOL_GPL(rtc_lock);
27 static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
29 irq_handler_t timer_routine = dev_id;
32 local_irq_save(flags);
33 timer_routine(0, NULL);
34 local_irq_restore(flags);
40 atari_sched_init(irq_handler_t timer_routine)
42 /* set Timer C data Register */
43 st_mfp.tim_dt_c = INT_TICKS;
44 /* start timer C, div = 1:100 */
45 st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
46 /* install interrupt service routine for MFP Timer C */
47 if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer",
49 pr_err("Couldn't register timer interrupt\n");
52 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
54 #define TICK_SIZE 10000
56 /* This is always executed with interrupts disabled. */
57 u32 atari_gettimeoffset(void)
59 u32 ticks, offset = 0;
61 /* read MFP timer C current value */
62 ticks = st_mfp.tim_dt_c;
63 /* The probability of underflow is less than 2% */
64 if (ticks > INT_TICKS - INT_TICKS / 50)
65 /* Check for pending timer interrupt */
66 if (st_mfp.int_pn_b & (1 << 5))
69 ticks = INT_TICKS - ticks;
70 ticks = ticks * 10000L / INT_TICKS;
72 return (ticks + offset) * 1000;
76 static void mste_read(struct MSTE_RTC *val)
78 #define COPY(v) val->v=(mste_rtc.v & 0xf)
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 reading the clock while it changed */
86 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
90 static void mste_write(struct MSTE_RTC *val)
92 #define COPY(v) mste_rtc.v=val->v
94 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
95 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
96 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
97 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
99 /* prevent from writing the clock while it changed */
100 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
104 #define RTC_READ(reg) \
105 ({ unsigned char __val; \
106 (void) atari_writeb(reg,&tt_rtc.regsel); \
107 __val = tt_rtc.data; \
111 #define RTC_WRITE(reg,val) \
113 atari_writeb(reg,&tt_rtc.regsel); \
114 tt_rtc.data = (val); \
118 #define HWCLK_POLL_INTERVAL 5
120 int atari_mste_hwclk( int op, struct rtc_time *t )
126 mste_rtc.mode=(mste_rtc.mode | 1);
127 hr24=mste_rtc.mon_tens & 1;
128 mste_rtc.mode=(mste_rtc.mode & ~1);
131 /* write: prepare values */
133 val.sec_ones = t->tm_sec % 10;
134 val.sec_tens = t->tm_sec / 10;
135 val.min_ones = t->tm_min % 10;
136 val.min_tens = t->tm_min / 10;
141 if (hour == 0 || hour == 20)
144 val.hr_ones = hour % 10;
145 val.hr_tens = hour / 10;
146 val.day_ones = t->tm_mday % 10;
147 val.day_tens = t->tm_mday / 10;
148 val.mon_ones = (t->tm_mon+1) % 10;
149 val.mon_tens = (t->tm_mon+1) / 10;
150 year = t->tm_year - 80;
151 val.year_ones = year % 10;
152 val.year_tens = year / 10;
153 val.weekday = t->tm_wday;
155 mste_rtc.mode=(mste_rtc.mode | 1);
156 val.year_ones = (year % 4); /* leap year register */
157 mste_rtc.mode=(mste_rtc.mode & ~1);
161 t->tm_sec = val.sec_ones + val.sec_tens * 10;
162 t->tm_min = val.min_ones + val.min_tens * 10;
163 hour = val.hr_ones + val.hr_tens * 10;
165 if (hour == 12 || hour == 12 + 20)
171 t->tm_mday = val.day_ones + val.day_tens * 10;
172 t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
173 t->tm_year = val.year_ones + val.year_tens * 10 + 80;
174 t->tm_wday = val.weekday;
179 int atari_tt_hwclk( int op, struct rtc_time *t )
181 int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
186 ctrl = RTC_READ(RTC_CONTROL); /* control registers are
187 * independent from the UIP */
190 /* write: prepare values */
197 year = t->tm_year - atari_rtc_year_offset;
198 wday = t->tm_wday + (t->tm_wday >= 0);
200 if (!(ctrl & RTC_24H)) {
210 if (!(ctrl & RTC_DM_BINARY)) {
213 hour = bin2bcd(hour);
216 year = bin2bcd(year);
218 wday = bin2bcd(wday);
222 /* Reading/writing the clock registers is a bit critical due to
223 * the regular update cycle of the RTC. While an update is in
224 * progress, registers 0..9 shouldn't be touched.
225 * The problem is solved like that: If an update is currently in
226 * progress (the UIP bit is set), the process sleeps for a while
227 * (50ms). This really should be enough, since the update cycle
228 * normally needs 2 ms.
229 * If the UIP bit reads as 0, we have at least 244 usecs until the
230 * update starts. This should be enough... But to be sure,
231 * additionally the RTC_SET bit is set to prevent an update cycle.
234 while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
235 if (in_atomic() || irqs_disabled())
238 schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
241 local_irq_save(flags);
242 RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
244 sec = RTC_READ( RTC_SECONDS );
245 min = RTC_READ( RTC_MINUTES );
246 hour = RTC_READ( RTC_HOURS );
247 day = RTC_READ( RTC_DAY_OF_MONTH );
248 mon = RTC_READ( RTC_MONTH );
249 year = RTC_READ( RTC_YEAR );
250 wday = RTC_READ( RTC_DAY_OF_WEEK );
253 RTC_WRITE( RTC_SECONDS, sec );
254 RTC_WRITE( RTC_MINUTES, min );
255 RTC_WRITE( RTC_HOURS, hour + pm);
256 RTC_WRITE( RTC_DAY_OF_MONTH, day );
257 RTC_WRITE( RTC_MONTH, mon );
258 RTC_WRITE( RTC_YEAR, year );
259 if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
261 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
262 local_irq_restore(flags);
265 /* read: adjust values */
272 if (!(ctrl & RTC_DM_BINARY)) {
275 hour = bcd2bin(hour);
278 year = bcd2bin(year);
279 wday = bcd2bin(wday);
282 if (!(ctrl & RTC_24H)) {
283 if (!pm && hour == 12)
285 else if (pm && hour != 12)
294 t->tm_year = year + atari_rtc_year_offset;
295 t->tm_wday = wday - 1;
302 int atari_mste_set_clock_mmss (unsigned long nowtime)
304 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
306 unsigned char rtc_minutes;
309 rtc_minutes= val.min_ones + val.min_tens * 10;
310 if ((rtc_minutes < real_minutes
311 ? real_minutes - rtc_minutes
312 : rtc_minutes - real_minutes) < 30)
314 val.sec_ones = real_seconds % 10;
315 val.sec_tens = real_seconds / 10;
316 val.min_ones = real_minutes % 10;
317 val.min_tens = real_minutes / 10;
325 int atari_tt_set_clock_mmss (unsigned long nowtime)
328 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
329 unsigned char save_control, save_freq_select, rtc_minutes;
331 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
332 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
334 save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
335 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
337 rtc_minutes = RTC_READ (RTC_MINUTES);
338 if (!(save_control & RTC_DM_BINARY))
339 rtc_minutes = bcd2bin(rtc_minutes);
341 /* Since we're only adjusting minutes and seconds, don't interfere
342 with hour overflow. This avoids messing with unknown time zones
343 but requires your RTC not to be off by more than 30 minutes. */
344 if ((rtc_minutes < real_minutes
345 ? real_minutes - rtc_minutes
346 : rtc_minutes - real_minutes) < 30)
348 if (!(save_control & RTC_DM_BINARY))
350 real_seconds = bin2bcd(real_seconds);
351 real_minutes = bin2bcd(real_minutes);
353 RTC_WRITE (RTC_SECONDS, real_seconds);
354 RTC_WRITE (RTC_MINUTES, real_minutes);
359 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
360 RTC_WRITE (RTC_CONTROL, save_control);