The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/i2c/max6900.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: max6900.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc.
    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 for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/device.h>
   41 #include <sys/kernel.h>
   42 #include <sys/fcntl.h>
   43 #include <sys/uio.h>
   44 #include <sys/conf.h>
   45 #include <sys/event.h>
   46 
   47 #include <dev/clock_subr.h>
   48 
   49 #include <dev/i2c/i2cvar.h>
   50 #include <dev/i2c/max6900reg.h>
   51 
   52 struct maxrtc_softc {
   53         struct device sc_dev;
   54         i2c_tag_t sc_tag;
   55         int sc_address;
   56         int sc_open;
   57         struct todr_chip_handle sc_todr;
   58 };
   59 
   60 static int  maxrtc_match(struct device *, struct cfdata *, void *);
   61 static void maxrtc_attach(struct device *, struct device *, void *);
   62 
   63 CFATTACH_DECL(maxrtc, sizeof(struct maxrtc_softc),
   64         maxrtc_match, maxrtc_attach, NULL, NULL);
   65 extern struct cfdriver maxrtc_cd;
   66 
   67 dev_type_open(maxrtc_open);
   68 dev_type_close(maxrtc_close);
   69 dev_type_read(maxrtc_read);
   70 dev_type_write(maxrtc_write);
   71 
   72 const struct cdevsw maxrtc_cdevsw = {
   73         maxrtc_open, maxrtc_close, maxrtc_read, maxrtc_write, noioctl,
   74         nostop, notty, nopoll, nommap, nokqfilter
   75 };
   76 
   77 static int maxrtc_clock_read(struct maxrtc_softc *, struct clock_ymdhms *);
   78 static int maxrtc_clock_write(struct maxrtc_softc *, struct clock_ymdhms *);
   79 static int maxrtc_gettime(struct todr_chip_handle *, struct timeval *);
   80 static int maxrtc_settime(struct todr_chip_handle *, struct timeval *);
   81 static int maxrtc_getcal(struct todr_chip_handle *, int *);
   82 static int maxrtc_setcal(struct todr_chip_handle *, int);
   83 
   84 int
   85 maxrtc_match(struct device *parent, struct cfdata *cf, void *aux)
   86 {
   87         struct i2c_attach_args *ia = aux;
   88 
   89         if ((ia->ia_addr & MAX6900_ADDRMASK) == MAX6900_ADDR)
   90                 return (1);
   91 
   92         return (0);
   93 }
   94 
   95 void
   96 maxrtc_attach(struct device *parent, struct device *self, void *aux)
   97 {
   98         struct maxrtc_softc *sc = (struct maxrtc_softc *)self;
   99         struct i2c_attach_args *ia = aux;
  100 
  101         sc->sc_tag = ia->ia_tag;
  102         sc->sc_address = ia->ia_addr;
  103 
  104         aprint_naive(": Real-time Clock/NVRAM\n");
  105         aprint_normal(": MAX6900 Real-time Clock/NVRAM\n");
  106 
  107         sc->sc_open = 0;
  108 
  109         sc->sc_todr.cookie = sc;
  110         sc->sc_todr.todr_gettime = maxrtc_gettime;
  111         sc->sc_todr.todr_settime = maxrtc_settime;
  112         sc->sc_todr.todr_getcal = maxrtc_getcal;
  113         sc->sc_todr.todr_setcal = maxrtc_setcal;
  114         sc->sc_todr.todr_setwen = NULL;
  115 
  116         todr_attach(&sc->sc_todr);
  117 }
  118 
  119 /*ARGSUSED*/
  120 int
  121 maxrtc_open(dev_t dev, int flag, int fmt, struct proc *p)
  122 {
  123         struct maxrtc_softc *sc;
  124 
  125         if ((sc = device_lookup(&maxrtc_cd, minor(dev))) == NULL)
  126                 return (ENXIO);
  127 
  128         /* XXX: Locking */
  129 
  130         if (sc->sc_open)
  131                 return (EBUSY);
  132 
  133         sc->sc_open = 1;
  134         return (0);
  135 }
  136 
  137 /*ARGSUSED*/
  138 int
  139 maxrtc_close(dev_t dev, int flag, int fmt, struct proc *p)
  140 {
  141         struct maxrtc_softc *sc;
  142 
  143         if ((sc = device_lookup(&maxrtc_cd, minor(dev))) == NULL)
  144                 return (ENXIO);
  145 
  146         sc->sc_open = 0;
  147         return (0);
  148 }
  149 
  150 /*ARGSUSED*/
  151 int
  152 maxrtc_read(dev_t dev, struct uio *uio, int flags)
  153 {
  154         struct maxrtc_softc *sc;
  155         u_int8_t ch, cmdbuf[1];
  156         int a, error;
  157 
  158         if ((sc = device_lookup(&maxrtc_cd, minor(dev))) == NULL)
  159                 return (ENXIO);
  160 
  161         if (uio->uio_offset >= MAX6900_RAM_BYTES)
  162                 return (EINVAL);
  163 
  164         if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
  165                 return (error);
  166 
  167         while (uio->uio_resid && uio->uio_offset < MAX6900_RAM_BYTES) {
  168                 a = (int)uio->uio_offset;
  169                 cmdbuf[0] = MAX6900_REG_RAM(a) | MAX6900_CMD_READ;
  170                 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  171                                       sc->sc_address, cmdbuf, 1,
  172                                       &ch, 1, 0)) != 0) {
  173                         iic_release_bus(sc->sc_tag, 0);
  174                         printf("%s: maxrtc_read: read failed at 0x%x\n",
  175                             sc->sc_dev.dv_xname, a);
  176                         return (error);
  177                 }
  178                 if ((error = uiomove(&ch, 1, uio)) != 0) {
  179                         iic_release_bus(sc->sc_tag, 0);
  180                         return (error);
  181                 }
  182         }
  183 
  184         iic_release_bus(sc->sc_tag, 0);
  185 
  186         return (0);
  187 }
  188 
  189 /*ARGSUSED*/
  190 int
  191 maxrtc_write(dev_t dev, struct uio *uio, int flags)
  192 {
  193         struct maxrtc_softc *sc;
  194         u_int8_t cmdbuf[2];
  195         int a, error, sverror;
  196 
  197         if ((sc = device_lookup(&maxrtc_cd, minor(dev))) == NULL)
  198                 return (ENXIO);
  199 
  200         if (uio->uio_offset >= MAX6900_RAM_BYTES)
  201                 return (EINVAL);
  202 
  203         if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
  204                 return (error);
  205 
  206         /* Start by clearing the control register's write-protect bit. */
  207         cmdbuf[0] = MAX6900_REG_CONTROL | MAX6900_CMD_WRITE;
  208         cmdbuf[1] = 0;
  209 
  210         if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address,
  211                               cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) {
  212                 iic_release_bus(sc->sc_tag, 0);
  213                 printf("%s: maxrtc_write: failed to clear WP bit\n",
  214                     sc->sc_dev.dv_xname);
  215                 return (error);
  216         }
  217 
  218         while (uio->uio_resid && uio->uio_offset < MAX6900_RAM_BYTES) {
  219                 a = (int)uio->uio_offset;
  220 
  221                 cmdbuf[0] = MAX6900_REG_RAM(a) | MAX6900_CMD_WRITE;
  222                 if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0)
  223                         break;
  224 
  225                 if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address,
  226                                       cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) {
  227                         printf("%s: maxrtc_write: write failed at 0x%x\n",
  228                             sc->sc_dev.dv_xname, a);
  229                         break;
  230                 }
  231         }
  232 
  233         /* Set the write-protect bit again. */
  234         cmdbuf[0] = MAX6900_REG_CONTROL | MAX6900_CMD_WRITE;
  235         cmdbuf[1] = MAX6900_CONTROL_WP;
  236 
  237         sverror = error;
  238         if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  239                               sc->sc_address, cmdbuf, 1,
  240                               &cmdbuf[1], 1, 0)) != 0) {
  241                 if (sverror != 0)
  242                         error = sverror;
  243                 printf("%s: maxrtc_write: failed to set WP bit\n",
  244                     sc->sc_dev.dv_xname);
  245         }
  246 
  247         iic_release_bus(sc->sc_tag, 0);
  248 
  249         return (error);
  250 }
  251 
  252 static int
  253 maxrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv)
  254 {
  255         struct maxrtc_softc *sc = ch->cookie;
  256         struct clock_ymdhms dt;
  257 
  258         if (maxrtc_clock_read(sc, &dt) == 0)
  259                 return (-1);
  260 
  261         tv->tv_sec = clock_ymdhms_to_secs(&dt);
  262         tv->tv_usec = 0;
  263 
  264         return (0);
  265 }
  266 
  267 static int
  268 maxrtc_settime(struct todr_chip_handle *ch, struct timeval *tv)
  269 {
  270         struct maxrtc_softc *sc = ch->cookie;
  271         struct clock_ymdhms dt;
  272 
  273         clock_secs_to_ymdhms(tv->tv_sec, &dt);
  274 
  275         if (maxrtc_clock_write(sc, &dt) == 0)
  276                 return (-1);
  277 
  278         return (0);
  279 }
  280 
  281 static int
  282 maxrtc_setcal(struct todr_chip_handle *ch, int cal)
  283 {
  284 
  285         return (EOPNOTSUPP);
  286 }
  287 
  288 static int
  289 maxrtc_getcal(struct todr_chip_handle *ch, int *cal)
  290 {
  291 
  292         return (EOPNOTSUPP);
  293 }
  294 
  295 /*
  296  * While the MAX6900 has a nice Clock Burst Read/Write command,
  297  * we can't use it, since some I2C controllers do not support
  298  * anything other than single-byte transfers.
  299  */
  300 static int max6900_rtc_offset[] = {
  301         MAX6900_REG_SECOND,
  302         MAX6900_REG_MINUTE,
  303         MAX6900_REG_HOUR,
  304         MAX6900_REG_DATE,
  305         MAX6900_REG_MONTH,
  306         MAX6900_REG_DAY,
  307         MAX6900_REG_YEAR,
  308         MAX6900_REG_CENTURY,    /* control, if burst */
  309 };
  310 
  311 static int
  312 maxrtc_clock_read(struct maxrtc_softc *sc, struct clock_ymdhms *dt)
  313 {
  314         u_int8_t bcd[MAX6900_BURST_LEN], cmdbuf[1];
  315         int i;
  316 
  317         if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
  318                 printf("%s: maxrtc_clock_read: failed to acquire I2C bus\n",
  319                     sc->sc_dev.dv_xname);
  320                 return (0);
  321         }
  322 
  323         /* Read each timekeeping register in order. */
  324         for (i = 0; i < MAX6900_BURST_LEN; i++) {
  325                 cmdbuf[0] = max6900_rtc_offset[i] | MAX6900_CMD_READ;
  326 
  327                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  328                              sc->sc_address, cmdbuf, 1,
  329                              &bcd[i], 1, I2C_F_POLL)) {
  330                         iic_release_bus(sc->sc_tag, I2C_F_POLL);
  331                         printf("%s: maxrtc_clock_read: failed to read rtc "
  332                             "at 0x%x\n", sc->sc_dev.dv_xname,
  333                             max6900_rtc_offset[i]);
  334                         return (0);
  335                 }
  336         }
  337 
  338         /* Done with I2C */
  339         iic_release_bus(sc->sc_tag, I2C_F_POLL);
  340 
  341         /*
  342          * Convert the MAX6900's register values into something useable
  343          */
  344         dt->dt_sec = FROMBCD(bcd[MAX6900_BURST_SECOND] & MAX6900_SECOND_MASK);
  345         dt->dt_min = FROMBCD(bcd[MAX6900_BURST_MINUTE] & MAX6900_MINUTE_MASK);
  346 
  347         if (bcd[MAX6900_BURST_HOUR] & MAX6900_HOUR_12HRS) {
  348                 dt->dt_hour = FROMBCD(bcd[MAX6900_BURST_HOUR] &
  349                     MAX6900_HOUR_12MASK);
  350                 if (bcd[MAX6900_BURST_HOUR] & MAX6900_HOUR_12HRS_PM)
  351                         dt->dt_hour += 12;
  352         } else {
  353                 dt->dt_hour = FROMBCD(bcd[MAX6900_BURST_HOUR] &
  354                     MAX6900_HOUR_24MASK);
  355         }
  356 
  357         dt->dt_day = FROMBCD(bcd[MAX6900_BURST_DATE] & MAX6900_DATE_MASK);
  358         dt->dt_mon = FROMBCD(bcd[MAX6900_BURST_MONTH] & MAX6900_MONTH_MASK);
  359         dt->dt_year = FROMBCD(bcd[MAX6900_BURST_YEAR]);
  360                 /* century in the burst control slot */
  361         dt->dt_year += (int)FROMBCD(bcd[MAX6900_BURST_CONTROL]) * 100;
  362 
  363         return (1);
  364 }
  365 
  366 static int
  367 maxrtc_clock_write(struct maxrtc_softc *sc, struct clock_ymdhms *dt)
  368 {
  369         uint8_t bcd[MAX6900_BURST_LEN], cmdbuf[2];
  370         uint8_t init_seconds, final_seconds;
  371         int i;
  372 
  373         /*
  374          * Convert our time representation into something the MAX6900
  375          * can understand.
  376          */
  377         bcd[MAX6900_BURST_SECOND] = TOBCD(dt->dt_sec);
  378         bcd[MAX6900_BURST_MINUTE] = TOBCD(dt->dt_min);
  379         bcd[MAX6900_BURST_HOUR] = TOBCD(dt->dt_hour) & MAX6900_HOUR_24MASK;
  380         bcd[MAX6900_BURST_DATE] = TOBCD(dt->dt_day);
  381         bcd[MAX6900_BURST_WDAY] = TOBCD(dt->dt_wday);
  382         bcd[MAX6900_BURST_MONTH] = TOBCD(dt->dt_mon);
  383         bcd[MAX6900_BURST_YEAR] = TOBCD(dt->dt_year % 100);
  384                 /* century in control slot */
  385         bcd[MAX6900_BURST_CONTROL] = TOBCD(dt->dt_year / 100);
  386 
  387         if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
  388                 printf("%s: maxrtc_clock_write: failed to acquire I2C bus\n",
  389                     sc->sc_dev.dv_xname);
  390                 return (0);
  391         }
  392 
  393         /* Start by clearing the control register's write-protect bit. */
  394         cmdbuf[0] = MAX6900_REG_CONTROL | MAX6900_CMD_WRITE;
  395         cmdbuf[1] = 0;
  396 
  397         if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address,
  398                      cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) {
  399                 iic_release_bus(sc->sc_tag, I2C_F_POLL);
  400                 printf("%s: maxrtc_clock_write: failed to clear WP bit\n",
  401                     sc->sc_dev.dv_xname);
  402                 return (0);
  403         }
  404 
  405         /*
  406          * The MAX6900 RTC manual recommends ensuring "atomicity" of
  407          * a non-burst write by:
  408          *
  409          *      - writing SECONDS
  410          *      - reading back SECONDS, remembering it as "initial seconds"
  411          *      - write the remaing RTC registers
  412          *      - read back SECONDS as "final seconds"
  413          *      - if "initial seconds" == 59, ensure "final seconds" == 59
  414          *      - else, ensure "final seconds" is no more than one second
  415          *        beyond "initial seconds".
  416          */
  417  again:
  418         cmdbuf[0] = MAX6900_REG_SECOND | MAX6900_CMD_WRITE;
  419         if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address,
  420                      cmdbuf, 1, &bcd[MAX6900_BURST_SECOND], 1, I2C_F_POLL)) {
  421                 iic_release_bus(sc->sc_tag, I2C_F_POLL);
  422                 printf("%s: maxrtc_clock_write: failed to write SECONDS\n",
  423                     sc->sc_dev.dv_xname);
  424                 return (0);
  425         }
  426 
  427         cmdbuf[0] = MAX6900_REG_SECOND | MAX6900_CMD_READ;
  428         if (iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address,
  429                      cmdbuf, 1, &init_seconds, 1, I2C_F_POLL)) {
  430                 iic_release_bus(sc->sc_tag, I2C_F_POLL);
  431                 printf("%s: maxrtc_clock_write: failed to read "
  432                     "INITIAL SECONDS\n", sc->sc_dev.dv_xname);
  433                 return (0);
  434         }
  435 
  436         for (i = 1; i < MAX6900_BURST_LEN; i++) {
  437                 cmdbuf[0] = max6900_rtc_offset[i] | MAX6900_CMD_WRITE;
  438                 if (iic_exec(sc->sc_tag,
  439                              i != MAX6900_BURST_LEN - 1 ? I2C_OP_WRITE :
  440                              I2C_OP_WRITE_WITH_STOP, sc->sc_address,
  441                              cmdbuf, 1, &bcd[i], 1, I2C_F_POLL)) {
  442                         iic_release_bus(sc->sc_tag, I2C_F_POLL);
  443                         printf("%s: maxrtc_clock_write: failed to write rtc "
  444                             " at 0x%x\n", sc->sc_dev.dv_xname,
  445                             max6900_rtc_offset[i]);
  446                         return (0);
  447                 }
  448         }
  449 
  450         cmdbuf[0] = MAX6900_REG_SECOND | MAX6900_CMD_READ;
  451         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address,
  452                      cmdbuf, 1, &final_seconds, 1, I2C_F_POLL)) {
  453                 iic_release_bus(sc->sc_tag, I2C_F_POLL);
  454                 printf("%s: maxrtc_clock_write: failed to read "
  455                     "FINAL SECONDS\n", sc->sc_dev.dv_xname);
  456                 return (0);
  457         }
  458 
  459         if ((init_seconds == 59 && final_seconds != 59) ||
  460             (init_seconds != 59 && final_seconds != init_seconds + 1)) {
  461 #if 1
  462                 printf("%s: maxrtc_clock_write: init %d, final %d, try again\n",
  463                     sc->sc_dev.dv_xname, init_seconds, final_seconds);
  464 #endif
  465                 goto again;
  466         }
  467 
  468         /* Finish by setting the control register's write-protect bit. */
  469         cmdbuf[0] = MAX6900_REG_CONTROL | MAX6900_CMD_WRITE;
  470         cmdbuf[1] = MAX6900_CONTROL_WP;
  471 
  472         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
  473                      cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) {
  474                 iic_release_bus(sc->sc_tag, I2C_F_POLL);
  475                 printf("%s: maxrtc_clock_write: failed to set WP bit\n",
  476                     sc->sc_dev.dv_xname);
  477                 return (0);
  478         }
  479 
  480         iic_release_bus(sc->sc_tag, I2C_F_POLL);
  481 
  482         return (1);
  483 }

Cache object: 28826b078853b086e77f4704c3c6b12f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.