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 21 #include <asm/atariints.h> 22 23 DEFINE_SPINLOCK(rtc_lock); 24 EXPORT_SYMBOL_GPL(rtc_lock); 25 26 void __init 27 atari_sched_init(irq_handler_t timer_routine) 28 { 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); 36 } 37 38 /* ++andreas: gettimeoffset fixed to check for pending interrupt */ 39 40 #define TICK_SIZE 10000 41 42 /* This is always executed with interrupts disabled. */ 43 unsigned long atari_gettimeoffset (void) 44 { 45 unsigned long ticks, offset = 0; 46 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; 54 55 ticks = INT_TICKS - ticks; 56 ticks = ticks * 10000L / INT_TICKS; 57 58 return ticks + offset; 59 } 60 61 62 static void mste_read(struct MSTE_RTC *val) 63 { 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 74 } 75 76 static void mste_write(struct MSTE_RTC *val) 77 { 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 88 } 89 90 #define RTC_READ(reg) \ 91 ({ unsigned char __val; \ 92 (void) atari_writeb(reg,&tt_rtc.regsel); \ 93 __val = tt_rtc.data; \ 94 __val; \ 95 }) 96 97 #define RTC_WRITE(reg,val) \ 98 do { \ 99 atari_writeb(reg,&tt_rtc.regsel); \ 100 tt_rtc.data = (val); \ 101 } while(0) 102 103 104 #define HWCLK_POLL_INTERVAL 5 105 106 int atari_mste_hwclk( int op, struct rtc_time *t ) 107 { 108 int hour, year; 109 int hr24=0; 110 struct MSTE_RTC val; 111 112 mste_rtc.mode=(mste_rtc.mode | 1); 113 hr24=mste_rtc.mon_tens & 1; 114 mste_rtc.mode=(mste_rtc.mode & ~1); 115 116 if (op) { 117 /* write: prepare values */ 118 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; 129 } 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); 144 } 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; 155 } 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; 161 } 162 return 0; 163 } 164 165 int atari_tt_hwclk( int op, struct rtc_time *t ) 166 { 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; 171 172 ctrl = RTC_READ(RTC_CONTROL); /* control registers are 173 * independent from the UIP */ 174 175 if (op) { 176 /* write: prepare values */ 177 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); 185 186 if (!(ctrl & RTC_24H)) { 187 if (hour > 11) { 188 pm = 0x80; 189 if (hour != 12) 190 hour -= 12; 191 } 192 else if (hour == 0) 193 hour = 12; 194 } 195 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); 205 } 206 } 207 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. 218 */ 219 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); 225 } 226 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 ); 237 } 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 ); 246 } 247 RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); 248 local_irq_restore(flags); 249 250 if (!op) { 251 /* read: adjust values */ 252 253 if (hour & 0x80) { 254 hour &= ~0x80; 255 pm = 1; 256 } 257 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); 266 } 267 268 if (!(ctrl & RTC_24H)) { 269 if (!pm && hour == 12) 270 hour = 0; 271 else if (pm && hour != 12) 272 hour += 12; 273 } 274 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; 282 } 283 284 return( 0 ); 285 } 286 287 288 int atari_mste_set_clock_mmss (unsigned long nowtime) 289 { 290 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; 291 struct MSTE_RTC val; 292 unsigned char rtc_minutes; 293 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) 299 { 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); 305 } 306 else 307 return -1; 308 return 0; 309 } 310 311 int atari_tt_set_clock_mmss (unsigned long nowtime) 312 { 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; 316 317 save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ 318 RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); 319 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); 322 323 rtc_minutes = RTC_READ (RTC_MINUTES); 324 if (!(save_control & RTC_DM_BINARY)) 325 rtc_minutes = bcd2bin(rtc_minutes); 326 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) 333 { 334 if (!(save_control & RTC_DM_BINARY)) 335 { 336 real_seconds = bin2bcd(real_seconds); 337 real_minutes = bin2bcd(real_minutes); 338 } 339 RTC_WRITE (RTC_SECONDS, real_seconds); 340 RTC_WRITE (RTC_MINUTES, real_minutes); 341 } 342 else 343 retval = -1; 344 345 RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); 346 RTC_WRITE (RTC_CONTROL, save_control); 347 return retval; 348 } 349 350 /* 351 * Local variables: 352 * c-indent-level: 4 353 * tab-width: 8 354 * End: 355 */ 356