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