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/ic/rs5c313.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: rs5c313.c,v 1.10 2014/11/20 16:34:26 christos Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: rs5c313.c,v 1.10 2014/11/20 16:34:26 christos Exp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/device.h>
   35 #include <sys/kernel.h>
   36 
   37 #include <dev/clock_subr.h>
   38 
   39 #include <dev/ic/rs5c313reg.h>
   40 #include <dev/ic/rs5c313var.h>
   41 
   42 
   43 /* todr(9) methods */
   44 static int rs5c313_todr_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
   45 static int rs5c313_todr_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
   46 
   47 /* sugar for chip access */
   48 #define rtc_begin(sc)           ((*sc->sc_ops->rs5c313_op_begin)(sc))
   49 #define rtc_ce(sc, onoff)       ((*sc->sc_ops->rs5c313_op_ce)(sc, onoff))
   50 #define rtc_clk(sc, onoff)      ((*sc->sc_ops->rs5c313_op_clk)(sc, onoff))
   51 #define rtc_dir(sc, output)     ((*sc->sc_ops->rs5c313_op_dir)(sc, output))
   52 #define rtc_di(sc)              ((*sc->sc_ops->rs5c313_op_read)(sc))
   53 #define rtc_do(sc, bit)         ((*sc->sc_ops->rs5c313_op_write)(sc, bit))
   54 
   55 static int rs5c313_init(struct rs5c313_softc *);
   56 static int rs5c313_read_reg(struct rs5c313_softc *, int);
   57 static void rs5c313_write_reg(struct rs5c313_softc *, int, int);
   58 
   59 
   60 void
   61 rs5c313_attach(struct rs5c313_softc *sc)
   62 {
   63         device_t self = sc->sc_dev;
   64         const char *model;
   65 
   66         switch (sc->sc_model) {
   67         case MODEL_5C313:
   68                 model = "5C313";
   69                 sc->sc_ctrl[0] = CTRL_24H;
   70                 sc->sc_ctrl[1] = CTRL2_NTEST;
   71                 break;
   72 
   73         case MODEL_5C316:
   74                 model = "5C316";
   75                 sc->sc_ctrl[0] = 0;
   76                 sc->sc_ctrl[1] = CTRL2_24H|CTRL2_NTEST;
   77                 break;
   78         
   79         default:
   80                 aprint_error("unknown model (%d)\n", sc->sc_model);
   81                 return;
   82         }
   83 
   84         aprint_naive("\n");
   85         aprint_normal(": RICOH %s real time clock\n", model);
   86 
   87         sc->sc_todr.cookie = sc;
   88         sc->sc_todr.todr_gettime_ymdhms = rs5c313_todr_gettime_ymdhms;
   89         sc->sc_todr.todr_settime_ymdhms = rs5c313_todr_settime_ymdhms;
   90 
   91         if (rs5c313_init(sc) != 0) {
   92                 aprint_error_dev(self, "init failed\n");
   93                 return;
   94         }
   95 
   96         todr_attach(&sc->sc_todr);
   97 }
   98 
   99 
  100 static int
  101 rs5c313_init(struct rs5c313_softc *sc)
  102 {
  103         device_t self = sc->sc_dev;
  104         int status = 0;
  105         int retry;
  106 
  107         rtc_ce(sc, 0);
  108 
  109         rtc_begin(sc);
  110         rtc_ce(sc, 1);
  111 
  112         if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_XSTP) == 0) {
  113                 sc->sc_valid = 1;
  114                 goto done;
  115         }
  116 
  117         sc->sc_valid = 0;
  118         aprint_error_dev(self, "time not valid\n");
  119 
  120         rs5c313_write_reg(sc, RS5C313_TINT, 0);
  121         rs5c313_write_reg(sc, RS5C313_CTRL, (sc->sc_ctrl[0] | CTRL_ADJ));
  122 
  123         for (retry = 1000; retry > 0; --retry) {
  124                 if (rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY)
  125                         delay(1);
  126                 else
  127                         break;
  128         }
  129         if (retry == 0) {
  130                 status = EIO;
  131                 goto done;
  132         }
  133 
  134         rs5c313_write_reg(sc, RS5C313_CTRL, sc->sc_ctrl[0]);
  135         rs5c313_write_reg(sc, RS5C313_CTRL2, sc->sc_ctrl[1]);
  136 
  137   done:
  138         rtc_ce(sc, 0);
  139         return status;
  140 }
  141 
  142 
  143 static int
  144 rs5c313_todr_gettime_ymdhms(todr_chip_handle_t todr, struct clock_ymdhms *dt)
  145 {
  146         struct rs5c313_softc *sc = todr->cookie;
  147         int retry;
  148         int s;
  149 
  150         /*
  151          * If chip had invalid data on init, don't bother reading
  152          * bogus values, let todr(9) cope.
  153          */
  154         if (sc->sc_valid == 0)
  155                 return EIO;
  156 
  157         s = splhigh();
  158 
  159         rtc_begin(sc);
  160         for (retry = 10; retry > 0; --retry) {
  161                 rtc_ce(sc, 1);
  162 
  163                 rs5c313_write_reg(sc, RS5C313_CTRL, sc->sc_ctrl[0]);
  164                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  165                         break;
  166 
  167                 rtc_ce(sc, 0);
  168                 delay(1);
  169         }
  170         if (retry == 0) {
  171                 splx(s);
  172                 return EIO;
  173         }
  174 
  175 #define RTCGET(x, y)                                                    \
  176         do {                                                            \
  177                 int ones = rs5c313_read_reg(sc, RS5C313_ ## y ## 1);    \
  178                 int tens = rs5c313_read_reg(sc, RS5C313_ ## y ## 10);   \
  179                 dt->dt_ ## x = tens * 10 + ones;                        \
  180         } while (/* CONSTCOND */0)
  181 
  182         RTCGET(sec, SEC);
  183         RTCGET(min, MIN);
  184         RTCGET(hour, HOUR);
  185         RTCGET(day, DAY);
  186         RTCGET(mon, MON);
  187         RTCGET(year, YEAR);
  188 #undef  RTCGET
  189         dt->dt_wday = rs5c313_read_reg(sc, RS5C313_WDAY);
  190 
  191         rtc_ce(sc, 0);
  192         splx(s);
  193 
  194         dt->dt_year = (dt->dt_year % 100) + 1900;
  195         if (dt->dt_year < POSIX_BASE_YEAR) {
  196                 dt->dt_year += 100;
  197         }
  198 
  199         return 0;
  200 }
  201 
  202 
  203 static int
  204 rs5c313_todr_settime_ymdhms(todr_chip_handle_t todr, struct clock_ymdhms *dt)
  205 {
  206         struct rs5c313_softc *sc = todr->cookie;
  207         int retry;
  208         int t;
  209         int s;
  210 
  211         s = splhigh();
  212 
  213         rtc_begin(sc);
  214         for (retry = 10; retry > 0; --retry) {
  215                 rtc_ce(sc, 1);
  216 
  217                 rs5c313_write_reg(sc, RS5C313_CTRL, sc->sc_ctrl[0]);
  218                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  219                         break;
  220 
  221                 rtc_ce(sc, 0);
  222                 delay(1);
  223         }
  224 
  225         if (retry == 0) {
  226                 splx(s);
  227                 return EIO;
  228         }
  229 
  230 #define RTCSET(x, y)                                                         \
  231         do {                                                                 \
  232                 t = bintobcd(dt->dt_ ## y) & 0xff;                                   \
  233                 rs5c313_write_reg(sc, RS5C313_ ## x ## 1, t & 0x0f);         \
  234                 rs5c313_write_reg(sc, RS5C313_ ## x ## 10, (t >> 4) & 0x0f); \
  235         } while (/* CONSTCOND */0)
  236 
  237         RTCSET(SEC, sec);
  238         RTCSET(MIN, min);
  239         RTCSET(HOUR, hour);
  240         RTCSET(DAY, day);
  241         RTCSET(MON, mon);
  242 
  243 #undef  RTCSET
  244 
  245         t = dt->dt_year % 100;
  246         t = bintobcd(t);
  247         rs5c313_write_reg(sc, RS5C313_YEAR1, t & 0x0f);
  248         rs5c313_write_reg(sc, RS5C313_YEAR10, (t >> 4) & 0x0f);
  249 
  250         rs5c313_write_reg(sc, RS5C313_WDAY, dt->dt_wday);
  251 
  252         rtc_ce(sc, 0);
  253         splx(s);
  254 
  255         sc->sc_valid = 1;
  256         return 0;
  257 }
  258 
  259 
  260 static int
  261 rs5c313_read_reg(struct rs5c313_softc *sc, int addr)
  262 {
  263         int data;
  264 
  265         /* output */
  266         rtc_dir(sc, 1);
  267 
  268         /* control */
  269         rtc_do(sc, 1);          /* ignored */
  270         rtc_do(sc, 1);          /* R/#W = 1(READ) */
  271         rtc_do(sc, 1);          /* AD = 1 */
  272         rtc_do(sc, 0);          /* DT = 0 */
  273 
  274         /* address */
  275         rtc_do(sc, addr & 0x8); /* A3 */
  276         rtc_do(sc, addr & 0x4); /* A2 */
  277         rtc_do(sc, addr & 0x2); /* A1 */
  278         rtc_do(sc, addr & 0x1); /* A0 */
  279 
  280         /* input */
  281         rtc_dir(sc, 0);
  282 
  283         /* ignore */
  284         (void)rtc_di(sc);
  285         (void)rtc_di(sc);
  286         (void)rtc_di(sc);
  287         (void)rtc_di(sc);
  288 
  289         /* data */
  290         data = rtc_di(sc);      /* D3 */
  291         data <<= 1;
  292         data |= rtc_di(sc);     /* D2 */
  293         data <<= 1;
  294         data |= rtc_di(sc);     /* D1 */
  295         data <<= 1;
  296         data |= rtc_di(sc);     /* D0 */
  297 
  298         return data;
  299 }
  300 
  301 
  302 static void
  303 rs5c313_write_reg(struct rs5c313_softc *sc, int addr, int data)
  304 {
  305 
  306         /* output */
  307         rtc_dir(sc, 1);
  308 
  309         /* control */
  310         rtc_do(sc, 1);          /* ignored */
  311         rtc_do(sc, 0);          /* R/#W = 0 (WRITE) */
  312         rtc_do(sc, 1);          /* AD = 1 */
  313         rtc_do(sc, 0);          /* DT = 0 */
  314 
  315         /* address */
  316         rtc_do(sc, addr & 0x8); /* A3 */
  317         rtc_do(sc, addr & 0x4); /* A2 */
  318         rtc_do(sc, addr & 0x2); /* A1 */
  319         rtc_do(sc, addr & 0x1); /* A0 */
  320 
  321         /* control */
  322         rtc_do(sc, 1);          /* ignored */
  323         rtc_do(sc, 0);          /* R/#W = 0(WRITE) */
  324         rtc_do(sc, 0);          /* AD = 0 */
  325         rtc_do(sc, 1);          /* DT = 1 */
  326 
  327         /* data */
  328         rtc_do(sc, data & 0x8); /* D3 */
  329         rtc_do(sc, data & 0x4); /* D2 */
  330         rtc_do(sc, data & 0x2); /* D1 */
  331         rtc_do(sc, data & 0x1); /* D0 */
  332 }

Cache object: c8a6cc783eea92b3ed7740acc286ea71


[ 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.