1 /* $NetBSD: rtc.c,v 1.3 1999/01/31 07:02:34 dbj Exp $ */ 2 /* 3 * Copyright (c) 1998 Darrin Jewell 4 * Copyright (c) 1997 Rolf Grossmann 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Rolf Grossmann. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* These haven't been tested to see how they interact with NeXTstep's 34 * interpretation of the rtc. 35 */ 36 37 /* Now using this in the kernel. This should be turned into a device 38 * Darrin B Jewell <jewell@mit.edu> Tue Jan 27 20:59:25 1998 39 */ 40 41 #include <sys/param.h> 42 #include <sys/cdefs.h> /* for __P */ 43 #include <sys/systm.h> /* for panic */ 44 45 #include <machine/cpu.h> 46 47 #include <dev/clock_subr.h> 48 49 #include <next68k/dev/clockreg.h> 50 51 /* #define RTC_DEBUG */ 52 53 void rtc_init __P((void)); 54 u_char rtc_read __P((u_char)); 55 void rtc_write __P((u_char, u_char)); 56 void rtc_print __P((void)); 57 void poweroff __P((void)); 58 time_t getsecs __P((void)); 59 void setsecs __P((time_t)); 60 61 u_char new_clock; 62 volatile u_int *scr2 = (u_int *)NEXT_P_SCR2; /* will get memory mapped in rtc_init */ 63 64 void 65 rtc_init(void) 66 { 67 u_char val; 68 69 scr2 = (u_int *)IIOV(NEXT_P_SCR2); 70 val = rtc_read(RTC_STATUS); 71 new_clock = (val & RTC_NEW_CLOCK) ? 1 : 0; 72 73 printf("Looks like a %s clock chip.\n", 74 (new_clock? 75 "MCS1850 (new style)": 76 "MC68HC68T1 (old style)")); 77 78 #ifdef RTC_DEBUG 79 rtc_print(); 80 #endif 81 } 82 83 void 84 rtc_print(void) 85 { 86 87 #define RTC_PRINT(x) printf("\t%16s= 0x%02x\n",#x, rtc_read(x)) 88 89 if (new_clock) { 90 RTC_PRINT(RTC_RAM); 91 RTC_PRINT(RTC_CNTR0); 92 RTC_PRINT(RTC_CNTR1); 93 RTC_PRINT(RTC_CNTR2); 94 RTC_PRINT(RTC_CNTR3); 95 RTC_PRINT(RTC_ALARM0); 96 RTC_PRINT(RTC_ALARM1); 97 RTC_PRINT(RTC_ALARM2); 98 RTC_PRINT(RTC_ALARM3); 99 RTC_PRINT(RTC_STATUS); 100 RTC_PRINT(RTC_CONTROL); 101 } else { 102 RTC_PRINT(RTC_RAM); 103 RTC_PRINT(RTC_SEC); 104 RTC_PRINT(RTC_MIN); 105 RTC_PRINT(RTC_HRS); 106 RTC_PRINT(RTC_DAY); 107 RTC_PRINT(RTC_DATE); 108 RTC_PRINT(RTC_MON); 109 RTC_PRINT(RTC_YR); 110 RTC_PRINT(RTC_ALARM_SEC); 111 RTC_PRINT(RTC_ALARM_MIN); 112 RTC_PRINT(RTC_ALARM_HR); 113 RTC_PRINT(RTC_STATUS); 114 RTC_PRINT(RTC_CONTROL); 115 RTC_PRINT(RTC_INTRCTL); 116 } 117 } 118 119 120 u_char 121 rtc_read(u_char reg) 122 { 123 int i; 124 u_int tmp; 125 u_char val; 126 127 *scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE; 128 DELAY(1); 129 130 val = reg; 131 for (i=0; i<8; i++) { 132 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 133 if (val & 0x80) 134 tmp |= SCR2_RTDATA; 135 136 *scr2 = tmp; 137 DELAY(1); 138 *scr2 = tmp | SCR2_RTCLK; 139 DELAY(1); 140 *scr2 = tmp; 141 DELAY(1); 142 143 val <<= 1; 144 } 145 146 val = 0; /* should be anyway */ 147 for (i=0; i<8; i++) { 148 val <<= 1; 149 150 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 151 152 *scr2 = tmp | SCR2_RTCLK; 153 DELAY(1); 154 *scr2 = tmp; 155 DELAY(1); 156 157 if (*scr2 & SCR2_RTDATA) 158 val |= 1; 159 } 160 161 *scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE); 162 DELAY(1); 163 164 return val; 165 } 166 167 void 168 rtc_write(u_char reg, u_char v) 169 { 170 int i; 171 u_int tmp; 172 u_char val; 173 174 *scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE; 175 DELAY(1); 176 177 val = reg|RTC_WRITE; 178 179 for (i=0; i<8; i++) { 180 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 181 if (val & 0x80) 182 tmp |= SCR2_RTDATA; 183 184 *scr2 = tmp; 185 DELAY(1); 186 *scr2 = tmp | SCR2_RTCLK; 187 DELAY(1); 188 *scr2 = tmp; 189 DELAY(1); 190 191 val <<= 1; 192 } 193 194 DELAY(1); 195 196 for (i=0; i<8; i++) { 197 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 198 if (v & 0x80) 199 tmp |= SCR2_RTDATA; 200 201 *scr2 = tmp; 202 DELAY(1); 203 *scr2 = tmp | SCR2_RTCLK; 204 DELAY(1); 205 *scr2 = tmp; 206 DELAY(1); 207 208 v <<= 1; 209 } 210 211 *scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE); 212 DELAY(1); 213 } 214 215 void 216 poweroff(void) 217 { 218 int reg, t; 219 220 if(new_clock) { 221 reg = RTC_CNTR3; 222 } else { 223 reg = RTC_CNTR0; 224 } 225 226 t = rtc_read(reg); /* seconds */ 227 /* wait for clock to tick */ 228 while(t == rtc_read(reg)); 229 230 DELAY(850000); /* hardware bug workaround ? */ 231 232 if(new_clock) { 233 reg = RTC_CONTROL; 234 } else { 235 reg = RTC_INTRCTL; 236 } 237 238 rtc_write(reg, rtc_read(reg)|(RTC_PDOWN)); 239 240 printf("....................."); /* @@@ work around some sort of bug. */ 241 242 panic("Failed to poweroff!\n"); 243 } 244 245 246 time_t 247 getsecs(void) 248 { 249 u_int secs = 0; 250 251 if (new_clock) { 252 secs = rtc_read(RTC_CNTR3) << 24 | 253 rtc_read(RTC_CNTR2) << 16 | 254 rtc_read(RTC_CNTR1) << 8 | 255 rtc_read(RTC_CNTR0); 256 } else { 257 struct clock_ymdhms val; 258 { 259 u_char y; 260 y = FROMBCD(rtc_read(RTC_YR)); 261 if (y >= 69) { 262 val.dt_year = 1900+y; 263 } else { 264 val.dt_year = 2000+y; 265 } 266 } 267 val.dt_mon = FROMBCD(rtc_read(RTC_MON)&0x1f); 268 val.dt_day = FROMBCD(rtc_read(RTC_DATE)&0x3f); 269 val.dt_wday = FROMBCD(rtc_read(RTC_DAY)&0x7); 270 { 271 u_char h; 272 h = rtc_read(RTC_HRS); 273 if (h & 0x80) { /* time is am/pm format */ 274 val.dt_hour = FROMBCD(h&0x1f); 275 if (h & 0x20) { /* pm */ 276 if (val.dt_hour < 12) val.dt_hour += 12; 277 } else { /* am */ 278 if (val.dt_hour == 12) val.dt_hour = 0; 279 } 280 } else { /* time is 24 hour format */ 281 val.dt_hour = FROMBCD(h & 0x3f); 282 } 283 } 284 val.dt_min = FROMBCD(rtc_read(RTC_MIN)&0x7f); 285 val.dt_sec = FROMBCD(rtc_read(RTC_SEC)&0x7f); 286 287 secs = clock_ymdhms_to_secs(&val); 288 } 289 290 return secs; 291 } 292 293 void 294 setsecs(time_t secs) 295 { 296 297 /* Stop the clock */ 298 rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) & ~RTC_START); 299 300 #ifdef RTC_DEBUG 301 printf("Setting RTC to 0x%08x. Regs before:\n",secs); 302 rtc_print(); 303 #endif 304 305 if (new_clock) { 306 rtc_write(RTC_CNTR3, (secs << 24) & 0xff); 307 rtc_write(RTC_CNTR2, (secs << 16) & 0xff); 308 rtc_write(RTC_CNTR1, (secs << 8) & 0xff); 309 rtc_write(RTC_CNTR0, (secs) & 0xff); 310 311 } else { 312 struct clock_ymdhms val; 313 clock_secs_to_ymdhms(secs,&val); 314 rtc_write(RTC_SEC,TOBCD(val.dt_sec)); 315 rtc_write(RTC_MIN,TOBCD(val.dt_min)); 316 { 317 u_char h; 318 h = rtc_read(RTC_HRS); 319 if (h & 0x80) { /* time is am/pm format */ 320 if (val.dt_hour == 0) { 321 rtc_write(RTC_HRS,TOBCD(12)|0x80); 322 } else if (val.dt_hour < 12) { /* am */ 323 rtc_write(RTC_HRS,TOBCD(val.dt_hour)|0x80); 324 } else if (val.dt_hour == 12) { 325 rtc_write(RTC_HRS,TOBCD(12)|0x80|0x20); 326 } else { /* pm */ 327 rtc_write(RTC_HRS,TOBCD(val.dt_hour-12)|0x80|0x20); 328 } 329 } else { /* time is 24 hour format */ 330 rtc_write(RTC_HRS,TOBCD(val.dt_hour)); 331 } 332 } 333 rtc_write(RTC_DAY,TOBCD(val.dt_wday)); 334 rtc_write(RTC_DATE,TOBCD(val.dt_day)); 335 rtc_write(RTC_MON,TOBCD(val.dt_mon)); 336 rtc_write(RTC_YR,TOBCD(val.dt_year%100)); 337 } 338 339 #ifdef RTC_DEBUG 340 printf("Regs after:\n",secs); 341 rtc_print(); 342 #endif 343 344 /* restart the clock */ 345 rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) | RTC_START); 346 347 } 348