1 /* $NetBSD: rtc.c,v 1.7 2002/09/27 15:36:32 provos 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/bus.h> 46 #include <machine/cpu.h> 47 48 #include <dev/clock_subr.h> 49 50 #include <next68k/next68k/rtc.h> 51 52 #include <next68k/dev/clockreg.h> 53 #include <next68k/dev/intiovar.h> 54 55 /* #define RTC_DEBUG */ 56 57 u_char new_clock; 58 volatile u_int *scr2 = (u_int *)NEXT_P_SCR2; /* will get memory mapped in rtc_init */ 59 60 void 61 rtc_init(void) 62 { 63 u_char val; 64 65 scr2 = (u_int *)IIOV(NEXT_P_SCR2); 66 val = rtc_read(RTC_STATUS); 67 new_clock = (val & RTC_NEW_CLOCK) ? 1 : 0; 68 69 printf("Looks like a %s clock chip.\n", 70 (new_clock? 71 "MCS1850 (new style)": 72 "MC68HC68T1 (old style)")); 73 74 #ifdef RTC_DEBUG 75 rtc_print(); 76 #endif 77 } 78 79 void 80 rtc_print(void) 81 { 82 83 #define RTC_PRINT(x) printf("\t%16s= 0x%02x\n",#x, rtc_read(x)) 84 85 if (new_clock) { 86 RTC_PRINT(RTC_RAM); 87 RTC_PRINT(RTC_CNTR0); 88 RTC_PRINT(RTC_CNTR1); 89 RTC_PRINT(RTC_CNTR2); 90 RTC_PRINT(RTC_CNTR3); 91 RTC_PRINT(RTC_ALARM0); 92 RTC_PRINT(RTC_ALARM1); 93 RTC_PRINT(RTC_ALARM2); 94 RTC_PRINT(RTC_ALARM3); 95 RTC_PRINT(RTC_STATUS); 96 RTC_PRINT(RTC_CONTROL); 97 } else { 98 RTC_PRINT(RTC_RAM); 99 RTC_PRINT(RTC_SEC); 100 RTC_PRINT(RTC_MIN); 101 RTC_PRINT(RTC_HRS); 102 RTC_PRINT(RTC_DAY); 103 RTC_PRINT(RTC_DATE); 104 RTC_PRINT(RTC_MON); 105 RTC_PRINT(RTC_YR); 106 RTC_PRINT(RTC_ALARM_SEC); 107 RTC_PRINT(RTC_ALARM_MIN); 108 RTC_PRINT(RTC_ALARM_HR); 109 RTC_PRINT(RTC_STATUS); 110 RTC_PRINT(RTC_CONTROL); 111 RTC_PRINT(RTC_INTRCTL); 112 } 113 } 114 115 116 u_char 117 rtc_read(u_char reg) 118 { 119 int i; 120 u_int tmp; 121 u_char val; 122 123 *scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE; 124 DELAY(1); 125 126 val = reg; 127 for (i=0; i<8; i++) { 128 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 129 if (val & 0x80) 130 tmp |= SCR2_RTDATA; 131 132 *scr2 = tmp; 133 DELAY(1); 134 *scr2 = tmp | SCR2_RTCLK; 135 DELAY(1); 136 *scr2 = tmp; 137 DELAY(1); 138 139 val <<= 1; 140 } 141 142 val = 0; /* should be anyway */ 143 for (i=0; i<8; i++) { 144 val <<= 1; 145 146 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 147 148 *scr2 = tmp | SCR2_RTCLK; 149 DELAY(1); 150 *scr2 = tmp; 151 DELAY(1); 152 153 if (*scr2 & SCR2_RTDATA) 154 val |= 1; 155 } 156 157 *scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE); 158 DELAY(1); 159 160 return val; 161 } 162 163 void 164 rtc_write(u_char reg, u_char v) 165 { 166 int i; 167 u_int tmp; 168 u_char val; 169 170 *scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE; 171 DELAY(1); 172 173 val = reg|RTC_WRITE; 174 175 for (i=0; i<8; i++) { 176 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 177 if (val & 0x80) 178 tmp |= SCR2_RTDATA; 179 180 *scr2 = tmp; 181 DELAY(1); 182 *scr2 = tmp | SCR2_RTCLK; 183 DELAY(1); 184 *scr2 = tmp; 185 DELAY(1); 186 187 val <<= 1; 188 } 189 190 DELAY(1); 191 192 for (i=0; i<8; i++) { 193 tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK); 194 if (v & 0x80) 195 tmp |= SCR2_RTDATA; 196 197 *scr2 = tmp; 198 DELAY(1); 199 *scr2 = tmp | SCR2_RTCLK; 200 DELAY(1); 201 *scr2 = tmp; 202 DELAY(1); 203 204 v <<= 1; 205 } 206 207 *scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE); 208 DELAY(1); 209 } 210 211 void 212 poweroff(void) 213 { 214 int reg, t; 215 216 if(new_clock) { 217 reg = RTC_CNTR3; 218 } else { 219 reg = RTC_CNTR0; 220 } 221 222 t = rtc_read(reg); /* seconds */ 223 /* wait for clock to tick */ 224 while(t == rtc_read(reg)); 225 226 DELAY(850000); /* hardware bug workaround ? */ 227 228 if(new_clock) { 229 reg = RTC_CONTROL; 230 } else { 231 reg = RTC_INTRCTL; 232 } 233 234 rtc_write(reg, rtc_read(reg)|(RTC_PDOWN)); 235 236 printf("....................."); /* @@@ work around some sort of bug. */ 237 238 panic("Failed to poweroff!"); 239 } 240 241 242 time_t 243 getsecs(void) 244 { 245 u_int secs = 0; 246 247 if (new_clock) { 248 secs = rtc_read(RTC_CNTR3) << 24 | 249 rtc_read(RTC_CNTR2) << 16 | 250 rtc_read(RTC_CNTR1) << 8 | 251 rtc_read(RTC_CNTR0); 252 } else { 253 struct clock_ymdhms val; 254 { 255 u_char y; 256 y = FROMBCD(rtc_read(RTC_YR)); 257 if (y >= 69) { 258 val.dt_year = 1900+y; 259 } else { 260 val.dt_year = 2000+y; 261 } 262 } 263 val.dt_mon = FROMBCD(rtc_read(RTC_MON)&0x1f); 264 val.dt_day = FROMBCD(rtc_read(RTC_DATE)&0x3f); 265 val.dt_wday = FROMBCD(rtc_read(RTC_DAY)&0x7); 266 { 267 u_char h; 268 h = rtc_read(RTC_HRS); 269 if (h & 0x80) { /* time is am/pm format */ 270 val.dt_hour = FROMBCD(h&0x1f); 271 if (h & 0x20) { /* pm */ 272 if (val.dt_hour < 12) val.dt_hour += 12; 273 } else { /* am */ 274 if (val.dt_hour == 12) val.dt_hour = 0; 275 } 276 } else { /* time is 24 hour format */ 277 val.dt_hour = FROMBCD(h & 0x3f); 278 } 279 } 280 val.dt_min = FROMBCD(rtc_read(RTC_MIN)&0x7f); 281 val.dt_sec = FROMBCD(rtc_read(RTC_SEC)&0x7f); 282 283 secs = clock_ymdhms_to_secs(&val); 284 } 285 286 return secs; 287 } 288 289 void 290 setsecs(time_t secs) 291 { 292 293 /* Stop the clock */ 294 rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) & ~RTC_START); 295 296 #ifdef RTC_DEBUG 297 printf("Setting RTC to 0x%08x. Regs before:\n",secs); 298 rtc_print(); 299 #endif 300 301 if (new_clock) { 302 rtc_write(RTC_CNTR3, (secs << 24) & 0xff); 303 rtc_write(RTC_CNTR2, (secs << 16) & 0xff); 304 rtc_write(RTC_CNTR1, (secs << 8) & 0xff); 305 rtc_write(RTC_CNTR0, (secs) & 0xff); 306 307 } else { 308 struct clock_ymdhms val; 309 clock_secs_to_ymdhms(secs,&val); 310 rtc_write(RTC_SEC,TOBCD(val.dt_sec)); 311 rtc_write(RTC_MIN,TOBCD(val.dt_min)); 312 { 313 u_char h; 314 h = rtc_read(RTC_HRS); 315 if (h & 0x80) { /* time is am/pm format */ 316 if (val.dt_hour == 0) { 317 rtc_write(RTC_HRS,TOBCD(12)|0x80); 318 } else if (val.dt_hour < 12) { /* am */ 319 rtc_write(RTC_HRS,TOBCD(val.dt_hour)|0x80); 320 } else if (val.dt_hour == 12) { 321 rtc_write(RTC_HRS,TOBCD(12)|0x80|0x20); 322 } else { /* pm */ 323 rtc_write(RTC_HRS,TOBCD(val.dt_hour-12)|0x80|0x20); 324 } 325 } else { /* time is 24 hour format */ 326 rtc_write(RTC_HRS,TOBCD(val.dt_hour)); 327 } 328 } 329 rtc_write(RTC_DAY,TOBCD(val.dt_wday)); 330 rtc_write(RTC_DATE,TOBCD(val.dt_day)); 331 rtc_write(RTC_MON,TOBCD(val.dt_mon)); 332 rtc_write(RTC_YR,TOBCD(val.dt_year%100)); 333 } 334 335 #ifdef RTC_DEBUG 336 printf("Regs after:\n",secs); 337 rtc_print(); 338 #endif 339 340 /* restart the clock */ 341 rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) | RTC_START); 342 343 } 344