[BACK]Return to rs5c313.c CVS log [TXT][DIR] Up to [local] / sys / arch / landisk / dev

Annotation of sys/arch/landisk/dev/rs5c313.c, Revision 1.1.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