airport: remove useless return in a function returning void
[linux/fpc-iii.git] / arch / m68k / atari / time.c
blob1edde27fa32dbb600dd5d07822cfd0bb5281b992
1 /*
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
10 * for more details.
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);
26 void __init
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 request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
35 "timer", timer_routine);
38 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
40 #define TICK_SIZE 10000
42 /* This is always executed with interrupts disabled. */
43 unsigned long atari_gettimeoffset (void)
45 unsigned long ticks, offset = 0;
47 /* read MFP timer C current value */
48 ticks = mfp.tim_dt_c;
49 /* The probability of underflow is less than 2% */
50 if (ticks > INT_TICKS - INT_TICKS / 50)
51 /* Check for pending timer interrupt */
52 if (mfp.int_pn_b & (1 << 5))
53 offset = TICK_SIZE;
55 ticks = INT_TICKS - ticks;
56 ticks = ticks * 10000L / INT_TICKS;
58 return ticks + offset;
62 static void mste_read(struct MSTE_RTC *val)
64 #define COPY(v) val->v=(mste_rtc.v & 0xf)
65 do {
66 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
67 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
68 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
69 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
70 COPY(year_tens) ;
71 /* prevent from reading the clock while it changed */
72 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
73 #undef COPY
76 static void mste_write(struct MSTE_RTC *val)
78 #define COPY(v) mste_rtc.v=val->v
79 do {
80 COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
81 COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
82 COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
83 COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
84 COPY(year_tens) ;
85 /* prevent from writing the clock while it changed */
86 } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
87 #undef COPY
90 #define RTC_READ(reg) \
91 ({ unsigned char __val; \
92 (void) atari_writeb(reg,&tt_rtc.regsel); \
93 __val = tt_rtc.data; \
94 __val; \
97 #define RTC_WRITE(reg,val) \
98 do { \
99 atari_writeb(reg,&tt_rtc.regsel); \
100 tt_rtc.data = (val); \
101 } while(0)
104 #define HWCLK_POLL_INTERVAL 5
106 int atari_mste_hwclk( int op, struct rtc_time *t )
108 int hour, year;
109 int hr24=0;
110 struct MSTE_RTC val;
112 mste_rtc.mode=(mste_rtc.mode | 1);
113 hr24=mste_rtc.mon_tens & 1;
114 mste_rtc.mode=(mste_rtc.mode & ~1);
116 if (op) {
117 /* write: prepare values */
119 val.sec_ones = t->tm_sec % 10;
120 val.sec_tens = t->tm_sec / 10;
121 val.min_ones = t->tm_min % 10;
122 val.min_tens = t->tm_min / 10;
123 hour = t->tm_hour;
124 if (!hr24) {
125 if (hour > 11)
126 hour += 20 - 12;
127 if (hour == 0 || hour == 20)
128 hour += 12;
130 val.hr_ones = hour % 10;
131 val.hr_tens = hour / 10;
132 val.day_ones = t->tm_mday % 10;
133 val.day_tens = t->tm_mday / 10;
134 val.mon_ones = (t->tm_mon+1) % 10;
135 val.mon_tens = (t->tm_mon+1) / 10;
136 year = t->tm_year - 80;
137 val.year_ones = year % 10;
138 val.year_tens = year / 10;
139 val.weekday = t->tm_wday;
140 mste_write(&val);
141 mste_rtc.mode=(mste_rtc.mode | 1);
142 val.year_ones = (year % 4); /* leap year register */
143 mste_rtc.mode=(mste_rtc.mode & ~1);
145 else {
146 mste_read(&val);
147 t->tm_sec = val.sec_ones + val.sec_tens * 10;
148 t->tm_min = val.min_ones + val.min_tens * 10;
149 hour = val.hr_ones + val.hr_tens * 10;
150 if (!hr24) {
151 if (hour == 12 || hour == 12 + 20)
152 hour -= 12;
153 if (hour >= 20)
154 hour += 12 - 20;
156 t->tm_hour = hour;
157 t->tm_mday = val.day_ones + val.day_tens * 10;
158 t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
159 t->tm_year = val.year_ones + val.year_tens * 10 + 80;
160 t->tm_wday = val.weekday;
162 return 0;
165 int atari_tt_hwclk( int op, struct rtc_time *t )
167 int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
168 unsigned long flags;
169 unsigned char ctrl;
170 int pm = 0;
172 ctrl = RTC_READ(RTC_CONTROL); /* control registers are
173 * independent from the UIP */
175 if (op) {
176 /* write: prepare values */
178 sec = t->tm_sec;
179 min = t->tm_min;
180 hour = t->tm_hour;
181 day = t->tm_mday;
182 mon = t->tm_mon + 1;
183 year = t->tm_year - atari_rtc_year_offset;
184 wday = t->tm_wday + (t->tm_wday >= 0);
186 if (!(ctrl & RTC_24H)) {
187 if (hour > 11) {
188 pm = 0x80;
189 if (hour != 12)
190 hour -= 12;
192 else if (hour == 0)
193 hour = 12;
196 if (!(ctrl & RTC_DM_BINARY)) {
197 sec = bin2bcd(sec);
198 min = bin2bcd(min);
199 hour = bin2bcd(hour);
200 day = bin2bcd(day);
201 mon = bin2bcd(mon);
202 year = bin2bcd(year);
203 if (wday >= 0)
204 wday = bin2bcd(wday);
208 /* Reading/writing the clock registers is a bit critical due to
209 * the regular update cycle of the RTC. While an update is in
210 * progress, registers 0..9 shouldn't be touched.
211 * The problem is solved like that: If an update is currently in
212 * progress (the UIP bit is set), the process sleeps for a while
213 * (50ms). This really should be enough, since the update cycle
214 * normally needs 2 ms.
215 * If the UIP bit reads as 0, we have at least 244 usecs until the
216 * update starts. This should be enough... But to be sure,
217 * additionally the RTC_SET bit is set to prevent an update cycle.
220 while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
221 if (in_atomic() || irqs_disabled())
222 mdelay(1);
223 else
224 schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
227 local_irq_save(flags);
228 RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
229 if (!op) {
230 sec = RTC_READ( RTC_SECONDS );
231 min = RTC_READ( RTC_MINUTES );
232 hour = RTC_READ( RTC_HOURS );
233 day = RTC_READ( RTC_DAY_OF_MONTH );
234 mon = RTC_READ( RTC_MONTH );
235 year = RTC_READ( RTC_YEAR );
236 wday = RTC_READ( RTC_DAY_OF_WEEK );
238 else {
239 RTC_WRITE( RTC_SECONDS, sec );
240 RTC_WRITE( RTC_MINUTES, min );
241 RTC_WRITE( RTC_HOURS, hour + pm);
242 RTC_WRITE( RTC_DAY_OF_MONTH, day );
243 RTC_WRITE( RTC_MONTH, mon );
244 RTC_WRITE( RTC_YEAR, year );
245 if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
247 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
248 local_irq_restore(flags);
250 if (!op) {
251 /* read: adjust values */
253 if (hour & 0x80) {
254 hour &= ~0x80;
255 pm = 1;
258 if (!(ctrl & RTC_DM_BINARY)) {
259 sec = bcd2bin(sec);
260 min = bcd2bin(min);
261 hour = bcd2bin(hour);
262 day = bcd2bin(day);
263 mon = bcd2bin(mon);
264 year = bcd2bin(year);
265 wday = bcd2bin(wday);
268 if (!(ctrl & RTC_24H)) {
269 if (!pm && hour == 12)
270 hour = 0;
271 else if (pm && hour != 12)
272 hour += 12;
275 t->tm_sec = sec;
276 t->tm_min = min;
277 t->tm_hour = hour;
278 t->tm_mday = day;
279 t->tm_mon = mon - 1;
280 t->tm_year = year + atari_rtc_year_offset;
281 t->tm_wday = wday - 1;
284 return( 0 );
288 int atari_mste_set_clock_mmss (unsigned long nowtime)
290 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
291 struct MSTE_RTC val;
292 unsigned char rtc_minutes;
294 mste_read(&val);
295 rtc_minutes= val.min_ones + val.min_tens * 10;
296 if ((rtc_minutes < real_minutes
297 ? real_minutes - rtc_minutes
298 : rtc_minutes - real_minutes) < 30)
300 val.sec_ones = real_seconds % 10;
301 val.sec_tens = real_seconds / 10;
302 val.min_ones = real_minutes % 10;
303 val.min_tens = real_minutes / 10;
304 mste_write(&val);
306 else
307 return -1;
308 return 0;
311 int atari_tt_set_clock_mmss (unsigned long nowtime)
313 int retval = 0;
314 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
315 unsigned char save_control, save_freq_select, rtc_minutes;
317 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
318 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
320 save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
321 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
323 rtc_minutes = RTC_READ (RTC_MINUTES);
324 if (!(save_control & RTC_DM_BINARY))
325 rtc_minutes = bcd2bin(rtc_minutes);
327 /* Since we're only adjusting minutes and seconds, don't interfere
328 with hour overflow. This avoids messing with unknown time zones
329 but requires your RTC not to be off by more than 30 minutes. */
330 if ((rtc_minutes < real_minutes
331 ? real_minutes - rtc_minutes
332 : rtc_minutes - real_minutes) < 30)
334 if (!(save_control & RTC_DM_BINARY))
336 real_seconds = bin2bcd(real_seconds);
337 real_minutes = bin2bcd(real_minutes);
339 RTC_WRITE (RTC_SECONDS, real_seconds);
340 RTC_WRITE (RTC_MINUTES, real_minutes);
342 else
343 retval = -1;
345 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
346 RTC_WRITE (RTC_CONTROL, save_control);
347 return retval;
351 * Local variables:
352 * c-indent-level: 4
353 * tab-width: 8
354 * End: