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>
19 #include <asm/atariints.h>
22 atari_sched_init(void (*timer_routine
)(int, void *, struct pt_regs
*))
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
);
33 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
35 #define TICK_SIZE 10000
37 /* This is always executed with interrupts disabled. */
38 unsigned long atari_gettimeoffset (void)
40 unsigned long ticks
, offset
= 0;
42 /* read MFP timer C current value */
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))
50 ticks
= INT_TICKS
- ticks
;
51 ticks
= ticks
* 10000L / INT_TICKS
;
53 return ticks
+ offset
;
57 static void mste_read(struct MSTE_RTC
*val
)
59 #define COPY(v) val->v=(mste_rtc.v & 0xf)
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
) ;
66 /* prevent from reading the clock while it changed */
67 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
71 static void mste_write(struct MSTE_RTC
*val
)
73 #define COPY(v) mste_rtc.v=val->v
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
) ;
80 /* prevent from writing the clock while it changed */
81 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
85 #define RTC_READ(reg) \
86 ({ unsigned char __val; \
87 (void) atari_writeb(reg,&tt_rtc.regsel); \
88 __val = tt_rtc.data; \
92 #define RTC_WRITE(reg,val) \
94 atari_writeb(reg,&tt_rtc.regsel); \
95 tt_rtc.data = (val); \
99 void atari_mste_gettod (int *yearp
, int *monp
, int *dayp
,
100 int *hourp
, int *minp
, int *secp
)
105 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
106 hr24
=mste_rtc
.mon_tens
& 1;
107 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
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;
114 if (hour
== 12 || hour
== 12 + 20)
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;
126 void atari_tt_gettod (int *yearp
, int *monp
, int *dayp
,
127 int *hourp
, int *minp
, int *secp
)
132 while (!(RTC_READ(RTC_FREQ_SELECT
) & RTC_UIP
)) ;
133 while (RTC_READ(RTC_FREQ_SELECT
) & RTC_UIP
) ;
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
);
144 ctrl
= RTC_READ(RTC_CONTROL
);
146 if (!(ctrl
& RTC_DM_BINARY
)) {
154 if (!(ctrl
& RTC_24H
)) {
155 if (!pm
&& hour
== 12)
157 else if (pm
&& hour
!= 12)
162 /* Adjust values (let the setup valid) */
163 *yearp
+= atari_rtc_year_offset
;
166 #define HWCLK_POLL_INTERVAL 5
168 int atari_mste_hwclk( int op
, struct rtc_time
*t
)
174 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
175 hr24
=mste_rtc
.mon_tens
& 1;
176 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
179 /* write: prepare values */
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;
189 if (hour
== 0 || hour
== 20)
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
;
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);
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;
213 if (hour
== 12 || hour
== 12 + 20)
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
;
227 int atari_tt_hwclk( int op
, struct rtc_time
*t
)
229 int sec
=0, min
=0, hour
=0, day
=0, mon
=0, year
=0, wday
=0;
234 ctrl
= RTC_READ(RTC_CONTROL
); /* control registers are
235 * independent from the UIP */
238 /* write: prepare values */
245 year
= t
->tm_year
- atari_rtc_year_offset
;
246 wday
= t
->tm_wday
+ (t
->tm_wday
>= 0);
248 if (!(ctrl
& RTC_24H
)) {
258 if (!(ctrl
& RTC_DM_BINARY
)) {
265 if (wday
>= 0) BIN_TO_BCD(wday
);
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.
281 while( RTC_READ(RTC_FREQ_SELECT
) & RTC_UIP
) {
282 current
->state
= TASK_INTERRUPTIBLE
;
283 schedule_timeout(HWCLK_POLL_INTERVAL
);
288 RTC_WRITE( RTC_CONTROL
, ctrl
| RTC_SET
);
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
);
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
);
307 RTC_WRITE( RTC_CONTROL
, ctrl
& ~RTC_SET
);
308 restore_flags(flags
);
311 /* read: adjust values */
318 if (!(ctrl
& RTC_DM_BINARY
)) {
328 if (!(ctrl
& RTC_24H
)) {
329 if (!pm
&& hour
== 12)
331 else if (pm
&& hour
!= 12)
340 t
->tm_year
= year
+ atari_rtc_year_offset
;
341 t
->tm_wday
= wday
- 1;
348 int atari_mste_set_clock_mmss (unsigned long nowtime
)
350 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
352 unsigned char rtc_minutes
;
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)
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;
371 int atari_tt_set_clock_mmss (unsigned long nowtime
)
374 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
375 unsigned char save_control
, save_freq_select
, rtc_minutes
;
377 save_control
= RTC_READ (RTC_CONTROL
); /* tell the clock it's being set */
378 RTC_WRITE (RTC_CONTROL
, save_control
| RTC_SET
);
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
);
383 rtc_minutes
= RTC_READ (RTC_MINUTES
);
384 if (!(save_control
& RTC_DM_BINARY
))
385 BCD_TO_BIN (rtc_minutes
);
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)
394 if (!(save_control
& RTC_DM_BINARY
))
396 BIN_TO_BCD (real_seconds
);
397 BIN_TO_BCD (real_minutes
);
399 RTC_WRITE (RTC_SECONDS
, real_seconds
);
400 RTC_WRITE (RTC_MINUTES
, real_minutes
);
405 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
);
406 RTC_WRITE (RTC_CONTROL
, save_control
);