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.8 2008/05/04 19:43:06 martin 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.8 2008/05/04 19:43:06 martin 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 
   65         aprint_naive("\n");
   66         aprint_normal(": real time clock\n");
   67 
   68         sc->sc_todr.cookie = sc;
   69         sc->sc_todr.todr_gettime_ymdhms = rs5c313_todr_gettime_ymdhms;
   70         sc->sc_todr.todr_settime_ymdhms = rs5c313_todr_settime_ymdhms;
   71 
   72         if (rs5c313_init(sc) != 0) {
   73                 aprint_error_dev(self, "init failed\n");
   74                 return;
   75         }
   76 
   77         todr_attach(&sc->sc_todr);
   78 }
   79 
   80 
   81 static int
   82 rs5c313_init(struct rs5c313_softc *sc)
   83 {
   84         device_t self = sc->sc_dev;
   85         int status = 0;
   86         int retry;
   87 
   88         rtc_ce(sc, 0);
   89 
   90         rtc_begin(sc);
   91         rtc_ce(sc, 1);
   92 
   93         if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_XSTP) == 0) {
   94                 sc->sc_valid = 1;
   95                 goto done;
   96         }
   97 
   98         sc->sc_valid = 0;
   99         aprint_error_dev(self, "time not valid\n");
  100 
  101         rs5c313_write_reg(sc, RS5C313_TINT, 0);
  102         rs5c313_write_reg(sc, RS5C313_CTRL, (CTRL_BASE | CTRL_ADJ));
  103 
  104         for (retry = 1000; retry > 0; --retry) {
  105                 if (rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY)
  106                         delay(1);
  107                 else
  108                         break;
  109         }
  110 
  111         if (retry == 0) {
  112                 status = EIO;
  113                 goto done;
  114         }
  115 
  116         rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  117 
  118   done:
  119         rtc_ce(sc, 0);
  120         return status;
  121 }
  122 
  123 
  124 static int
  125 rs5c313_todr_gettime_ymdhms(todr_chip_handle_t todr, struct clock_ymdhms *dt)
  126 {
  127         struct rs5c313_softc *sc = todr->cookie;
  128         int retry;
  129         int s;
  130 
  131         /*
  132          * If chip had invalid data on init, don't bother reading
  133          * bogus values, let todr(9) cope.
  134          */
  135         if (sc->sc_valid == 0)
  136                 return EIO;
  137 
  138         s = splhigh();
  139 
  140         rtc_begin(sc);
  141         for (retry = 10; retry > 0; --retry) {
  142                 rtc_ce(sc, 1);
  143 
  144                 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  145                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  146                         break;
  147 
  148                 rtc_ce(sc, 0);
  149                 delay(1);
  150         }
  151 
  152         if (retry == 0) {
  153                 splx(s);
  154                 return EIO;
  155         }
  156 
  157 #define RTCGET(x, y)                                                    \
  158         do {                                                            \
  159                 int ones = rs5c313_read_reg(sc, RS5C313_ ## y ## 1);    \
  160                 int tens = rs5c313_read_reg(sc, RS5C313_ ## y ## 10);   \
  161                 dt->dt_ ## x = tens * 10 + ones;                        \
  162         } while (/* CONSTCOND */0)
  163 
  164         RTCGET(sec, SEC);
  165         RTCGET(min, MIN);
  166         RTCGET(hour, HOUR);
  167         RTCGET(day, DAY);
  168         RTCGET(mon, MON);
  169         RTCGET(year, YEAR);
  170 #undef  RTCGET
  171         dt->dt_wday = rs5c313_read_reg(sc, RS5C313_WDAY);
  172 
  173         rtc_ce(sc, 0);
  174         splx(s);
  175 
  176 
  177         dt->dt_year = (dt->dt_year % 100) + 1900;
  178         if (dt->dt_year < POSIX_BASE_YEAR) {
  179                 dt->dt_year += 100;
  180         }
  181 
  182         return 0;
  183 }
  184 
  185 
  186 static int
  187 rs5c313_todr_settime_ymdhms(todr_chip_handle_t todr, struct clock_ymdhms *dt)
  188 {
  189         struct rs5c313_softc *sc = todr->cookie;
  190         int retry;
  191         int t;
  192         int s;
  193 
  194         s = splhigh();
  195 
  196         rtc_begin(sc);
  197         for (retry = 10; retry > 0; --retry) {
  198                 rtc_ce(sc, 1);
  199 
  200                 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  201                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  202                         break;
  203 
  204                 rtc_ce(sc, 0);
  205                 delay(1);
  206         }
  207 
  208         if (retry == 0) {
  209                 splx(s);
  210                 return EIO;
  211         }
  212 
  213 #define RTCSET(x, y)                                                         \
  214         do {                                                                 \
  215                 t = TOBCD(dt->dt_ ## y) & 0xff;                              \
  216                 rs5c313_write_reg(sc, RS5C313_ ## x ## 1, t & 0x0f);         \
  217                 rs5c313_write_reg(sc, RS5C313_ ## x ## 10, (t >> 4) & 0x0f); \
  218         } while (/* CONSTCOND */0)
  219 
  220         RTCSET(SEC, sec);
  221         RTCSET(MIN, min);
  222         RTCSET(HOUR, hour);
  223         RTCSET(DAY, day);
  224         RTCSET(MON, mon);
  225 
  226 #undef  RTCSET
  227 
  228         t = dt->dt_year % 100;
  229         t = TOBCD(t);
  230         rs5c313_write_reg(sc, RS5C313_YEAR1, t & 0x0f);
  231         rs5c313_write_reg(sc, RS5C313_YEAR10, (t >> 4) & 0x0f);
  232 
  233         rs5c313_write_reg(sc, RS5C313_WDAY, dt->dt_wday);
  234 
  235         rtc_ce(sc, 0);
  236         splx(s);
  237 
  238         sc->sc_valid = 1;
  239         return 0;
  240 }
  241 
  242 
  243 static int
  244 rs5c313_read_reg(struct rs5c313_softc *sc, int addr)
  245 {
  246         int data;
  247 
  248         /* output */
  249         rtc_dir(sc, 1);
  250 
  251         /* control */
  252         rtc_do(sc, 1);          /* ignored */
  253         rtc_do(sc, 1);          /* R/#W = 1(READ) */
  254         rtc_do(sc, 1);          /* AD = 1 */
  255         rtc_do(sc, 0);          /* DT = 0 */
  256 
  257         /* address */
  258         rtc_do(sc, addr & 0x8); /* A3 */
  259         rtc_do(sc, addr & 0x4); /* A2 */
  260         rtc_do(sc, addr & 0x2); /* A1 */
  261         rtc_do(sc, addr & 0x1); /* A0 */
  262 
  263         /* input */
  264         rtc_dir(sc, 0);
  265 
  266         /* ignore */
  267         (void)rtc_di(sc);
  268         (void)rtc_di(sc);
  269         (void)rtc_di(sc);
  270         (void)rtc_di(sc);
  271 
  272         /* data */
  273         data = rtc_di(sc);      /* D3 */
  274         data <<= 1;
  275         data |= rtc_di(sc);     /* D2 */
  276         data <<= 1;
  277         data |= rtc_di(sc);     /* D1 */
  278         data <<= 1;
  279         data |= rtc_di(sc);     /* D0 */
  280 
  281         return data;
  282 }
  283 
  284 
  285 static void
  286 rs5c313_write_reg(struct rs5c313_softc *sc, int addr, int data)
  287 {
  288 
  289         /* output */
  290         rtc_dir(sc, 1);
  291 
  292         /* control */
  293         rtc_do(sc, 1);          /* ignored */
  294         rtc_do(sc, 0);          /* R/#W = 0 (WRITE) */
  295         rtc_do(sc, 1);          /* AD = 1 */
  296         rtc_do(sc, 0);          /* DT = 0 */
  297 
  298         /* address */
  299         rtc_do(sc, addr & 0x8); /* A3 */
  300         rtc_do(sc, addr & 0x4); /* A2 */
  301         rtc_do(sc, addr & 0x2); /* A1 */
  302         rtc_do(sc, addr & 0x1); /* A0 */
  303 
  304         /* control */
  305         rtc_do(sc, 1);          /* ignored */
  306         rtc_do(sc, 0);          /* R/#W = 0(WRITE) */
  307         rtc_do(sc, 0);          /* AD = 0 */
  308         rtc_do(sc, 1);          /* DT = 1 */
  309 
  310         /* data */
  311         rtc_do(sc, data & 0x8); /* D3 */
  312         rtc_do(sc, data & 0x4); /* D2 */
  313         rtc_do(sc, data & 0x2); /* D1 */
  314         rtc_do(sc, data & 0x1); /* D0 */
  315 }

Cache object: 575a3692c6856ebbac3784c8b9e83240


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