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/arm/at91/at91_rtc.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  * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
    3  * Copyright (c) 2012 Ian Lepore.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * Driver for the at91 on-chip realtime clock.
   29  *
   30  * This driver does not currently support alarms, just date and time.
   31  *
   32  * The RTC on the AT91RM9200 resets when the core rests, so it is useless as a
   33  * source of time (except when the CPU clock is powered down to save power,
   34  * which we don't currently do).  On AT91SAM9 chips, the RTC survives chip
   35  * reset, and there's provisions for it to keep time via battery backup if the
   36  * system loses power.  On those systems, we use it as a RTC.  We tell the two
   37  * apart because the century field is 19 on AT91RM9200 on reset, or on AT91SAM9
   38  * chips that haven't had their time properly set.
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __FBSDID("$FreeBSD$");
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/bus.h>
   47 #include <sys/clock.h>
   48 #include <sys/conf.h>
   49 #include <sys/kernel.h>
   50 #include <sys/lock.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/malloc.h>
   53 #include <sys/module.h>
   54 #include <sys/mutex.h>
   55 #include <sys/rman.h>
   56 #include <machine/bus.h>
   57 #include <machine/cpu.h>
   58 
   59 #include <arm/at91/at91_rtcreg.h>
   60 
   61 #include "clock_if.h"
   62 
   63 /*
   64  * The driver has all the infrastructure to use interrupts but doesn't actually
   65  * have any need to do so right now.  There's a non-zero cost for installing the
   66  * handler because the RTC shares the system interrupt (IRQ 1), and thus will
   67  * get called a lot for no reason at all.
   68  */
   69 #define AT91_RTC_USE_INTERRUPTS_NOT
   70 
   71 struct at91_rtc_softc
   72 {
   73         device_t dev;                   /* Myself */
   74         void *intrhand;                 /* Interrupt handle */
   75         struct resource *irq_res;       /* IRQ resource */
   76         struct resource *mem_res;       /* Memory resource */
   77         struct mtx sc_mtx;              /* basically a perimeter lock */
   78 };
   79 
   80 static inline uint32_t
   81 RD4(struct at91_rtc_softc *sc, bus_size_t off)
   82 {
   83         return bus_read_4(sc->mem_res, off);
   84 }
   85 
   86 static inline void
   87 WR4(struct at91_rtc_softc *sc, bus_size_t off, uint32_t val)
   88 {
   89         bus_write_4(sc->mem_res, off, val);
   90 }
   91 
   92 #define AT91_RTC_LOCK(_sc)              mtx_lock_spin(&(_sc)->sc_mtx)
   93 #define AT91_RTC_UNLOCK(_sc)            mtx_unlock_spin(&(_sc)->sc_mtx)
   94 #define AT91_RTC_LOCK_INIT(_sc) \
   95         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
   96             "rtc", MTX_SPIN)
   97 #define AT91_RTC_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
   98 #define AT91_RTC_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
   99 #define AT91_RTC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
  100 
  101 static devclass_t at91_rtc_devclass;
  102 
  103 /* bus entry points */
  104 
  105 static int at91_rtc_probe(device_t dev);
  106 static int at91_rtc_attach(device_t dev);
  107 static int at91_rtc_detach(device_t dev);
  108 
  109 /* helper routines */
  110 static int at91_rtc_activate(device_t dev);
  111 static void at91_rtc_deactivate(device_t dev);
  112 
  113 #ifdef AT91_RTC_USE_INTERRUPTS
  114 static int
  115 at91_rtc_intr(void *xsc)
  116 {
  117         struct at91_rtc_softc *sc;
  118         uint32_t status;
  119 
  120         sc = xsc;
  121         /* Must clear the status bits after reading them to re-arm. */
  122         status = RD4(sc, RTC_SR);
  123         WR4(sc, RTC_SCCR, status);
  124         if (status == 0)
  125                 return;
  126         AT91_RTC_LOCK(sc);
  127         /* Do something here */
  128         AT91_RTC_UNLOCK(sc);
  129         wakeup(sc);
  130         return (FILTER_HANDLED);
  131 }
  132 #endif
  133 
  134 static int
  135 at91_rtc_probe(device_t dev)
  136 {
  137         device_set_desc(dev, "RTC");
  138         return (0);
  139 }
  140 
  141 static int
  142 at91_rtc_attach(device_t dev)
  143 {
  144         struct at91_rtc_softc *sc = device_get_softc(dev);
  145         int err;
  146 
  147         sc->dev = dev;
  148         err = at91_rtc_activate(dev);
  149         if (err)
  150                 goto out;
  151 
  152         AT91_RTC_LOCK_INIT(sc);
  153 
  154         /*
  155          * Disable all interrupts in the hardware.
  156          * Clear all bits in the status register.
  157          * Set 24-hour-clock mode.
  158          */
  159         WR4(sc, RTC_IDR, 0xffffffff);
  160         WR4(sc, RTC_SCCR, 0x1f);
  161         WR4(sc, RTC_MR, 0);
  162 
  163 #ifdef AT91_RTC_USE_INTERRUPTS
  164         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
  165             at91_rtc_intr, NULL, sc, &sc->intrhand);
  166         if (err) {
  167                 AT91_RTC_LOCK_DESTROY(sc);
  168                 goto out;
  169         }
  170 #endif  
  171 
  172         /*
  173          * Read the calendar register.  If the century is 19 then the clock has
  174          * never been set.  Try to store an invalid value into the register,
  175          * which will turn on the error bit in RTC_VER, and our getclock code
  176          * knows to return EINVAL if any error bits are on.
  177          */
  178         if (RTC_CALR_CEN(RD4(sc, RTC_CALR)) == 19)
  179                 WR4(sc, RTC_CALR, 0);
  180 
  181         /*
  182          * Register as a time of day clock with 1-second resolution.
  183          */
  184         clock_register(dev, 1000000);
  185 out:
  186         if (err)
  187                 at91_rtc_deactivate(dev);
  188         return (err);
  189 }
  190 
  191 /*
  192  * Cannot support detach, since there's no clock_unregister function.
  193  */
  194 static int
  195 at91_rtc_detach(device_t dev)
  196 {
  197         return (EBUSY);
  198 }
  199 
  200 static int
  201 at91_rtc_activate(device_t dev)
  202 {
  203         struct at91_rtc_softc *sc;
  204         int rid;
  205 
  206         sc = device_get_softc(dev);
  207         rid = 0;
  208         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  209             RF_ACTIVE);
  210         if (sc->mem_res == NULL)
  211                 goto errout;
  212 #ifdef AT91_RTC_USE_INTERRUPTS
  213         rid = 0;
  214         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  215             RF_ACTIVE | RF_SHAREABLE);
  216         if (sc->irq_res == NULL)
  217                 goto errout;
  218 #endif  
  219         return (0);
  220 errout:
  221         at91_rtc_deactivate(dev);
  222         return (ENOMEM);
  223 }
  224 
  225 static void
  226 at91_rtc_deactivate(device_t dev)
  227 {
  228         struct at91_rtc_softc *sc;
  229 
  230         sc = device_get_softc(dev);
  231 #ifdef AT91_RTC_USE_INTERRUPTS
  232         WR4(sc, RTC_IDR, 0xffffffff);
  233         if (sc->intrhand)
  234                 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  235         sc->intrhand = 0;
  236 #endif
  237         bus_generic_detach(sc->dev);
  238         if (sc->mem_res)
  239                 bus_release_resource(dev, SYS_RES_MEMORY,
  240                     rman_get_rid(sc->mem_res), sc->mem_res);
  241         sc->mem_res = 0;
  242 #ifdef AT91_RTC_USE_INTERRUPTS
  243         if (sc->irq_res)
  244                 bus_release_resource(dev, SYS_RES_IRQ,
  245                     rman_get_rid(sc->irq_res), sc->irq_res);
  246         sc->irq_res = 0;
  247 #endif  
  248         return;
  249 }
  250 
  251 /*
  252  * Get the time of day clock and return it in ts.
  253  * Return 0 on success, an error number otherwise.
  254  */
  255 static int
  256 at91_rtc_gettime(device_t dev, struct timespec *ts)
  257 {
  258         struct clocktime ct;
  259         uint32_t calr, calr2, timr, timr2;
  260         struct at91_rtc_softc *sc;
  261 
  262         sc = device_get_softc(dev);
  263 
  264         /* If the error bits are set we can't return useful values. */
  265 
  266         if (RD4(sc, RTC_VER) & (RTC_VER_NVTIM | RTC_VER_NVCAL))
  267                 return EINVAL;
  268 
  269         /*
  270          * The RTC hardware can update registers while the CPU is reading them.
  271          * The manual advises reading until you obtain the same values twice.
  272          * Interleaving the reads (rather than timr, timr2, calr, calr2 order)
  273          * also ensures we don't miss a midnight rollover/carry between reads.
  274          */
  275         do {
  276                 timr = RD4(sc, RTC_TIMR);
  277                 calr = RD4(sc, RTC_CALR);
  278                 timr2 = RD4(sc, RTC_TIMR);
  279                 calr2 = RD4(sc, RTC_CALR);
  280         } while (timr != timr2 || calr != calr2);
  281 
  282         ct.nsec = 0;
  283         ct.sec = RTC_TIMR_SEC(timr);
  284         ct.min = RTC_TIMR_MIN(timr);
  285         ct.hour = RTC_TIMR_HR(timr);
  286         ct.year = RTC_CALR_CEN(calr) * 100 + RTC_CALR_YEAR(calr);
  287         ct.mon = RTC_CALR_MON(calr);
  288         ct.day = RTC_CALR_DAY(calr);
  289         ct.dow = -1;
  290         return clock_ct_to_ts(&ct, ts);
  291 }
  292 
  293 /*
  294  * Set the time of day clock based on the value of the struct timespec arg.
  295  * Return 0 on success, an error number otherwise.
  296  */
  297 static int
  298 at91_rtc_settime(device_t dev, struct timespec *ts)
  299 {
  300         struct at91_rtc_softc *sc;
  301         struct clocktime ct;
  302         int rv;
  303 
  304         sc = device_get_softc(dev);
  305         clock_ts_to_ct(ts, &ct);
  306 
  307         /*
  308          * Can't set the clock unless a second has elapsed since we last did so.
  309          */
  310         while ((RD4(sc, RTC_SR) & RTC_SR_SECEV) == 0)
  311                 cpu_spinwait();
  312 
  313         /*
  314          * Stop the clocks for an update; wait until hardware is ready.
  315          * Clear the update-ready status after it gets asserted (the manual says
  316          * to do this before updating the value registers).
  317          */
  318         WR4(sc, RTC_CR, RTC_CR_UPDCAL | RTC_CR_UPDTIM);
  319         while ((RD4(sc, RTC_SR) & RTC_SR_ACKUPD) == 0)
  320                 cpu_spinwait();
  321         WR4(sc, RTC_SCCR, RTC_SR_ACKUPD);
  322 
  323         /*
  324          * Set the values in the hardware, then check whether the hardware was
  325          * happy with them so we can return the correct status.
  326          */
  327         WR4(sc, RTC_TIMR, RTC_TIMR_MK(ct.hour, ct.min, ct.sec));
  328         WR4(sc, RTC_CALR, RTC_CALR_MK(ct.year, ct.mon, ct.day, ct.dow+1));
  329 
  330         if (RD4(sc, RTC_VER) & (RTC_VER_NVTIM | RTC_VER_NVCAL))
  331                 rv = EINVAL;
  332         else
  333                 rv = 0;
  334 
  335         /*
  336          * Restart the clocks (turn off the update bits).
  337          * Clear the second-event bit (because the manual says to).
  338          */
  339         WR4(sc, RTC_CR, RD4(sc, RTC_CR) & ~(RTC_CR_UPDCAL | RTC_CR_UPDTIM));
  340         WR4(sc, RTC_SCCR, RTC_SR_SECEV);
  341 
  342         return (0);
  343 }
  344 
  345 static device_method_t at91_rtc_methods[] = {
  346         /* Device interface */
  347         DEVMETHOD(device_probe,         at91_rtc_probe),
  348         DEVMETHOD(device_attach,        at91_rtc_attach),
  349         DEVMETHOD(device_detach,        at91_rtc_detach),
  350 
  351         /* clock interface */
  352         DEVMETHOD(clock_gettime,        at91_rtc_gettime),
  353         DEVMETHOD(clock_settime,        at91_rtc_settime),
  354 
  355         DEVMETHOD_END
  356 };
  357 
  358 static driver_t at91_rtc_driver = {
  359         "at91_rtc",
  360         at91_rtc_methods,
  361         sizeof(struct at91_rtc_softc),
  362 };
  363 
  364 DRIVER_MODULE(at91_rtc, atmelarm, at91_rtc_driver, at91_rtc_devclass, 0, 0);

Cache object: f12e4a266b9a0fbf09080d2ec5f3bf34


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