Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Rework this driver to support other dsrtc than j...



details:   https://anonhg.NetBSD.org/src/rev/a218c3ae0958
branches:  trunk
changeset: 777574:a218c3ae0958
user:      matt <matt%NetBSD.org@localhost>
date:      Thu Feb 23 20:59:19 2012 +0000

description:
Rework this driver to support other dsrtc than just the DS1307.
Support both BCD and 32-bit binary type RTCs.
Supports DS1339, DS1672, and DS3232.
To select variant, put the module # in flags in the the config file.
dsrtc at iic0 addr 0x69 flags 1339
If the flags is not supplied, a 1307 is assumed (compatible).

diffstat:

 sys/dev/i2c/ds1307.c    |  371 ++++++++++++++++++++++++++++++++++++++---------
 sys/dev/i2c/ds1307reg.h |   71 ++++++--
 2 files changed, 346 insertions(+), 96 deletions(-)

diffs (truncated from 658 to 300 lines):

diff -r 63f35d53b58d -r a218c3ae0958 sys/dev/i2c/ds1307.c
--- a/sys/dev/i2c/ds1307.c      Thu Feb 23 20:49:46 2012 +0000
+++ b/sys/dev/i2c/ds1307.c      Thu Feb 23 20:59:19 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ds1307.c,v 1.14 2012/01/07 15:03:11 phx Exp $  */
+/*     $NetBSD: ds1307.c,v 1.15 2012/02/23 20:59:19 matt Exp $ */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.14 2012/01/07 15:03:11 phx Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.15 2012/02/23 20:59:19 matt Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -52,11 +52,55 @@
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/ds1307reg.h>
 
+struct dsrtc_model {
+       uint16_t dm_model;
+       uint8_t dm_ch_reg;
+       uint8_t dm_ch_value;
+       uint8_t dm_rtc_start;
+       uint8_t dm_rtc_size;
+       uint8_t dm_nvram_start;
+       uint8_t dm_nvram_size;
+       uint8_t dm_flags;
+#define        DSRTC_FLAG_CLOCK_HOLD   1
+#define        DSRTC_FLAG_BCD          2       
+};
+
+static const struct dsrtc_model dsrtc_models[] = {
+       {
+               .dm_model = 1307,
+               .dm_ch_reg = DSXXXX_SECONDS,
+               .dm_ch_value = DS1307_SECONDS_CH,
+               .dm_rtc_start = DS1307_RTC_START,
+               .dm_rtc_size = DS1307_RTC_SIZE,
+               .dm_nvram_start = DS1307_NVRAM_START,
+               .dm_nvram_size = DS1307_NVRAM_SIZE,
+               .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD,
+       }, {
+               .dm_model = 1339,
+               .dm_rtc_start = DS1339_RTC_START,
+               .dm_rtc_size = DS1339_RTC_SIZE,
+               .dm_flags = DSRTC_FLAG_BCD,
+       }, {
+               .dm_model = 1672,
+               .dm_rtc_start = DS1672_RTC_START,
+               .dm_rtc_size = DS1672_RTC_SIZE,
+               .dm_flags = 0,
+       }, {
+               .dm_model = 3232,
+               .dm_rtc_start = DS3232_RTC_START,
+               .dm_rtc_size = DS3232_RTC_SIZE,
+               .dm_nvram_start = DS3232_NVRAM_START,
+               .dm_nvram_size = DS3232_NVRAM_SIZE,
+               .dm_flags = DSRTC_FLAG_BCD,
+       },
+};
+
 struct dsrtc_softc {
        device_t sc_dev;
        i2c_tag_t sc_tag;
-       int sc_address;
-       int sc_open;
+       uint8_t sc_address;
+       bool sc_open;
+       struct dsrtc_model sc_model;
        struct todr_chip_handle sc_todr;
 };
 
@@ -77,10 +121,30 @@
        nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
 };
 
-static int dsrtc_clock_read(struct dsrtc_softc *, struct clock_ymdhms *);
-static int dsrtc_clock_write(struct dsrtc_softc *, struct clock_ymdhms *);
-static int dsrtc_gettime(struct todr_chip_handle *, struct clock_ymdhms *);
-static int dsrtc_settime(struct todr_chip_handle *, struct clock_ymdhms *);
+static int dsrtc_gettime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *);
+static int dsrtc_settime_ymdhms(struct todr_chip_handle *, struct clock_ymdhms *);
+static int dsrtc_clock_read_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *);
+static int dsrtc_clock_write_ymdhms(struct dsrtc_softc *, struct clock_ymdhms *);
+
+static int dsrtc_gettime_timeval(struct todr_chip_handle *, struct timeval *);
+static int dsrtc_settime_timeval(struct todr_chip_handle *, struct timeval *);
+static int dsrtc_clock_read_timeval(struct dsrtc_softc *, time_t *);
+static int dsrtc_clock_write_timeval(struct dsrtc_softc *, time_t);
+
+static const struct dsrtc_model *
+dsrtc_model(u_int model)
+{
+       /* no model given, assume it's a DS1307 (the first one) */
+       if (model == 0)
+               return &dsrtc_models[0];
+
+       for (const struct dsrtc_model *dm = dsrtc_models;
+            dm < dsrtc_models + __arraycount(dsrtc_models); dm++) {
+               if (dm->dm_model == model)
+                       return dm;
+       }
+       return NULL;
+}
 
 static int
 dsrtc_match(device_t parent, cfdata_t cf, void *arg)
@@ -94,7 +158,7 @@
        } else {
                /* indirect config - check typical address */
                if (ia->ia_addr == DS1307_ADDR)
-                       return 1;
+                       return dsrtc_model(cf->cf_flags & 0xffff) != NULL;
        }
        return 0;
 }
@@ -104,19 +168,27 @@
 {
        struct dsrtc_softc *sc = device_private(self);
        struct i2c_attach_args *ia = arg;
+       const struct dsrtc_model * const dm =
+           dsrtc_model(device_cfdata(self)->cf_flags);
 
-       aprint_naive(": Real-time Clock/NVRAM\n");
-       aprint_normal(": DS1307 Real-time Clock/NVRAM\n");
+       aprint_naive(": Real-time Clock%s\n",
+           dm->dm_nvram_size > 0 ? "/NVRAM" : "");
+       aprint_normal(": DS%u Real-time Clock%s\n", dm->dm_model,
+           dm->dm_nvram_size > 0 ? "/NVRAM" : "");
 
        sc->sc_tag = ia->ia_tag;
        sc->sc_address = ia->ia_addr;
+       sc->sc_model = *dm;
        sc->sc_dev = self;
        sc->sc_open = 0;
        sc->sc_todr.cookie = sc;
-       sc->sc_todr.todr_gettime = NULL;
-       sc->sc_todr.todr_settime = NULL;
-       sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime;
-       sc->sc_todr.todr_settime_ymdhms = dsrtc_settime;
+       if (dm->dm_flags & DSRTC_FLAG_BCD) {
+               sc->sc_todr.todr_gettime_ymdhms = dsrtc_gettime_ymdhms;
+               sc->sc_todr.todr_settime_ymdhms = dsrtc_settime_ymdhms;
+       } else {
+               sc->sc_todr.todr_gettime = dsrtc_gettime_timeval;
+               sc->sc_todr.todr_settime = dsrtc_settime_timeval;
+       }
        sc->sc_todr.todr_setwen = NULL;
 
        todr_attach(&sc->sc_todr);
@@ -132,11 +204,10 @@
                return ENXIO;
 
        /* XXX: Locking */
-
        if (sc->sc_open)
                return EBUSY;
 
-       sc->sc_open = 1;
+       sc->sc_open = true;
        return 0;
 }
 
@@ -149,7 +220,7 @@
        if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL)
                return ENXIO;
 
-       sc->sc_open = 0;
+       sc->sc_open = false;
        return 0;
 }
 
@@ -158,24 +229,26 @@
 dsrtc_read(dev_t dev, struct uio *uio, int flags)
 {
        struct dsrtc_softc *sc;
-       u_int8_t ch, cmdbuf[1];
-       int a, error;
+       int error;
 
        if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL)
                return ENXIO;
 
-       if (uio->uio_offset >= DS1307_NVRAM_SIZE)
+       const struct dsrtc_model * const dm = &sc->sc_model;
+       if (uio->uio_offset >= dm->dm_nvram_size)
                return EINVAL;
 
        if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
                return error;
 
-       while (uio->uio_resid && uio->uio_offset < DS1307_NVRAM_SIZE) {
-               a = (int)uio->uio_offset;
-               cmdbuf[0] = a + DS1307_NVRAM_START;
-               if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
-                                     sc->sc_address, cmdbuf, 1,
-                                     &ch, 1, 0)) != 0) {
+       KASSERT(uio->uio_offset >= 0);
+       while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) {
+               uint8_t ch, cmd;
+               const u_int a = uio->uio_offset;
+               cmd = a + dm->dm_nvram_start;
+               if ((error = iic_exec(sc->sc_tag,
+                   uio->uio_resid > 1 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP,
+                   sc->sc_address, &cmd, 1, &ch, 1, 0)) != 0) {
                        iic_release_bus(sc->sc_tag, 0);
                        aprint_error_dev(sc->sc_dev,
                            "dsrtc_read: read failed at 0x%x\n", a);
@@ -197,21 +270,22 @@
 dsrtc_write(dev_t dev, struct uio *uio, int flags)
 {
        struct dsrtc_softc *sc;
-       u_int8_t cmdbuf[2];
-       int a, error;
+       int error;
 
        if ((sc = device_lookup_private(&dsrtc_cd, minor(dev))) == NULL)
                return ENXIO;
 
-       if (uio->uio_offset >= DS1307_NVRAM_SIZE)
+       const struct dsrtc_model * const dm = &sc->sc_model;
+       if (uio->uio_offset >= dm->dm_nvram_size)
                return EINVAL;
 
        if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
                return error;
 
-       while (uio->uio_resid && uio->uio_offset < DS1307_NVRAM_SIZE) {
-               a = (int)uio->uio_offset;
-               cmdbuf[0] = a + DS1307_NVRAM_START;
+       while (uio->uio_resid && uio->uio_offset < dm->dm_nvram_size) {
+               uint8_t cmdbuf[2];
+               const u_int a = (int)uio->uio_offset;
+               cmdbuf[0] = a + dm->dm_nvram_start;
                if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0)
                        break;
 
@@ -230,7 +304,7 @@
 }
 
 static int
-dsrtc_gettime(struct todr_chip_handle *ch, struct clock_ymdhms *dt)
+dsrtc_gettime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt)
 {
        struct dsrtc_softc *sc = ch->cookie;
        struct clock_ymdhms check;
@@ -245,29 +319,31 @@
         */
        retries = 5;
        do {
-               dsrtc_clock_read(sc, dt);
-               dsrtc_clock_read(sc, &check);
+               dsrtc_clock_read_ymdhms(sc, dt);
+               dsrtc_clock_read_ymdhms(sc, &check);
        } while (memcmp(dt, &check, sizeof(check)) != 0 && --retries);
 
        return 0;
 }
 
 static int
-dsrtc_settime(struct todr_chip_handle *ch, struct clock_ymdhms *dt)
+dsrtc_settime_ymdhms(struct todr_chip_handle *ch, struct clock_ymdhms *dt)
 {
        struct dsrtc_softc *sc = ch->cookie;
 
-       if (dsrtc_clock_write(sc, dt) == 0)
+       if (dsrtc_clock_write_ymdhms(sc, dt) == 0)
                return -1;
 
        return 0;
 }
 
 static int
-dsrtc_clock_read(struct dsrtc_softc *sc, struct clock_ymdhms *dt)
+dsrtc_clock_read_ymdhms(struct dsrtc_softc *sc, struct clock_ymdhms *dt)
 {
-       u_int8_t bcd[DS1307_NRTC_REGS], cmdbuf[1];
-       int i;
+       struct dsrtc_model * const dm = &sc->sc_model;
+       uint8_t bcd[DSXXXX_RTC_SIZE], cmdbuf[1];
+
+       KASSERT(DSXXXX_RTC_SIZE >= dm->dm_rtc_size);
 
        if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
                aprint_error_dev(sc->sc_dev,
@@ -276,8 +352,8 @@
        }
 
        /* Read each RTC register in order. */
-       for (i = DS1307_SECONDS; i < DS1307_NRTC_REGS; i++) {
-               cmdbuf[0] = i;
+       for (u_int i = 0; i < dm->dm_rtc_size; i++) {
+               cmdbuf[0] = dm->dm_rtc_start + i;
 
                if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                             sc->sc_address, cmdbuf, 1,



Home | Main Index | Thread Index | Old Index