Merge branch 'dev' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[pandora-kernel.git] / arch / m68k / atari / time.c
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 #include <linux/delay.h>
20 #include <linux/export.h>
21
22 #include <asm/atariints.h>
23
24 DEFINE_SPINLOCK(rtc_lock);
25 EXPORT_SYMBOL_GPL(rtc_lock);
26
27 void __init
28 atari_sched_init(irq_handler_t timer_routine)
29 {
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");
38 }
39
40 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
41
42 #define TICK_SIZE 10000
43
44 /* This is always executed with interrupts disabled.  */
45 unsigned long atari_gettimeoffset (void)
46 {
47   unsigned long ticks, offset = 0;
48
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))
55       offset = TICK_SIZE;
56
57   ticks = INT_TICKS - ticks;
58   ticks = ticks * 10000L / INT_TICKS;
59
60   return ticks + offset;
61 }
62
63
64 static void mste_read(struct MSTE_RTC *val)
65 {
66 #define COPY(v) val->v=(mste_rtc.v & 0xf)
67         do {
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) ;
72                 COPY(year_tens) ;
73         /* prevent from reading the clock while it changed */
74         } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
75 #undef COPY
76 }
77
78 static void mste_write(struct MSTE_RTC *val)
79 {
80 #define COPY(v) mste_rtc.v=val->v
81         do {
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) ;
86                 COPY(year_tens) ;
87         /* prevent from writing the clock while it changed */
88         } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
89 #undef COPY
90 }
91
92 #define RTC_READ(reg)                           \
93     ({  unsigned char   __val;                  \
94                 (void) atari_writeb(reg,&tt_rtc.regsel);        \
95                 __val = tt_rtc.data;            \
96                 __val;                          \
97         })
98
99 #define RTC_WRITE(reg,val)                      \
100     do {                                        \
101                 atari_writeb(reg,&tt_rtc.regsel);       \
102                 tt_rtc.data = (val);            \
103         } while(0)
104
105
106 #define HWCLK_POLL_INTERVAL     5
107
108 int atari_mste_hwclk( int op, struct rtc_time *t )
109 {
110     int hour, year;
111     int hr24=0;
112     struct MSTE_RTC val;
113
114     mste_rtc.mode=(mste_rtc.mode | 1);
115     hr24=mste_rtc.mon_tens & 1;
116     mste_rtc.mode=(mste_rtc.mode & ~1);
117
118     if (op) {
119         /* write: prepare values */
120
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;
125         hour = t->tm_hour;
126         if (!hr24) {
127             if (hour > 11)
128                 hour += 20 - 12;
129             if (hour == 0 || hour == 20)
130                 hour += 12;
131         }
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;
142         mste_write(&val);
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);
146     }
147     else {
148         mste_read(&val);
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;
152         if (!hr24) {
153             if (hour == 12 || hour == 12 + 20)
154                 hour -= 12;
155             if (hour >= 20)
156                 hour += 12 - 20;
157         }
158         t->tm_hour = hour;
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;
163     }
164     return 0;
165 }
166
167 int atari_tt_hwclk( int op, struct rtc_time *t )
168 {
169     int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
170     unsigned long       flags;
171     unsigned char       ctrl;
172     int pm = 0;
173
174     ctrl = RTC_READ(RTC_CONTROL); /* control registers are
175                                    * independent from the UIP */
176
177     if (op) {
178         /* write: prepare values */
179
180         sec  = t->tm_sec;
181         min  = t->tm_min;
182         hour = t->tm_hour;
183         day  = t->tm_mday;
184         mon  = t->tm_mon + 1;
185         year = t->tm_year - atari_rtc_year_offset;
186         wday = t->tm_wday + (t->tm_wday >= 0);
187
188         if (!(ctrl & RTC_24H)) {
189             if (hour > 11) {
190                 pm = 0x80;
191                 if (hour != 12)
192                     hour -= 12;
193             }
194             else if (hour == 0)
195                 hour = 12;
196         }
197
198         if (!(ctrl & RTC_DM_BINARY)) {
199             sec = bin2bcd(sec);
200             min = bin2bcd(min);
201             hour = bin2bcd(hour);
202             day = bin2bcd(day);
203             mon = bin2bcd(mon);
204             year = bin2bcd(year);
205             if (wday >= 0)
206                 wday = bin2bcd(wday);
207         }
208     }
209
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.
220      */
221
222     while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
223         if (in_atomic() || irqs_disabled())
224             mdelay(1);
225         else
226             schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
227     }
228
229     local_irq_save(flags);
230     RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
231     if (!op) {
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 );
239     }
240     else {
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 );
248     }
249     RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
250     local_irq_restore(flags);
251
252     if (!op) {
253         /* read: adjust values */
254
255         if (hour & 0x80) {
256             hour &= ~0x80;
257             pm = 1;
258         }
259
260         if (!(ctrl & RTC_DM_BINARY)) {
261             sec = bcd2bin(sec);
262             min = bcd2bin(min);
263             hour = bcd2bin(hour);
264             day = bcd2bin(day);
265             mon = bcd2bin(mon);
266             year = bcd2bin(year);
267             wday = bcd2bin(wday);
268         }
269
270         if (!(ctrl & RTC_24H)) {
271             if (!pm && hour == 12)
272                 hour = 0;
273             else if (pm && hour != 12)
274                 hour += 12;
275         }
276
277         t->tm_sec  = sec;
278         t->tm_min  = min;
279         t->tm_hour = hour;
280         t->tm_mday = day;
281         t->tm_mon  = mon - 1;
282         t->tm_year = year + atari_rtc_year_offset;
283         t->tm_wday = wday - 1;
284     }
285
286     return( 0 );
287 }
288
289
290 int atari_mste_set_clock_mmss (unsigned long nowtime)
291 {
292     short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
293     struct MSTE_RTC val;
294     unsigned char rtc_minutes;
295
296     mste_read(&val);
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)
301     {
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;
306         mste_write(&val);
307     }
308     else
309         return -1;
310     return 0;
311 }
312
313 int atari_tt_set_clock_mmss (unsigned long nowtime)
314 {
315     int retval = 0;
316     short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
317     unsigned char save_control, save_freq_select, rtc_minutes;
318
319     save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
320     RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
321
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);
324
325     rtc_minutes = RTC_READ (RTC_MINUTES);
326     if (!(save_control & RTC_DM_BINARY))
327         rtc_minutes = bcd2bin(rtc_minutes);
328
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)
335         {
336             if (!(save_control & RTC_DM_BINARY))
337                 {
338                     real_seconds = bin2bcd(real_seconds);
339                     real_minutes = bin2bcd(real_minutes);
340                 }
341             RTC_WRITE (RTC_SECONDS, real_seconds);
342             RTC_WRITE (RTC_MINUTES, real_minutes);
343         }
344     else
345         retval = -1;
346
347     RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
348     RTC_WRITE (RTC_CONTROL, save_control);
349     return retval;
350 }
351
352 /*
353  * Local variables:
354  *  c-indent-level: 4
355  *  tab-width: 8
356  * End:
357  */