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.1 2006/09/07 01:12:00 uwe 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  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *        This product includes software developed by the NetBSD
   18  *        Foundation, Inc. and its contributors.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: rs5c313.c,v 1.1 2006/09/07 01:12:00 uwe Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/device.h>
   39 #include <sys/kernel.h>
   40 
   41 #include <dev/clock_subr.h>
   42 
   43 #include <dev/ic/rs5c313reg.h>
   44 #include <dev/ic/rs5c313var.h>
   45 
   46 
   47 /* todr(9) methods */
   48 static int rs5c313_todr_gettime(todr_chip_handle_t, volatile struct timeval *);
   49 static int rs5c313_todr_settime(todr_chip_handle_t, volatile struct timeval *);
   50 
   51 /* sugar for chip access */
   52 #define rtc_begin(sc)           ((*sc->sc_ops->rs5c313_op_begin)(sc))
   53 #define rtc_ce(sc, onoff)       ((*sc->sc_ops->rs5c313_op_ce)(sc, onoff))
   54 #define rtc_clk(sc, onoff)      ((*sc->sc_ops->rs5c313_op_clk)(sc, onoff))
   55 #define rtc_dir(sc, output)     ((*sc->sc_ops->rs5c313_op_dir)(sc, output))
   56 #define rtc_di(sc)              ((*sc->sc_ops->rs5c313_op_read)(sc))
   57 #define rtc_do(sc, bit)         ((*sc->sc_ops->rs5c313_op_write)(sc, bit))
   58 
   59 static int rs5c313_init(struct rs5c313_softc *);
   60 static int rs5c313_read_reg(struct rs5c313_softc *, int);
   61 static void rs5c313_write_reg(struct rs5c313_softc *, int, int);
   62 
   63 
   64 void
   65 rs5c313_attach(struct rs5c313_softc *sc)
   66 {
   67 
   68         printf(": RS5C313 real time clock\n");
   69 
   70         sc->sc_todr.cookie = sc;
   71         sc->sc_todr.todr_gettime = rs5c313_todr_gettime;
   72         sc->sc_todr.todr_settime = rs5c313_todr_settime;
   73         sc->sc_todr.todr_setwen = NULL;
   74 
   75         if (rs5c313_init(sc) != 0) {
   76                 printf("%s: init failed\n", sc->sc_dev.dv_xname);
   77                 return;
   78         }
   79 
   80         todr_attach(&sc->sc_todr);
   81 }
   82 
   83 
   84 static int
   85 rs5c313_init(struct rs5c313_softc *sc)
   86 {
   87         int status = 0;
   88         int retry;
   89 
   90         rtc_ce(sc, 0);
   91 
   92         rtc_begin(sc);
   93         rtc_ce(sc, 1);
   94 
   95         if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_XSTP) == 0) {
   96                 sc->sc_valid = 1;
   97                 goto done;
   98         }
   99 
  100         sc->sc_valid = 0;
  101         printf("%s: time not valid\n", sc->sc_dev.dv_xname);
  102 
  103         rs5c313_write_reg(sc, RS5C313_TINT, 0);
  104         rs5c313_write_reg(sc, RS5C313_CTRL, (CTRL_BASE | CTRL_ADJ));
  105 
  106         for (retry = 1000; retry > 0; --retry) {
  107                 if (rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY)
  108                         delay(1);
  109                 else
  110                         break;
  111         }
  112 
  113         if (retry == 0) {
  114                 status = EIO;
  115                 goto done;
  116         }
  117 
  118         rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  119 
  120   done:
  121         rtc_ce(sc, 0);
  122         return status;
  123 }
  124 
  125 
  126 static int
  127 rs5c313_todr_gettime(todr_chip_handle_t todr, volatile struct timeval *tv)
  128 {
  129         struct rs5c313_softc *sc = todr->cookie;
  130         struct clock_ymdhms dt;
  131         int retry;
  132         int s;
  133 
  134         /*
  135          * If chip had invalid data on init, don't bother reading
  136          * bogus values, let todr(9) cope.
  137          */
  138         if (sc->sc_valid == 0)
  139                 return EIO;
  140 
  141         s = splhigh();
  142 
  143         rtc_begin(sc);
  144         for (retry = 10; retry > 0; --retry) {
  145                 rtc_ce(sc, 1);
  146 
  147                 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  148                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  149                         break;
  150 
  151                 rtc_ce(sc, 0);
  152                 delay(1);
  153         }
  154 
  155         if (retry == 0) {
  156                 splx(s);
  157                 return EIO;
  158         }
  159 
  160 #define RTCGET(x, y)                                                    \
  161         do {                                                            \
  162                 int ones = rs5c313_read_reg(sc, RS5C313_ ## y ## 1);    \
  163                 int tens = rs5c313_read_reg(sc, RS5C313_ ## y ## 10);   \
  164                 dt.dt_ ## x = tens * 10 + ones;                         \
  165         } while (/* CONSTCOND */0)
  166 
  167         RTCGET(sec, SEC);
  168         RTCGET(min, MIN);
  169         RTCGET(hour, HOUR);
  170         RTCGET(day, DAY);
  171         RTCGET(mon, MON);
  172         RTCGET(year, YEAR);
  173 #undef  RTCGET
  174         dt.dt_wday = rs5c313_read_reg(sc, RS5C313_WDAY);
  175 
  176         rtc_ce(sc, 0);
  177         splx(s);
  178 
  179         dt.dt_year = (dt.dt_year % 100) + 1900;
  180         if (dt.dt_year < 1970) {
  181                 dt.dt_year += 100;
  182         }
  183 
  184         /*
  185          * If time_t is 32 bits, then the "End of Time" is 
  186          * Mon Jan 18 22:14:07 2038 (US/Eastern)
  187          * This code copes with RTC's past the end of time if time_t
  188          * is an int32 or less. Needed because sometimes RTCs screw
  189          * up or are badly set, and that would cause the time to go
  190          * negative in the calculation below, which causes Very Bad
  191          * Mojo. This at least lets the user boot and fix the problem.
  192          * Note the code is self eliminating once time_t goes to 64 bits.
  193          */
  194         if (/* CONSTCOND */ sizeof(time_t) <= sizeof(int32_t)) {
  195                 if (dt.dt_year >= 2038) {
  196                         return -1;
  197                 }
  198         }
  199 
  200         tv->tv_sec = clock_ymdhms_to_secs(&dt) + rtc_offset * 60;
  201         tv->tv_usec = 0;
  202 
  203         return 0;
  204 }
  205 
  206 
  207 static int
  208 rs5c313_todr_settime(todr_chip_handle_t todr, volatile struct timeval *tv)
  209 {
  210         struct rs5c313_softc *sc = todr->cookie;
  211         struct clock_ymdhms dt;
  212         int retry;
  213         int t;
  214         int s;
  215 
  216         clock_secs_to_ymdhms(tv->tv_sec - rtc_offset * 60, &dt);
  217 
  218         s = splhigh();
  219 
  220         rtc_begin(sc);
  221         for (retry = 10; retry > 0; --retry) {
  222                 rtc_ce(sc, 1);
  223 
  224                 rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
  225                 if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
  226                         break;
  227 
  228                 rtc_ce(sc, 0);
  229                 delay(1);
  230         }
  231 
  232         if (retry == 0) {
  233                 splx(s);
  234                 return EIO;
  235         }
  236 
  237 #define RTCSET(x, y)                                                         \
  238         do {                                                                 \
  239                 t = TOBCD(dt.dt_ ## y) & 0xff;                               \
  240                 rs5c313_write_reg(sc, RS5C313_ ## x ## 1, t & 0x0f);         \
  241                 rs5c313_write_reg(sc, RS5C313_ ## x ## 10, (t >> 4) & 0x0f); \
  242         } while (/* CONSTCOND */0)
  243 
  244         RTCSET(SEC, sec);
  245         RTCSET(MIN, min);
  246         RTCSET(HOUR, hour);
  247         RTCSET(DAY, day);
  248         RTCSET(MON, mon);
  249 
  250 #undef  RTCSET
  251 
  252         t = dt.dt_year % 100;
  253         t = TOBCD(t);
  254         rs5c313_write_reg(sc, RS5C313_YEAR1, t & 0x0f);
  255         rs5c313_write_reg(sc, RS5C313_YEAR10, (t >> 4) & 0x0f);
  256 
  257         rs5c313_write_reg(sc, RS5C313_WDAY, dt.dt_wday);
  258 
  259         rtc_ce(sc, 0);
  260         splx(s);
  261 
  262         sc->sc_valid = 1;
  263         return 0;
  264 }
  265 
  266 
  267 static int
  268 rs5c313_read_reg(struct rs5c313_softc *sc, int addr)
  269 {
  270         int data;
  271 
  272         /* output */
  273         rtc_dir(sc, 1);
  274 
  275         /* control */
  276         rtc_do(sc, 1);          /* ignored */
  277         rtc_do(sc, 1);          /* R/#W = 1(READ) */
  278         rtc_do(sc, 1);          /* AD = 1 */
  279         rtc_do(sc, 0);          /* DT = 0 */
  280 
  281         /* address */
  282         rtc_do(sc, addr & 0x8); /* A3 */
  283         rtc_do(sc, addr & 0x4); /* A2 */
  284         rtc_do(sc, addr & 0x2); /* A1 */
  285         rtc_do(sc, addr & 0x1); /* A0 */
  286 
  287         /* input */
  288         rtc_dir(sc, 0);
  289 
  290         /* ignore */
  291         (void)rtc_di(sc);
  292         (void)rtc_di(sc);
  293         (void)rtc_di(sc);
  294         (void)rtc_di(sc);
  295 
  296         /* data */
  297         data = rtc_di(sc);      /* D3 */
  298         data <<= 1;
  299         data |= rtc_di(sc);     /* D2 */
  300         data <<= 1;
  301         data |= rtc_di(sc);     /* D1 */
  302         data <<= 1;
  303         data |= rtc_di(sc);     /* D0 */
  304 
  305         return data;
  306 }
  307 
  308 
  309 static void
  310 rs5c313_write_reg(struct rs5c313_softc *sc, int addr, int data)
  311 {
  312 
  313         /* output */
  314         rtc_dir(sc, 1);
  315 
  316         /* control */
  317         rtc_do(sc, 1);          /* ignored */
  318         rtc_do(sc, 0);          /* R/#W = 0 (WRITE) */
  319         rtc_do(sc, 1);          /* AD = 1 */
  320         rtc_do(sc, 0);          /* DT = 0 */
  321 
  322         /* address */
  323         rtc_do(sc, addr & 0x8); /* A3 */
  324         rtc_do(sc, addr & 0x4); /* A2 */
  325         rtc_do(sc, addr & 0x2); /* A1 */
  326         rtc_do(sc, addr & 0x1); /* A0 */
  327 
  328         /* control */
  329         rtc_do(sc, 1);          /* ignored */
  330         rtc_do(sc, 0);          /* R/#W = 0(WRITE) */
  331         rtc_do(sc, 0);          /* AD = 0 */
  332         rtc_do(sc, 1);          /* DT = 1 */
  333 
  334         /* data */
  335         rtc_do(sc, data & 0x8); /* D3 */
  336         rtc_do(sc, data & 0x4); /* D2 */
  337         rtc_do(sc, data & 0x2); /* D1 */
  338         rtc_do(sc, data & 0x1); /* D0 */
  339 }

Cache object: f30d883046d8338cfa7e03d59c8c3857


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