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
);
28 atari_sched_init(irq_handler_t timer_routine
)
30 /* set Timer C data Register */
31 st_mfp
.tim_dt_c
= INT_TICKS
;
32 /* start timer C, div = 1:100 */
33 st_mfp
.tim_ct_cd
= (st_mfp
.tim_ct_cd
& 15) | 0x60;
34 /* install interrupt service routine for MFP Timer C */
35 if (request_irq(IRQ_MFP_TIMC
, timer_routine
, IRQ_TYPE_SLOW
,
36 "timer", timer_routine
))
37 pr_err("Couldn't register timer interrupt\n");
40 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
42 #define TICK_SIZE 10000
44 /* This is always executed with interrupts disabled. */
45 unsigned long atari_gettimeoffset (void)
47 unsigned long ticks
, offset
= 0;
49 /* read MFP timer C current value */
50 ticks
= st_mfp
.tim_dt_c
;
51 /* The probability of underflow is less than 2% */
52 if (ticks
> INT_TICKS
- INT_TICKS
/ 50)
53 /* Check for pending timer interrupt */
54 if (st_mfp
.int_pn_b
& (1 << 5))
57 ticks
= INT_TICKS
- ticks
;
58 ticks
= ticks
* 10000L / INT_TICKS
;
60 return ticks
+ offset
;
64 static void mste_read(struct MSTE_RTC
*val
)
66 #define COPY(v) val->v=(mste_rtc.v & 0xf)
68 COPY(sec_ones
) ; COPY(sec_tens
) ; COPY(min_ones
) ;
69 COPY(min_tens
) ; COPY(hr_ones
) ; COPY(hr_tens
) ;
70 COPY(weekday
) ; COPY(day_ones
) ; COPY(day_tens
) ;
71 COPY(mon_ones
) ; COPY(mon_tens
) ; COPY(year_ones
) ;
73 /* prevent from reading the clock while it changed */
74 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
78 static void mste_write(struct MSTE_RTC
*val
)
80 #define COPY(v) mste_rtc.v=val->v
82 COPY(sec_ones
) ; COPY(sec_tens
) ; COPY(min_ones
) ;
83 COPY(min_tens
) ; COPY(hr_ones
) ; COPY(hr_tens
) ;
84 COPY(weekday
) ; COPY(day_ones
) ; COPY(day_tens
) ;
85 COPY(mon_ones
) ; COPY(mon_tens
) ; COPY(year_ones
) ;
87 /* prevent from writing the clock while it changed */
88 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
92 #define RTC_READ(reg) \
93 ({ unsigned char __val; \
94 (void) atari_writeb(reg,&tt_rtc.regsel); \
95 __val = tt_rtc.data; \
99 #define RTC_WRITE(reg,val) \
101 atari_writeb(reg,&tt_rtc.regsel); \
102 tt_rtc.data = (val); \
106 #define HWCLK_POLL_INTERVAL 5
108 int atari_mste_hwclk( int op
, struct rtc_time
*t
)
114 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
115 hr24
=mste_rtc
.mon_tens
& 1;
116 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
119 /* write: prepare values */
121 val
.sec_ones
= t
->tm_sec
% 10;
122 val
.sec_tens
= t
->tm_sec
/ 10;
123 val
.min_ones
= t
->tm_min
% 10;
124 val
.min_tens
= t
->tm_min
/ 10;
129 if (hour
== 0 || hour
== 20)
132 val
.hr_ones
= hour
% 10;
133 val
.hr_tens
= hour
/ 10;
134 val
.day_ones
= t
->tm_mday
% 10;
135 val
.day_tens
= t
->tm_mday
/ 10;
136 val
.mon_ones
= (t
->tm_mon
+1) % 10;
137 val
.mon_tens
= (t
->tm_mon
+1) / 10;
138 year
= t
->tm_year
- 80;
139 val
.year_ones
= year
% 10;
140 val
.year_tens
= year
/ 10;
141 val
.weekday
= t
->tm_wday
;
143 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
144 val
.year_ones
= (year
% 4); /* leap year register */
145 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
149 t
->tm_sec
= val
.sec_ones
+ val
.sec_tens
* 10;
150 t
->tm_min
= val
.min_ones
+ val
.min_tens
* 10;
151 hour
= val
.hr_ones
+ val
.hr_tens
* 10;
153 if (hour
== 12 || hour
== 12 + 20)
159 t
->tm_mday
= val
.day_ones
+ val
.day_tens
* 10;
160 t
->tm_mon
= val
.mon_ones
+ val
.mon_tens
* 10 - 1;
161 t
->tm_year
= val
.year_ones
+ val
.year_tens
* 10 + 80;
162 t
->tm_wday
= val
.weekday
;
167 int atari_tt_hwclk( int op
, struct rtc_time
*t
)
169 int sec
=0, min
=0, hour
=0, day
=0, mon
=0, year
=0, wday
=0;
174 ctrl
= RTC_READ(RTC_CONTROL
); /* control registers are
175 * independent from the UIP */
178 /* write: prepare values */
185 year
= t
->tm_year
- atari_rtc_year_offset
;
186 wday
= t
->tm_wday
+ (t
->tm_wday
>= 0);
188 if (!(ctrl
& RTC_24H
)) {
198 if (!(ctrl
& RTC_DM_BINARY
)) {
201 hour
= bin2bcd(hour
);
204 year
= bin2bcd(year
);
206 wday
= bin2bcd(wday
);
210 /* Reading/writing the clock registers is a bit critical due to
211 * the regular update cycle of the RTC. While an update is in
212 * progress, registers 0..9 shouldn't be touched.
213 * The problem is solved like that: If an update is currently in
214 * progress (the UIP bit is set), the process sleeps for a while
215 * (50ms). This really should be enough, since the update cycle
216 * normally needs 2 ms.
217 * If the UIP bit reads as 0, we have at least 244 usecs until the
218 * update starts. This should be enough... But to be sure,
219 * additionally the RTC_SET bit is set to prevent an update cycle.
222 while( RTC_READ(RTC_FREQ_SELECT
) & RTC_UIP
) {
223 if (in_atomic() || irqs_disabled())
226 schedule_timeout_interruptible(HWCLK_POLL_INTERVAL
);
229 local_irq_save(flags
);
230 RTC_WRITE( RTC_CONTROL
, ctrl
| RTC_SET
);
232 sec
= RTC_READ( RTC_SECONDS
);
233 min
= RTC_READ( RTC_MINUTES
);
234 hour
= RTC_READ( RTC_HOURS
);
235 day
= RTC_READ( RTC_DAY_OF_MONTH
);
236 mon
= RTC_READ( RTC_MONTH
);
237 year
= RTC_READ( RTC_YEAR
);
238 wday
= RTC_READ( RTC_DAY_OF_WEEK
);
241 RTC_WRITE( RTC_SECONDS
, sec
);
242 RTC_WRITE( RTC_MINUTES
, min
);
243 RTC_WRITE( RTC_HOURS
, hour
+ pm
);
244 RTC_WRITE( RTC_DAY_OF_MONTH
, day
);
245 RTC_WRITE( RTC_MONTH
, mon
);
246 RTC_WRITE( RTC_YEAR
, year
);
247 if (wday
>= 0) RTC_WRITE( RTC_DAY_OF_WEEK
, wday
);
249 RTC_WRITE( RTC_CONTROL
, ctrl
& ~RTC_SET
);
250 local_irq_restore(flags
);
253 /* read: adjust values */
260 if (!(ctrl
& RTC_DM_BINARY
)) {
263 hour
= bcd2bin(hour
);
266 year
= bcd2bin(year
);
267 wday
= bcd2bin(wday
);
270 if (!(ctrl
& RTC_24H
)) {
271 if (!pm
&& hour
== 12)
273 else if (pm
&& hour
!= 12)
282 t
->tm_year
= year
+ atari_rtc_year_offset
;
283 t
->tm_wday
= wday
- 1;
290 int atari_mste_set_clock_mmss (unsigned long nowtime
)
292 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
294 unsigned char rtc_minutes
;
297 rtc_minutes
= val
.min_ones
+ val
.min_tens
* 10;
298 if ((rtc_minutes
< real_minutes
299 ? real_minutes
- rtc_minutes
300 : rtc_minutes
- real_minutes
) < 30)
302 val
.sec_ones
= real_seconds
% 10;
303 val
.sec_tens
= real_seconds
/ 10;
304 val
.min_ones
= real_minutes
% 10;
305 val
.min_tens
= real_minutes
/ 10;
313 int atari_tt_set_clock_mmss (unsigned long nowtime
)
316 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
317 unsigned char save_control
, save_freq_select
, rtc_minutes
;
319 save_control
= RTC_READ (RTC_CONTROL
); /* tell the clock it's being set */
320 RTC_WRITE (RTC_CONTROL
, save_control
| RTC_SET
);
322 save_freq_select
= RTC_READ (RTC_FREQ_SELECT
); /* stop and reset prescaler */
323 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
| RTC_DIV_RESET2
);
325 rtc_minutes
= RTC_READ (RTC_MINUTES
);
326 if (!(save_control
& RTC_DM_BINARY
))
327 rtc_minutes
= bcd2bin(rtc_minutes
);
329 /* Since we're only adjusting minutes and seconds, don't interfere
330 with hour overflow. This avoids messing with unknown time zones
331 but requires your RTC not to be off by more than 30 minutes. */
332 if ((rtc_minutes
< real_minutes
333 ? real_minutes
- rtc_minutes
334 : rtc_minutes
- real_minutes
) < 30)
336 if (!(save_control
& RTC_DM_BINARY
))
338 real_seconds
= bin2bcd(real_seconds
);
339 real_minutes
= bin2bcd(real_minutes
);
341 RTC_WRITE (RTC_SECONDS
, real_seconds
);
342 RTC_WRITE (RTC_MINUTES
, real_minutes
);
347 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
);
348 RTC_WRITE (RTC_CONTROL
, save_control
);