PageRenderTime 61ms CodeModel.GetById 11ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/arch/m68k/atari/time.c

https://bitbucket.org/evzijst/gittest
C | 348 lines | 258 code | 45 blank | 45 comment | 48 complexity | 34ff36c99783b9cf4ca1323b9babb9f6 MD5 | raw file
  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#include <linux/bcd.h>
 19
 20#include <asm/atariints.h>
 21
 22void __init
 23atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
 24{
 25    /* set Timer C data Register */
 26    mfp.tim_dt_c = INT_TICKS;
 27    /* start timer C, div = 1:100 */
 28    mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
 29    /* install interrupt service routine for MFP Timer C */
 30    request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
 31                "timer", timer_routine);
 32}
 33
 34/* ++andreas: gettimeoffset fixed to check for pending interrupt */
 35
 36#define TICK_SIZE 10000
 37
 38/* This is always executed with interrupts disabled.  */
 39unsigned long atari_gettimeoffset (void)
 40{
 41  unsigned long ticks, offset = 0;
 42
 43  /* read MFP timer C current value */
 44  ticks = mfp.tim_dt_c;
 45  /* The probability of underflow is less than 2% */
 46  if (ticks > INT_TICKS - INT_TICKS / 50)
 47    /* Check for pending timer interrupt */
 48    if (mfp.int_pn_b & (1 << 5))
 49      offset = TICK_SIZE;
 50
 51  ticks = INT_TICKS - ticks;
 52  ticks = ticks * 10000L / INT_TICKS;
 53
 54  return ticks + offset;
 55}
 56
 57
 58static void mste_read(struct MSTE_RTC *val)
 59{
 60#define COPY(v) val->v=(mste_rtc.v & 0xf)
 61	do {
 62		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
 63		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
 64		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
 65		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
 66		COPY(year_tens) ;
 67	/* prevent from reading the clock while it changed */
 68	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
 69#undef COPY
 70}
 71
 72static void mste_write(struct MSTE_RTC *val)
 73{
 74#define COPY(v) mste_rtc.v=val->v
 75	do {
 76		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
 77		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
 78		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
 79		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
 80		COPY(year_tens) ;
 81	/* prevent from writing the clock while it changed */
 82	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
 83#undef COPY
 84}
 85
 86#define	RTC_READ(reg)				\
 87    ({	unsigned char	__val;			\
 88		(void) atari_writeb(reg,&tt_rtc.regsel);	\
 89		__val = tt_rtc.data;		\
 90		__val;				\
 91	})
 92
 93#define	RTC_WRITE(reg,val)			\
 94    do {					\
 95		atari_writeb(reg,&tt_rtc.regsel);	\
 96		tt_rtc.data = (val);		\
 97	} while(0)
 98
 99
100#define HWCLK_POLL_INTERVAL	5
101
102int atari_mste_hwclk( int op, struct rtc_time *t )
103{
104    int hour, year;
105    int hr24=0;
106    struct MSTE_RTC val;
107
108    mste_rtc.mode=(mste_rtc.mode | 1);
109    hr24=mste_rtc.mon_tens & 1;
110    mste_rtc.mode=(mste_rtc.mode & ~1);
111
112    if (op) {
113        /* write: prepare values */
114
115        val.sec_ones = t->tm_sec % 10;
116        val.sec_tens = t->tm_sec / 10;
117        val.min_ones = t->tm_min % 10;
118        val.min_tens = t->tm_min / 10;
119        hour = t->tm_hour;
120        if (!hr24) {
121	    if (hour > 11)
122		hour += 20 - 12;
123	    if (hour == 0 || hour == 20)
124		hour += 12;
125        }
126        val.hr_ones = hour % 10;
127        val.hr_tens = hour / 10;
128        val.day_ones = t->tm_mday % 10;
129        val.day_tens = t->tm_mday / 10;
130        val.mon_ones = (t->tm_mon+1) % 10;
131        val.mon_tens = (t->tm_mon+1) / 10;
132        year = t->tm_year - 80;
133        val.year_ones = year % 10;
134        val.year_tens = year / 10;
135        val.weekday = t->tm_wday;
136        mste_write(&val);
137        mste_rtc.mode=(mste_rtc.mode | 1);
138        val.year_ones = (year % 4);	/* leap year register */
139        mste_rtc.mode=(mste_rtc.mode & ~1);
140    }
141    else {
142        mste_read(&val);
143        t->tm_sec = val.sec_ones + val.sec_tens * 10;
144        t->tm_min = val.min_ones + val.min_tens * 10;
145        hour = val.hr_ones + val.hr_tens * 10;
146	if (!hr24) {
147	    if (hour == 12 || hour == 12 + 20)
148		hour -= 12;
149	    if (hour >= 20)
150                hour += 12 - 20;
151        }
152	t->tm_hour = hour;
153	t->tm_mday = val.day_ones + val.day_tens * 10;
154        t->tm_mon  = val.mon_ones + val.mon_tens * 10 - 1;
155        t->tm_year = val.year_ones + val.year_tens * 10 + 80;
156        t->tm_wday = val.weekday;
157    }
158    return 0;
159}
160
161int atari_tt_hwclk( int op, struct rtc_time *t )
162{
163    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
164    unsigned long	flags;
165    unsigned char	ctrl;
166    int pm = 0;
167
168    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
169                                   * independent from the UIP */
170
171    if (op) {
172        /* write: prepare values */
173
174        sec  = t->tm_sec;
175        min  = t->tm_min;
176        hour = t->tm_hour;
177        day  = t->tm_mday;
178        mon  = t->tm_mon + 1;
179        year = t->tm_year - atari_rtc_year_offset;
180        wday = t->tm_wday + (t->tm_wday >= 0);
181
182        if (!(ctrl & RTC_24H)) {
183	    if (hour > 11) {
184		pm = 0x80;
185		if (hour != 12)
186		    hour -= 12;
187	    }
188	    else if (hour == 0)
189		hour = 12;
190        }
191
192        if (!(ctrl & RTC_DM_BINARY)) {
193            BIN_TO_BCD(sec);
194            BIN_TO_BCD(min);
195            BIN_TO_BCD(hour);
196            BIN_TO_BCD(day);
197            BIN_TO_BCD(mon);
198            BIN_TO_BCD(year);
199            if (wday >= 0) BIN_TO_BCD(wday);
200        }
201    }
202
203    /* Reading/writing the clock registers is a bit critical due to
204     * the regular update cycle of the RTC. While an update is in
205     * progress, registers 0..9 shouldn't be touched.
206     * The problem is solved like that: If an update is currently in
207     * progress (the UIP bit is set), the process sleeps for a while
208     * (50ms). This really should be enough, since the update cycle
209     * normally needs 2 ms.
210     * If the UIP bit reads as 0, we have at least 244 usecs until the
211     * update starts. This should be enough... But to be sure,
212     * additionally the RTC_SET bit is set to prevent an update cycle.
213     */
214
215    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
216        current->state = TASK_INTERRUPTIBLE;
217        schedule_timeout(HWCLK_POLL_INTERVAL);
218    }
219
220    local_irq_save(flags);
221    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
222    if (!op) {
223        sec  = RTC_READ( RTC_SECONDS );
224        min  = RTC_READ( RTC_MINUTES );
225        hour = RTC_READ( RTC_HOURS );
226        day  = RTC_READ( RTC_DAY_OF_MONTH );
227        mon  = RTC_READ( RTC_MONTH );
228        year = RTC_READ( RTC_YEAR );
229        wday = RTC_READ( RTC_DAY_OF_WEEK );
230    }
231    else {
232        RTC_WRITE( RTC_SECONDS, sec );
233        RTC_WRITE( RTC_MINUTES, min );
234        RTC_WRITE( RTC_HOURS, hour + pm);
235        RTC_WRITE( RTC_DAY_OF_MONTH, day );
236        RTC_WRITE( RTC_MONTH, mon );
237        RTC_WRITE( RTC_YEAR, year );
238        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
239    }
240    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
241    local_irq_restore(flags);
242
243    if (!op) {
244        /* read: adjust values */
245
246        if (hour & 0x80) {
247	    hour &= ~0x80;
248	    pm = 1;
249	}
250
251	if (!(ctrl & RTC_DM_BINARY)) {
252            BCD_TO_BIN(sec);
253            BCD_TO_BIN(min);
254            BCD_TO_BIN(hour);
255            BCD_TO_BIN(day);
256            BCD_TO_BIN(mon);
257            BCD_TO_BIN(year);
258            BCD_TO_BIN(wday);
259        }
260
261        if (!(ctrl & RTC_24H)) {
262	    if (!pm && hour == 12)
263		hour = 0;
264	    else if (pm && hour != 12)
265		hour += 12;
266        }
267
268        t->tm_sec  = sec;
269        t->tm_min  = min;
270        t->tm_hour = hour;
271        t->tm_mday = day;
272        t->tm_mon  = mon - 1;
273        t->tm_year = year + atari_rtc_year_offset;
274        t->tm_wday = wday - 1;
275    }
276
277    return( 0 );
278}
279
280
281int atari_mste_set_clock_mmss (unsigned long nowtime)
282{
283    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
284    struct MSTE_RTC val;
285    unsigned char rtc_minutes;
286
287    mste_read(&val);
288    rtc_minutes= val.min_ones + val.min_tens * 10;
289    if ((rtc_minutes < real_minutes
290         ? real_minutes - rtc_minutes
291         : rtc_minutes - real_minutes) < 30)
292    {
293        val.sec_ones = real_seconds % 10;
294        val.sec_tens = real_seconds / 10;
295        val.min_ones = real_minutes % 10;
296        val.min_tens = real_minutes / 10;
297        mste_write(&val);
298    }
299    else
300        return -1;
301    return 0;
302}
303
304int atari_tt_set_clock_mmss (unsigned long nowtime)
305{
306    int retval = 0;
307    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
308    unsigned char save_control, save_freq_select, rtc_minutes;
309
310    save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
311    RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
312
313    save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
314    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
315
316    rtc_minutes = RTC_READ (RTC_MINUTES);
317    if (!(save_control & RTC_DM_BINARY))
318        BCD_TO_BIN (rtc_minutes);
319
320    /* Since we're only adjusting minutes and seconds, don't interfere
321       with hour overflow.  This avoids messing with unknown time zones
322       but requires your RTC not to be off by more than 30 minutes.  */
323    if ((rtc_minutes < real_minutes
324         ? real_minutes - rtc_minutes
325         : rtc_minutes - real_minutes) < 30)
326        {
327            if (!(save_control & RTC_DM_BINARY))
328                {
329                    BIN_TO_BCD (real_seconds);
330                    BIN_TO_BCD (real_minutes);
331                }
332            RTC_WRITE (RTC_SECONDS, real_seconds);
333            RTC_WRITE (RTC_MINUTES, real_minutes);
334        }
335    else
336        retval = -1;
337
338    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
339    RTC_WRITE (RTC_CONTROL, save_control);
340    return retval;
341}
342
343/*
344 * Local variables:
345 *  c-indent-level: 4
346 *  tab-width: 8
347 * End:
348 */