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/iicbus/s35390a.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
    3  *
    4  * Copyright (c) 2012 Yusuke Tanaka
    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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*-
   30  * Copyright (c) 2011 Frank Wille.
   31  * All rights reserved.
   32  *
   33  * Written by Frank Wille for The NetBSD Project.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  *
   44  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   45  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   46  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   47  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   48  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   49  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   50  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   51  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   52  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   53  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   54  * POSSIBILITY OF SUCH DAMAGE.
   55  */
   56 
   57 #include <sys/cdefs.h>
   58 __FBSDID("$FreeBSD$");
   59 
   60 /*
   61  * Driver for Seiko Instruments S-35390A Real-time Clock
   62  */
   63 
   64 #include "opt_platform.h"
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 #include <sys/bus.h>
   69 #include <sys/clock.h>
   70 #include <sys/kernel.h>
   71 #include <sys/module.h>
   72 
   73 #include <dev/iicbus/iicbus.h>
   74 #include <dev/iicbus/iiconf.h>
   75 
   76 #ifdef FDT
   77 #include <dev/ofw/openfirm.h>
   78 #include <dev/ofw/ofw_bus.h>
   79 #include <dev/ofw/ofw_bus_subr.h>
   80 #endif
   81 
   82 #include "clock_if.h"
   83 #include "iicbus_if.h"
   84 
   85 #define S390_DEVNAME            "s35390a_rtc"
   86 #define S390_DEVCODE            0x6     /* 0110 */
   87 /*
   88  * S-35390A uses 4-bit device code + 3-bit command in the slave address
   89  * field.  The possible combination is 0x60-0x6f including the R/W bit.
   90  * 0x60 means an write access to status register 1.
   91  */
   92 #define S390_ADDR               (S390_DEVCODE << 4)
   93 
   94 /* Registers are encoded into the slave address */
   95 #define S390_STATUS1            (0 << 1)
   96 #define S390_STATUS2            (1 << 1)
   97 #define S390_REALTIME1          (2 << 1)
   98 #define S390_REALTIME2          (3 << 1)
   99 #define S390_INT1_1             (4 << 1)
  100 #define S390_INT1_2             (5 << 1)
  101 #define S390_CLOCKADJ           (6 << 1)
  102 #define S390_FREE               (7 << 1)
  103 
  104 /* Status1 bits */
  105 #define S390_ST1_POC            (1 << 7)
  106 #define S390_ST1_BLD            (1 << 6)
  107 #define S390_ST1_24H            (1 << 1)
  108 #define S390_ST1_RESET          (1 << 0)
  109 
  110 /* Status2 bits */
  111 #define S390_ST2_TEST           (1 << 7)
  112 
  113 /* Realtime1 data bytes */
  114 #define S390_RT1_NBYTES         7
  115 #define S390_RT1_YEAR           0
  116 #define S390_RT1_MONTH          1
  117 #define S390_RT1_DAY            2
  118 #define S390_RT1_WDAY           3
  119 #define S390_RT1_HOUR           4
  120 #define S390_RT1_MINUTE         5
  121 #define S390_RT1_SECOND         6
  122 
  123 struct s390rtc_softc {
  124         device_t        sc_dev;
  125         uint16_t        sc_addr;
  126 };
  127 
  128 /*
  129  * S-35390A interprets bits in each byte on SDA in reverse order.
  130  * bitreverse() reverses the bits in uint8_t.
  131  */
  132 static const uint8_t nibbletab[] = {
  133         /* 0x0 0000 -> 0000 */  0x0,
  134         /* 0x1 0001 -> 1000 */  0x8,
  135         /* 0x2 0010 -> 0100 */  0x4,
  136         /* 0x3 0011 -> 1100 */  0xc,
  137         /* 0x4 0100 -> 0010 */  0x2,
  138         /* 0x5 0101 -> 1010 */  0xa,
  139         /* 0x6 0110 -> 0110 */  0x6,
  140         /* 0x7 0111 -> 1110 */  0xe,
  141         /* 0x8 1000 -> 0001 */  0x1,
  142         /* 0x9 1001 -> 1001 */  0x9,
  143         /* 0xa 1010 -> 0101 */  0x5,
  144         /* 0xb 1011 -> 1101 */  0xd,
  145         /* 0xc 1100 -> 0011 */  0x3,
  146         /* 0xd 1101 -> 1011 */  0xb,
  147         /* 0xe 1110 -> 0111 */  0x7,
  148         /* 0xf 1111 -> 1111 */  0xf, };
  149 
  150 static uint8_t
  151 bitreverse(uint8_t x)
  152 {
  153 
  154         return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
  155 }
  156 
  157 static int
  158 s390rtc_read(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
  159 {
  160         struct s390rtc_softc *sc = device_get_softc(dev);
  161         struct iic_msg msg[] = {
  162                 {
  163                         .slave = sc->sc_addr | reg,
  164                         .flags = IIC_M_RD,
  165                         .len = len,
  166                         .buf = buf,
  167                 },
  168         };
  169         int i;
  170         int error;
  171 
  172         error = iicbus_transfer_excl(dev, msg, 1, IIC_WAIT);
  173         if (error)
  174                 return (error);
  175 
  176         /* this chip returns each byte in reverse order */
  177         for (i = 0; i < len; ++i)
  178                 buf[i] = bitreverse(buf[i]);
  179 
  180         return (0);
  181 }
  182 
  183 static int
  184 s390rtc_write(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
  185 {
  186         struct s390rtc_softc *sc = device_get_softc(dev);
  187         struct iic_msg msg[] = {
  188                 {
  189                         .slave = sc->sc_addr | reg,
  190                         .flags = IIC_M_WR,
  191                         .len = len,
  192                         .buf = buf,
  193                 },
  194         };
  195         int i;
  196 
  197         /* this chip expects each byte in reverse order */
  198         for (i = 0; i < len; ++i)
  199                 buf[i] = bitreverse(buf[i]);
  200 
  201         return (iicbus_transfer_excl(dev, msg, 1, IIC_WAIT));
  202 }
  203 
  204 static int
  205 s390rtc_probe(device_t dev)
  206 {
  207 
  208 #ifdef FDT
  209         if (!ofw_bus_status_okay(dev))
  210                 return (ENXIO);
  211 
  212         if (!ofw_bus_is_compatible(dev, "sii,s35390a"))
  213                 return (ENXIO);
  214 #else
  215         if (iicbus_get_addr(dev) != S390_ADDR) {
  216                 if (bootverbose)
  217                         device_printf(dev, "slave address mismatch. "
  218                             "(%02x != %02x)\n", iicbus_get_addr(dev),
  219                             S390_ADDR);
  220                 return (ENXIO);
  221         }
  222 #endif
  223         device_set_desc(dev, "Seiko Instruments S-35390A RTC");
  224 
  225         return (BUS_PROBE_DEFAULT);
  226 }
  227 
  228 static void
  229 s390rtc_start(void *arg)
  230 {
  231         device_t dev;
  232         uint8_t reg;
  233         int error;
  234 
  235         dev = arg;
  236 
  237         /* Reset the chip and turn on 24h mode, after power-off or battery. */
  238         error = s390rtc_read(dev, S390_STATUS1, &reg, 1);
  239         if (error) {
  240                 device_printf(dev, "%s: cannot read status1 register\n",
  241                      __func__);
  242                 return;
  243         }
  244         if (reg & (S390_ST1_POC | S390_ST1_BLD)) {
  245                 reg |= S390_ST1_24H | S390_ST1_RESET;
  246                 error = s390rtc_write(dev, S390_STATUS1, &reg, 1);
  247                 if (error) {
  248                         device_printf(dev,
  249                             "%s: cannot initialize\n", __func__);
  250                         return;
  251                 }
  252         }
  253 
  254         /* Disable the test mode, when enabled. */
  255         error = s390rtc_read(dev, S390_STATUS2, &reg, 1);
  256         if (error) {
  257                 device_printf(dev, "%s: cannot read status2 register\n",
  258                     __func__);
  259                 return;
  260         }
  261         if (reg & S390_ST2_TEST) {
  262                 reg &= ~S390_ST2_TEST;
  263                 error = s390rtc_write(dev, S390_STATUS2, &reg, 1);
  264                 if (error) {
  265                         device_printf(dev,
  266                             "%s: cannot disable the test mode\n", __func__);
  267                         return;
  268                 }
  269         }
  270 
  271         clock_register(dev, 1000000);   /* 1 second resolution */
  272 }
  273 
  274 static int
  275 s390rtc_attach(device_t dev)
  276 {
  277         struct s390rtc_softc *sc;
  278 
  279         sc = device_get_softc(dev);
  280         sc->sc_dev = dev;
  281         sc->sc_addr = iicbus_get_addr(dev);
  282 
  283         config_intrhook_oneshot(s390rtc_start, dev);
  284 
  285         return (0);
  286 }
  287 
  288 static int
  289 s390rtc_detach(device_t dev)
  290 {
  291 
  292         clock_unregister(dev);
  293         return (0);
  294 }
  295 
  296 static int
  297 s390rtc_gettime(device_t dev, struct timespec *ts)
  298 {
  299         uint8_t bcd[S390_RT1_NBYTES];
  300         struct bcd_clocktime bct;
  301         int error;
  302 
  303         error = s390rtc_read(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES);
  304         if (error) {
  305                 device_printf(dev, "%s: cannot read realtime1 register\n",
  306                     __func__);
  307                 return (error);
  308         }
  309 
  310         /*
  311          * Convert the register values into something useable.
  312          */
  313         bct.nsec = 0;
  314         bct.sec  = bcd[S390_RT1_SECOND];
  315         bct.min  = bcd[S390_RT1_MINUTE];
  316         bct.hour = bcd[S390_RT1_HOUR] & 0x3f;
  317         bct.day  = bcd[S390_RT1_DAY];
  318         bct.dow  = bcd[S390_RT1_WDAY] & 0x07;
  319         bct.mon  = bcd[S390_RT1_MONTH];
  320         bct.year = bcd[S390_RT1_YEAR];
  321 
  322         clock_dbgprint_bcd(dev, CLOCK_DBG_READ, &bct); 
  323         return (clock_bcd_to_ts(&bct, ts, false));
  324 }
  325 
  326 static int
  327 s390rtc_settime(device_t dev, struct timespec *ts)
  328 {
  329         uint8_t bcd[S390_RT1_NBYTES];
  330         struct bcd_clocktime bct;
  331 
  332         clock_ts_to_bcd(ts, &bct, false);
  333         clock_dbgprint_bcd(dev, CLOCK_DBG_WRITE, &bct); 
  334 
  335         /*
  336          * Convert our time representation into something the S-xx390
  337          * can understand.
  338          */
  339         bcd[S390_RT1_SECOND] = bct.sec;
  340         bcd[S390_RT1_MINUTE] = bct.min;
  341         bcd[S390_RT1_HOUR]   = bct.hour;
  342         bcd[S390_RT1_DAY]    = bct.day;
  343         bcd[S390_RT1_WDAY]   = bct.dow;
  344         bcd[S390_RT1_MONTH]  = bct.mon;
  345         bcd[S390_RT1_YEAR]   = bct.year & 0xff;
  346 
  347         return (s390rtc_write(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES));
  348 }
  349 
  350 static device_method_t s390rtc_methods[] = {
  351         DEVMETHOD(device_probe,         s390rtc_probe),
  352         DEVMETHOD(device_attach,        s390rtc_attach),
  353         DEVMETHOD(device_detach,        s390rtc_detach),
  354 
  355         DEVMETHOD(clock_gettime,        s390rtc_gettime),
  356         DEVMETHOD(clock_settime,        s390rtc_settime),
  357 
  358         DEVMETHOD_END
  359 };
  360 
  361 static driver_t s390rtc_driver = {
  362         S390_DEVNAME,
  363         s390rtc_methods,
  364         sizeof(struct s390rtc_softc),
  365 };
  366 
  367 DRIVER_MODULE(s35390a, iicbus, s390rtc_driver, NULL, NULL);
  368 MODULE_VERSION(s35390a, 1);
  369 MODULE_DEPEND(s35390a, iicbus, 1, 1, 1);

Cache object: 011d96ab45bcd02ad44d2bf3ca147c98


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