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>
16 #include <linux/interrupt.h>
17 #include <linux/init.h>
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 */
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))
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)
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
) ;
65 /* prevent from reading the clock while it changed */
66 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
70 static void mste_write(struct MSTE_RTC
*val
)
72 #define COPY(v) mste_rtc.v=val->v
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
) ;
79 /* prevent from writing the clock while it changed */
80 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
84 #define RTC_READ(reg) \
85 ({ unsigned char __val; \
86 (void) writeb(reg,&tt_rtc.regsel); \
87 __val = tt_rtc.data; \
91 #define RTC_WRITE(reg,val) \
93 writeb(reg,&tt_rtc.regsel); \
94 tt_rtc.data = (val); \
98 void atari_mste_gettod (int *yearp
, int *monp
, int *dayp
,
99 int *hourp
, int *minp
, int *secp
)
104 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
105 hr24
=mste_rtc
.mon_tens
& 1;
106 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
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;
113 if (hour
== 12 || hour
== 12 + 20)
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
)
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
);
143 ctrl
= RTC_READ(RTC_CONTROL
);
145 if (!(ctrl
& RTC_DM_BINARY
)) {
153 if (!(ctrl
& RTC_24H
)) {
154 if (!pm
&& hour
== 12)
156 else if (pm
&& hour
!= 12)
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
)
173 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
174 hr24
=mste_rtc
.mon_tens
& 1;
175 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
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;
188 if (hour
== 0 || hour
== 20)
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;
198 val
.year_ones
= year
% 10;
199 val
.year_tens
= year
/ 10;
200 val
.weekday
= t
->wday
;
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);
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;
212 if (hour
== 12 || hour
== 12 + 20)
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
;
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;
233 ctrl
= RTC_READ(RTC_CONTROL
); /* control registers are
234 * independent from the UIP */
237 /* write: prepare values */
244 year
= t
->year
- atari_rtc_year_offset
;
245 wday
= t
->wday
+ (t
->wday
>= 0);
247 if (!(ctrl
& RTC_24H
)) {
257 if (!(ctrl
& RTC_DM_BINARY
)) {
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
);
287 RTC_WRITE( RTC_CONTROL
, ctrl
| RTC_SET
);
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
);
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
);
310 /* read: adjust values */
317 if (!(ctrl
& RTC_DM_BINARY
)) {
327 if (!(ctrl
& RTC_24H
)) {
328 if (!pm
&& hour
== 12)
330 else if (pm
&& hour
!= 12)
339 t
->year
= year
+ atari_rtc_year_offset
;
347 int atari_mste_set_clock_mmss (unsigned long nowtime
)
349 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
351 unsigned char rtc_minutes
;
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;
370 int atari_tt_set_clock_mmss (unsigned long nowtime
)
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
);
404 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
);
405 RTC_WRITE (RTC_CONTROL
, save_control
);