1 /* $OpenBSD: rs5c313.c,v 1.3 2008/06/27 06:03:08 ray Exp $ */ 2 /* $NetBSD: rs5c313.c,v 1.1 2006/09/07 01:12:00 uwe Exp $ */ 3 /* $NetBSD: rs5c313_landisk.c,v 1.1 2006/09/07 01:55:03 uwe Exp $ */ 4 5 /*- 6 * Copyright (c) 2002 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * RICOH RS5C313 Real Time Clock 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/kernel.h> 39 40 #include <dev/clock_subr.h> 41 #include <sh/clock.h> 42 43 #include <sh/devreg.h> 44 #include <sh/dev/scireg.h> 45 46 #include <landisk/dev/rs5c313reg.h> 47 #include <landisk/landisk/landiskreg.h> 48 49 struct rs5c313_softc { 50 struct device sc_dev; 51 52 int sc_valid; /* oscillation halt sensing on init */ 53 }; 54 55 /* chip access methods */ 56 void rtc_begin(struct rs5c313_softc *); 57 void rtc_ce(struct rs5c313_softc *, int); 58 void rtc_dir(struct rs5c313_softc *, int); 59 void rtc_clk(struct rs5c313_softc *, int); 60 int rtc_read(struct rs5c313_softc *); 61 void rtc_write(struct rs5c313_softc *, int); 62 63 int rs5c313_init(struct rs5c313_softc *); 64 int rs5c313_read_reg(struct rs5c313_softc *, int); 65 void rs5c313_write_reg(struct rs5c313_softc *, int, int); 66 void rs5c313_gettime(void *, time_t, struct clock_ymdhms *); 67 void rs5c313_settime(void *, struct clock_ymdhms *); 68 69 int 70 rs5c313_init(struct rs5c313_softc *sc) 71 { 72 int status = 0; 73 int retry; 74 75 rtc_ce(sc, 0); 76 77 rtc_begin(sc); 78 rtc_ce(sc, 1); 79 80 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_XSTP) == 0) { 81 sc->sc_valid = 1; 82 goto done; 83 } 84 85 sc->sc_valid = 0; 86 printf("%s: time not valid\n", sc->sc_dev.dv_xname); 87 88 rs5c313_write_reg(sc, RS5C313_TINT, 0); 89 rs5c313_write_reg(sc, RS5C313_CTRL, (CTRL_BASE | CTRL_ADJ)); 90 91 for (retry = 1000; retry > 0; --retry) { 92 if (rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) 93 delay(1); 94 else 95 break; 96 } 97 98 if (retry == 0) { 99 status = EIO; 100 goto done; 101 } 102 103 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE); 104 105 done: 106 rtc_ce(sc, 0); 107 return status; 108 } 109 110 int 111 rs5c313_read_reg(struct rs5c313_softc *sc, int addr) 112 { 113 int data; 114 115 /* output */ 116 rtc_dir(sc, 1); 117 118 /* control */ 119 rtc_write(sc, 1); /* ignored */ 120 rtc_write(sc, 1); /* R/#W = 1(READ) */ 121 rtc_write(sc, 1); /* AD = 1 */ 122 rtc_write(sc, 0); /* DT = 0 */ 123 124 /* address */ 125 rtc_write(sc, addr & 0x8); /* A3 */ 126 rtc_write(sc, addr & 0x4); /* A2 */ 127 rtc_write(sc, addr & 0x2); /* A1 */ 128 rtc_write(sc, addr & 0x1); /* A0 */ 129 130 /* input */ 131 rtc_dir(sc, 0); 132 133 /* ignore */ 134 (void)rtc_read(sc); 135 (void)rtc_read(sc); 136 (void)rtc_read(sc); 137 (void)rtc_read(sc); 138 139 /* data */ 140 data = rtc_read(sc); /* D3 */ 141 data <<= 1; 142 data |= rtc_read(sc); /* D2 */ 143 data <<= 1; 144 data |= rtc_read(sc); /* D1 */ 145 data <<= 1; 146 data |= rtc_read(sc); /* D0 */ 147 148 return data; 149 } 150 151 void 152 rs5c313_write_reg(struct rs5c313_softc *sc, int addr, int data) 153 { 154 /* output */ 155 rtc_dir(sc, 1); 156 157 /* control */ 158 rtc_write(sc, 1); /* ignored */ 159 rtc_write(sc, 0); /* R/#W = 0 (WRITE) */ 160 rtc_write(sc, 1); /* AD = 1 */ 161 rtc_write(sc, 0); /* DT = 0 */ 162 163 /* address */ 164 rtc_write(sc, addr & 0x8); /* A3 */ 165 rtc_write(sc, addr & 0x4); /* A2 */ 166 rtc_write(sc, addr & 0x2); /* A1 */ 167 rtc_write(sc, addr & 0x1); /* A0 */ 168 169 /* control */ 170 rtc_write(sc, 1); /* ignored */ 171 rtc_write(sc, 0); /* R/#W = 0(WRITE) */ 172 rtc_write(sc, 0); /* AD = 0 */ 173 rtc_write(sc, 1); /* DT = 1 */ 174 175 /* data */ 176 rtc_write(sc, data & 0x8); /* D3 */ 177 rtc_write(sc, data & 0x4); /* D2 */ 178 rtc_write(sc, data & 0x2); /* D1 */ 179 rtc_write(sc, data & 0x1); /* D0 */ 180 } 181 182 void 183 rs5c313_gettime(void *cookie, time_t base, struct clock_ymdhms *dt) 184 { 185 struct rs5c313_softc *sc = cookie; 186 int retry; 187 int s; 188 189 /* 190 * If chip had invalid data on init, don't bother reading 191 * bogus values. 192 */ 193 if (sc->sc_valid == 0) 194 return; 195 196 s = splhigh(); 197 198 rtc_begin(sc); 199 for (retry = 10; retry > 0; --retry) { 200 rtc_ce(sc, 1); 201 202 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE); 203 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0) 204 break; 205 206 rtc_ce(sc, 0); 207 delay(1); 208 } 209 210 if (retry == 0) { 211 splx(s); 212 return; 213 } 214 215 #define RTCGET(x, y) \ 216 do { \ 217 int ones = rs5c313_read_reg(sc, RS5C313_ ## y ## 1); \ 218 int tens = rs5c313_read_reg(sc, RS5C313_ ## y ## 10); \ 219 dt->dt_ ## x = tens * 10 + ones; \ 220 } while (/* CONSTCOND */0) 221 222 RTCGET(sec, SEC); 223 RTCGET(min, MIN); 224 RTCGET(hour, HOUR); 225 RTCGET(day, DAY); 226 RTCGET(mon, MON); 227 RTCGET(year, YEAR); 228 #undef RTCGET 229 dt->dt_wday = rs5c313_read_reg(sc, RS5C313_WDAY); 230 231 rtc_ce(sc, 0); 232 splx(s); 233 234 dt->dt_year = (dt->dt_year % 100) + 1900; 235 if (dt->dt_year < 1970) { 236 dt->dt_year += 100; 237 } 238 } 239 240 void 241 rs5c313_settime(void *cookie, struct clock_ymdhms *dt) 242 { 243 struct rs5c313_softc *sc = cookie; 244 int retry; 245 int t; 246 int s; 247 248 s = splhigh(); 249 250 rtc_begin(sc); 251 for (retry = 10; retry > 0; --retry) { 252 rtc_ce(sc, 1); 253 254 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE); 255 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0) 256 break; 257 258 rtc_ce(sc, 0); 259 delay(1); 260 } 261 262 if (retry == 0) { 263 splx(s); 264 return; 265 } 266 267 #define RTCSET(x, y) \ 268 do { \ 269 t = TOBCD(dt->dt_ ## y) & 0xff; \ 270 rs5c313_write_reg(sc, RS5C313_ ## x ## 1, t & 0x0f); \ 271 rs5c313_write_reg(sc, RS5C313_ ## x ## 10, (t >> 4) & 0x0f); \ 272 } while (/* CONSTCOND */0) 273 274 RTCSET(SEC, sec); 275 RTCSET(MIN, min); 276 RTCSET(HOUR, hour); 277 RTCSET(DAY, day); 278 RTCSET(MON, mon); 279 280 #undef RTCSET 281 282 t = dt->dt_year % 100; 283 t = TOBCD(t); 284 rs5c313_write_reg(sc, RS5C313_YEAR1, t & 0x0f); 285 rs5c313_write_reg(sc, RS5C313_YEAR10, (t >> 4) & 0x0f); 286 287 rs5c313_write_reg(sc, RS5C313_WDAY, dt->dt_wday); 288 289 rtc_ce(sc, 0); 290 splx(s); 291 292 sc->sc_valid = 1; 293 } 294 295 struct rtc_ops rs5c313_ops = { 296 NULL, 297 NULL, /* not used */ 298 rs5c313_gettime, 299 rs5c313_settime 300 }; 301 302 void 303 rtc_begin(struct rs5c313_softc *sc) 304 { 305 SHREG_SCSPTR = SCSPTR_SPB1IO | SCSPTR_SPB1DT 306 | SCSPTR_SPB0IO | SCSPTR_SPB0DT; 307 delay(100); 308 } 309 310 /* 311 * CE pin 312 */ 313 void 314 rtc_ce(struct rs5c313_softc *sc, int onoff) 315 { 316 if (onoff) 317 _reg_write_1(LANDISK_PWRMNG, PWRMNG_RTC_CE); 318 else 319 _reg_write_1(LANDISK_PWRMNG, 0); 320 delay(600); 321 } 322 323 /* 324 * SCLK pin is connnected to SPB0DT. 325 * SPB0DT is always in output mode, we set SPB0IO in rtc_begin. 326 */ 327 void 328 rtc_clk(struct rs5c313_softc *sc, int onoff) 329 { 330 uint8_t r = SHREG_SCSPTR; 331 332 if (onoff) 333 r |= SCSPTR_SPB0DT; 334 else 335 r &= ~SCSPTR_SPB0DT; 336 SHREG_SCSPTR = r; 337 } 338 339 /* 340 * SIO pin is connected to SPB1DT. 341 * SPB1DT is output when SPB1IO is set. 342 */ 343 void 344 rtc_dir(struct rs5c313_softc *sc, int output) 345 { 346 uint8_t r = SHREG_SCSPTR; 347 348 if (output) 349 r |= SCSPTR_SPB1IO; 350 else 351 r &= ~SCSPTR_SPB1IO; 352 SHREG_SCSPTR = r; 353 } 354 355 /* 356 * Read bit from SPB1DT pin. 357 */ 358 int 359 rtc_read(struct rs5c313_softc *sc) 360 { 361 int bit; 362 363 delay(300); 364 365 bit = (SHREG_SCSPTR & SCSPTR_SPB1DT) ? 1 : 0; 366 367 rtc_clk(sc, 0); 368 delay(300); 369 rtc_clk(sc, 1); 370 371 return bit; 372 } 373 374 /* 375 * Write bit via SPB1DT pin. 376 */ 377 void 378 rtc_write(struct rs5c313_softc *sc, int bit) 379 { 380 uint8_t r = SHREG_SCSPTR; 381 382 if (bit) 383 r |= SCSPTR_SPB1DT; 384 else 385 r &= ~SCSPTR_SPB1DT; 386 SHREG_SCSPTR = r; 387 388 delay(300); 389 390 rtc_clk(sc, 0); 391 delay(300); 392 rtc_clk(sc, 1); 393 } 394 395 /* autoconf glue */ 396 int rs5c313_landisk_match(struct device *, void *, void *); 397 void rs5c313_landisk_attach(struct device *, struct device *, void *); 398 399 const struct cfattach rsclock_ca = { 400 sizeof (struct rs5c313_softc), 401 rs5c313_landisk_match, rs5c313_landisk_attach 402 }; 403 404 struct cfdriver rsclock_cd = { 405 0, "rsclock", DV_DULL 406 }; 407 408 int 409 rs5c313_landisk_match(struct device *parent, void *vcf, void *aux) 410 { 411 static int matched = 0; 412 413 if (matched) 414 return (0); 415 416 return (matched = 1); 417 } 418 419 void 420 rs5c313_landisk_attach(struct device *parent, struct device *self, void *aux) 421 { 422 struct rs5c313_softc *sc = (void *)self; 423 424 printf(": RS5C313 real time clock\n"); 425 426 if (rs5c313_init(sc) != 0) { 427 printf("%s: init failed\n", self->dv_xname); 428 return; 429 } 430 431 rs5c313_ops._cookie = sc; 432 sh_clock_init(SH_CLOCK_NORTC, &rs5c313_ops); 433 } 434