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