1 /*
2  * linux/arch/m68k/atari/time.c
3  *
4  * Atari time and real time clock stuff
5  *
6  * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
7  *
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
10  * for more details.
11  */
12 
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 
19 #include <asm/atariints.h>
20 
21 void __init
atari_sched_init(void (* timer_routine)(int,void *,struct pt_regs *))22 atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
23 {
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);
31 }
32 
33 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
34 
35 #define TICK_SIZE 10000
36 
37 /* This is always executed with interrupts disabled.  */
atari_gettimeoffset(void)38 unsigned long atari_gettimeoffset (void)
39 {
40   unsigned long ticks, offset = 0;
41 
42   /* read MFP timer C current value */
43   ticks = mfp.tim_dt_c;
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))
48       offset = TICK_SIZE;
49 
50   ticks = INT_TICKS - ticks;
51   ticks = ticks * 10000L / INT_TICKS;
52 
53   return ticks + offset;
54 }
55 
56 
mste_read(struct MSTE_RTC * val)57 static void mste_read(struct MSTE_RTC *val)
58 {
59 #define COPY(v) val->v=(mste_rtc.v & 0xf)
60 	do {
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) ;
65 		COPY(year_tens) ;
66 	/* prevent from reading the clock while it changed */
67 	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
68 #undef COPY
69 }
70 
mste_write(struct MSTE_RTC * val)71 static void mste_write(struct MSTE_RTC *val)
72 {
73 #define COPY(v) mste_rtc.v=val->v
74 	do {
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) ;
79 		COPY(year_tens) ;
80 	/* prevent from writing the clock while it changed */
81 	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
82 #undef COPY
83 }
84 
85 #define	RTC_READ(reg)				\
86     ({	unsigned char	__val;			\
87 		(void) atari_writeb(reg,&tt_rtc.regsel);	\
88 		__val = tt_rtc.data;		\
89 		__val;				\
90 	})
91 
92 #define	RTC_WRITE(reg,val)			\
93     do {					\
94 		atari_writeb(reg,&tt_rtc.regsel);	\
95 		tt_rtc.data = (val);		\
96 	} while(0)
97 
98 
atari_mste_gettod(int * yearp,int * monp,int * dayp,int * hourp,int * minp,int * secp)99 void atari_mste_gettod (int *yearp, int *monp, int *dayp,
100 			int *hourp, int *minp, int *secp)
101 {
102     int hr24=0, hour;
103     struct MSTE_RTC val;
104 
105     mste_rtc.mode=(mste_rtc.mode | 1);
106     hr24=mste_rtc.mon_tens & 1;
107     mste_rtc.mode=(mste_rtc.mode & ~1);
108 
109     mste_read(&val);
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;
113     if (!hr24) {
114         if (hour == 12 || hour == 12 + 20)
115 	    hour -= 12;
116 	if (hour >= 20)
117 	    hour += 12 - 20;
118     }
119     *hourp = hour;
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;
123 }
124 
125 
atari_tt_gettod(int * yearp,int * monp,int * dayp,int * hourp,int * minp,int * secp)126 void atari_tt_gettod (int *yearp, int *monp, int *dayp,
127 		      int *hourp, int *minp, int *secp)
128 {
129     unsigned char	ctrl;
130     int hour, pm;
131 
132     while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
133     while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
134 
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);
141     pm = hour & 0x80;
142     hour &= ~0x80;
143 
144     ctrl = RTC_READ(RTC_CONTROL);
145 
146     if (!(ctrl & RTC_DM_BINARY)) {
147         BCD_TO_BIN(*secp);
148         BCD_TO_BIN(*minp);
149         BCD_TO_BIN(hour);
150         BCD_TO_BIN(*dayp);
151         BCD_TO_BIN(*monp);
152         BCD_TO_BIN(*yearp);
153     }
154     if (!(ctrl & RTC_24H)) {
155 	if (!pm && hour == 12)
156 	    hour = 0;
157 	else if (pm && hour != 12)
158             hour += 12;
159     }
160     *hourp = hour;
161 
162     /* Adjust values (let the setup valid) */
163     *yearp += atari_rtc_year_offset;
164 }
165 
166 #define HWCLK_POLL_INTERVAL	5
167 
atari_mste_hwclk(int op,struct rtc_time * t)168 int atari_mste_hwclk( int op, struct rtc_time *t )
169 {
170     int hour, year;
171     int hr24=0;
172     struct MSTE_RTC val;
173 
174     mste_rtc.mode=(mste_rtc.mode | 1);
175     hr24=mste_rtc.mon_tens & 1;
176     mste_rtc.mode=(mste_rtc.mode & ~1);
177 
178     if (op) {
179         /* write: prepare values */
180 
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;
185         hour = t->tm_hour;
186         if (!hr24) {
187 	    if (hour > 11)
188 		hour += 20 - 12;
189 	    if (hour == 0 || hour == 20)
190 		hour += 12;
191         }
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;
202         mste_write(&val);
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);
206     }
207     else {
208         mste_read(&val);
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;
212 	if (!hr24) {
213 	    if (hour == 12 || hour == 12 + 20)
214 		hour -= 12;
215 	    if (hour >= 20)
216                 hour += 12 - 20;
217         }
218 	t->tm_hour = hour;
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;
223     }
224     return 0;
225 }
226 
atari_tt_hwclk(int op,struct rtc_time * t)227 int atari_tt_hwclk( int op, struct rtc_time *t )
228 {
229     int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
230     unsigned long 	flags;
231     unsigned char	ctrl;
232     int pm = 0;
233 
234     ctrl = RTC_READ(RTC_CONTROL); /* control registers are
235                                    * independent from the UIP */
236 
237     if (op) {
238         /* write: prepare values */
239 
240         sec  = t->tm_sec;
241         min  = t->tm_min;
242         hour = t->tm_hour;
243         day  = t->tm_mday;
244         mon  = t->tm_mon + 1;
245         year = t->tm_year - atari_rtc_year_offset;
246         wday = t->tm_wday + (t->tm_wday >= 0);
247 
248         if (!(ctrl & RTC_24H)) {
249 	    if (hour > 11) {
250 		pm = 0x80;
251 		if (hour != 12)
252 		    hour -= 12;
253 	    }
254 	    else if (hour == 0)
255 		hour = 12;
256         }
257 
258         if (!(ctrl & RTC_DM_BINARY)) {
259             BIN_TO_BCD(sec);
260             BIN_TO_BCD(min);
261             BIN_TO_BCD(hour);
262             BIN_TO_BCD(day);
263             BIN_TO_BCD(mon);
264             BIN_TO_BCD(year);
265             if (wday >= 0) BIN_TO_BCD(wday);
266         }
267     }
268 
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.
279      */
280 
281     while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
282         current->state = TASK_INTERRUPTIBLE;
283         schedule_timeout(HWCLK_POLL_INTERVAL);
284     }
285 
286     save_flags(flags);
287     cli();
288     RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
289     if (!op) {
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 );
297     }
298     else {
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 );
306     }
307     RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
308     restore_flags(flags);
309 
310     if (!op) {
311         /* read: adjust values */
312 
313         if (hour & 0x80) {
314 	    hour &= ~0x80;
315 	    pm = 1;
316 	}
317 
318 	if (!(ctrl & RTC_DM_BINARY)) {
319             BCD_TO_BIN(sec);
320             BCD_TO_BIN(min);
321             BCD_TO_BIN(hour);
322             BCD_TO_BIN(day);
323             BCD_TO_BIN(mon);
324             BCD_TO_BIN(year);
325             BCD_TO_BIN(wday);
326         }
327 
328         if (!(ctrl & RTC_24H)) {
329 	    if (!pm && hour == 12)
330 		hour = 0;
331 	    else if (pm && hour != 12)
332 		hour += 12;
333         }
334 
335         t->tm_sec  = sec;
336         t->tm_min  = min;
337         t->tm_hour = hour;
338         t->tm_mday = day;
339         t->tm_mon  = mon - 1;
340         t->tm_year = year + atari_rtc_year_offset;
341         t->tm_wday = wday - 1;
342     }
343 
344     return( 0 );
345 }
346 
347 
atari_mste_set_clock_mmss(unsigned long nowtime)348 int atari_mste_set_clock_mmss (unsigned long nowtime)
349 {
350     short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
351     struct MSTE_RTC val;
352     unsigned char rtc_minutes;
353 
354     mste_read(&val);
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)
359     {
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;
364         mste_write(&val);
365     }
366     else
367         return -1;
368     return 0;
369 }
370 
atari_tt_set_clock_mmss(unsigned long nowtime)371 int atari_tt_set_clock_mmss (unsigned long nowtime)
372 {
373     int retval = 0;
374     short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
375     unsigned char save_control, save_freq_select, rtc_minutes;
376 
377     save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
378     RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
379 
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);
382 
383     rtc_minutes = RTC_READ (RTC_MINUTES);
384     if (!(save_control & RTC_DM_BINARY))
385         BCD_TO_BIN (rtc_minutes);
386 
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)
393         {
394             if (!(save_control & RTC_DM_BINARY))
395                 {
396                     BIN_TO_BCD (real_seconds);
397                     BIN_TO_BCD (real_minutes);
398                 }
399             RTC_WRITE (RTC_SECONDS, real_seconds);
400             RTC_WRITE (RTC_MINUTES, real_minutes);
401         }
402     else
403         retval = -1;
404 
405     RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
406     RTC_WRITE (RTC_CONTROL, save_control);
407     return retval;
408 }
409 
410 /*
411  * Local variables:
412  *  c-indent-level: 4
413  *  tab-width: 8
414  * End:
415  */
416