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 if (request_irq(IRQ_MFP_TIMC
, timer_routine
, IRQ_TYPE_SLOW
,
35 "timer", timer_routine
))
36 pr_err("Couldn't register timer interrupt\n");
39 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
41 #define TICK_SIZE 10000
43 /* This is always executed with interrupts disabled. */
44 unsigned long atari_gettimeoffset (void)
46 unsigned long ticks
, offset
= 0;
48 /* read MFP timer C current value */
50 /* The probability of underflow is less than 2% */
51 if (ticks
> INT_TICKS
- INT_TICKS
/ 50)
52 /* Check for pending timer interrupt */
53 if (mfp
.int_pn_b
& (1 << 5))
56 ticks
= INT_TICKS
- ticks
;
57 ticks
= ticks
* 10000L / INT_TICKS
;
59 return ticks
+ offset
;
63 static void mste_read(struct MSTE_RTC
*val
)
65 #define COPY(v) val->v=(mste_rtc.v & 0xf)
67 COPY(sec_ones
) ; COPY(sec_tens
) ; COPY(min_ones
) ;
68 COPY(min_tens
) ; COPY(hr_ones
) ; COPY(hr_tens
) ;
69 COPY(weekday
) ; COPY(day_ones
) ; COPY(day_tens
) ;
70 COPY(mon_ones
) ; COPY(mon_tens
) ; COPY(year_ones
) ;
72 /* prevent from reading the clock while it changed */
73 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
77 static void mste_write(struct MSTE_RTC
*val
)
79 #define COPY(v) mste_rtc.v=val->v
81 COPY(sec_ones
) ; COPY(sec_tens
) ; COPY(min_ones
) ;
82 COPY(min_tens
) ; COPY(hr_ones
) ; COPY(hr_tens
) ;
83 COPY(weekday
) ; COPY(day_ones
) ; COPY(day_tens
) ;
84 COPY(mon_ones
) ; COPY(mon_tens
) ; COPY(year_ones
) ;
86 /* prevent from writing the clock while it changed */
87 } while (val
->sec_ones
!= (mste_rtc
.sec_ones
& 0xf));
91 #define RTC_READ(reg) \
92 ({ unsigned char __val; \
93 (void) atari_writeb(reg,&tt_rtc.regsel); \
94 __val = tt_rtc.data; \
98 #define RTC_WRITE(reg,val) \
100 atari_writeb(reg,&tt_rtc.regsel); \
101 tt_rtc.data = (val); \
105 #define HWCLK_POLL_INTERVAL 5
107 int atari_mste_hwclk( int op
, struct rtc_time
*t
)
113 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
114 hr24
=mste_rtc
.mon_tens
& 1;
115 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
118 /* write: prepare values */
120 val
.sec_ones
= t
->tm_sec
% 10;
121 val
.sec_tens
= t
->tm_sec
/ 10;
122 val
.min_ones
= t
->tm_min
% 10;
123 val
.min_tens
= t
->tm_min
/ 10;
128 if (hour
== 0 || hour
== 20)
131 val
.hr_ones
= hour
% 10;
132 val
.hr_tens
= hour
/ 10;
133 val
.day_ones
= t
->tm_mday
% 10;
134 val
.day_tens
= t
->tm_mday
/ 10;
135 val
.mon_ones
= (t
->tm_mon
+1) % 10;
136 val
.mon_tens
= (t
->tm_mon
+1) / 10;
137 year
= t
->tm_year
- 80;
138 val
.year_ones
= year
% 10;
139 val
.year_tens
= year
/ 10;
140 val
.weekday
= t
->tm_wday
;
142 mste_rtc
.mode
=(mste_rtc
.mode
| 1);
143 val
.year_ones
= (year
% 4); /* leap year register */
144 mste_rtc
.mode
=(mste_rtc
.mode
& ~1);
148 t
->tm_sec
= val
.sec_ones
+ val
.sec_tens
* 10;
149 t
->tm_min
= val
.min_ones
+ val
.min_tens
* 10;
150 hour
= val
.hr_ones
+ val
.hr_tens
* 10;
152 if (hour
== 12 || hour
== 12 + 20)
158 t
->tm_mday
= val
.day_ones
+ val
.day_tens
* 10;
159 t
->tm_mon
= val
.mon_ones
+ val
.mon_tens
* 10 - 1;
160 t
->tm_year
= val
.year_ones
+ val
.year_tens
* 10 + 80;
161 t
->tm_wday
= val
.weekday
;
166 int atari_tt_hwclk( int op
, struct rtc_time
*t
)
168 int sec
=0, min
=0, hour
=0, day
=0, mon
=0, year
=0, wday
=0;
173 ctrl
= RTC_READ(RTC_CONTROL
); /* control registers are
174 * independent from the UIP */
177 /* write: prepare values */
184 year
= t
->tm_year
- atari_rtc_year_offset
;
185 wday
= t
->tm_wday
+ (t
->tm_wday
>= 0);
187 if (!(ctrl
& RTC_24H
)) {
197 if (!(ctrl
& RTC_DM_BINARY
)) {
200 hour
= bin2bcd(hour
);
203 year
= bin2bcd(year
);
205 wday
= bin2bcd(wday
);
209 /* Reading/writing the clock registers is a bit critical due to
210 * the regular update cycle of the RTC. While an update is in
211 * progress, registers 0..9 shouldn't be touched.
212 * The problem is solved like that: If an update is currently in
213 * progress (the UIP bit is set), the process sleeps for a while
214 * (50ms). This really should be enough, since the update cycle
215 * normally needs 2 ms.
216 * If the UIP bit reads as 0, we have at least 244 usecs until the
217 * update starts. This should be enough... But to be sure,
218 * additionally the RTC_SET bit is set to prevent an update cycle.
221 while( RTC_READ(RTC_FREQ_SELECT
) & RTC_UIP
) {
222 if (in_atomic() || irqs_disabled())
225 schedule_timeout_interruptible(HWCLK_POLL_INTERVAL
);
228 local_irq_save(flags
);
229 RTC_WRITE( RTC_CONTROL
, ctrl
| RTC_SET
);
231 sec
= RTC_READ( RTC_SECONDS
);
232 min
= RTC_READ( RTC_MINUTES
);
233 hour
= RTC_READ( RTC_HOURS
);
234 day
= RTC_READ( RTC_DAY_OF_MONTH
);
235 mon
= RTC_READ( RTC_MONTH
);
236 year
= RTC_READ( RTC_YEAR
);
237 wday
= RTC_READ( RTC_DAY_OF_WEEK
);
240 RTC_WRITE( RTC_SECONDS
, sec
);
241 RTC_WRITE( RTC_MINUTES
, min
);
242 RTC_WRITE( RTC_HOURS
, hour
+ pm
);
243 RTC_WRITE( RTC_DAY_OF_MONTH
, day
);
244 RTC_WRITE( RTC_MONTH
, mon
);
245 RTC_WRITE( RTC_YEAR
, year
);
246 if (wday
>= 0) RTC_WRITE( RTC_DAY_OF_WEEK
, wday
);
248 RTC_WRITE( RTC_CONTROL
, ctrl
& ~RTC_SET
);
249 local_irq_restore(flags
);
252 /* read: adjust values */
259 if (!(ctrl
& RTC_DM_BINARY
)) {
262 hour
= bcd2bin(hour
);
265 year
= bcd2bin(year
);
266 wday
= bcd2bin(wday
);
269 if (!(ctrl
& RTC_24H
)) {
270 if (!pm
&& hour
== 12)
272 else if (pm
&& hour
!= 12)
281 t
->tm_year
= year
+ atari_rtc_year_offset
;
282 t
->tm_wday
= wday
- 1;
289 int atari_mste_set_clock_mmss (unsigned long nowtime
)
291 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
293 unsigned char rtc_minutes
;
296 rtc_minutes
= val
.min_ones
+ val
.min_tens
* 10;
297 if ((rtc_minutes
< real_minutes
298 ? real_minutes
- rtc_minutes
299 : rtc_minutes
- real_minutes
) < 30)
301 val
.sec_ones
= real_seconds
% 10;
302 val
.sec_tens
= real_seconds
/ 10;
303 val
.min_ones
= real_minutes
% 10;
304 val
.min_tens
= real_minutes
/ 10;
312 int atari_tt_set_clock_mmss (unsigned long nowtime
)
315 short real_seconds
= nowtime
% 60, real_minutes
= (nowtime
/ 60) % 60;
316 unsigned char save_control
, save_freq_select
, rtc_minutes
;
318 save_control
= RTC_READ (RTC_CONTROL
); /* tell the clock it's being set */
319 RTC_WRITE (RTC_CONTROL
, save_control
| RTC_SET
);
321 save_freq_select
= RTC_READ (RTC_FREQ_SELECT
); /* stop and reset prescaler */
322 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
| RTC_DIV_RESET2
);
324 rtc_minutes
= RTC_READ (RTC_MINUTES
);
325 if (!(save_control
& RTC_DM_BINARY
))
326 rtc_minutes
= bcd2bin(rtc_minutes
);
328 /* Since we're only adjusting minutes and seconds, don't interfere
329 with hour overflow. This avoids messing with unknown time zones
330 but requires your RTC not to be off by more than 30 minutes. */
331 if ((rtc_minutes
< real_minutes
332 ? real_minutes
- rtc_minutes
333 : rtc_minutes
- real_minutes
) < 30)
335 if (!(save_control
& RTC_DM_BINARY
))
337 real_seconds
= bin2bcd(real_seconds
);
338 real_minutes
= bin2bcd(real_minutes
);
340 RTC_WRITE (RTC_SECONDS
, real_seconds
);
341 RTC_WRITE (RTC_MINUTES
, real_minutes
);
346 RTC_WRITE (RTC_FREQ_SELECT
, save_freq_select
);
347 RTC_WRITE (RTC_CONTROL
, save_control
);