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/ti/am335x/am335x_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) 2015 Luiz Otavio O Souza <loos@FreeBSD.org>
    3  * 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 THE 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 THE 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 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/clock.h>
   34 #include <sys/kernel.h>
   35 #include <sys/lock.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/rman.h>
   39 
   40 #include <machine/bus.h>
   41 
   42 #include <dev/ofw/ofw_bus.h>
   43 #include <dev/ofw/ofw_bus_subr.h>
   44 #include <arm/ti/ti_sysc.h>
   45 #include <arm/ti/am335x/am335x_rtcvar.h>
   46 #include <arm/ti/am335x/am335x_rtcreg.h>
   47 
   48 #define RTC_LOCK(_sc)           mtx_lock(&(_sc)->sc_mtx)
   49 #define RTC_UNLOCK(_sc)         mtx_unlock(&(_sc)->sc_mtx)
   50 #define RTC_LOCK_INIT(_sc)      mtx_init(&(_sc)->sc_mtx, \
   51     device_get_nameunit(_sc->sc_dev), "am335x_rtc", MTX_DEF)
   52 #define RTC_LOCK_DESTROY(_sc)   mtx_destroy(&(_sc)->sc_mtx)
   53 
   54 #define RTC_READ4(_sc, reg)             \
   55         bus_read_4((_sc)->sc_mem_res, reg)
   56 #define RTC_WRITE4(_sc, reg, value)     \
   57         bus_write_4((_sc)->sc_mem_res, reg, value)
   58 
   59 #define RTC_MAXIRQS             2
   60 
   61 struct am335x_rtc_softc {
   62         device_t                sc_dev;
   63         struct mtx              sc_mtx;
   64         struct resource         *sc_irq_res[RTC_MAXIRQS];
   65         struct resource         *sc_mem_res;
   66 };
   67 
   68 static struct am335x_rtc_softc *rtc_sc = NULL;
   69 static struct resource_spec am335x_rtc_irq_spec[] = {
   70         { SYS_RES_IRQ, 0,  RF_ACTIVE },
   71         { SYS_RES_IRQ, 1,  RF_ACTIVE },
   72         { -1, 0,  0 }
   73 };
   74 
   75 static int
   76 am335x_rtc_probe(device_t dev)
   77 {
   78 
   79         if (!ofw_bus_status_okay(dev))
   80                 return (ENXIO);
   81         if (!ofw_bus_is_compatible(dev, "ti,da830-rtc"))
   82                 return (ENXIO);
   83         device_set_desc(dev, "AM335x RTC (power management mode)");
   84 
   85         return (BUS_PROBE_DEFAULT);
   86 }
   87 
   88 static int
   89 am335x_rtc_attach(device_t dev)
   90 {
   91         int rid;
   92         struct am335x_rtc_softc *sc;
   93         uint32_t rev;
   94 
   95         if (rtc_sc != NULL)
   96                 return (ENXIO);
   97         rtc_sc = sc = device_get_softc(dev);
   98         sc->sc_dev = dev;
   99         rid = 0;
  100         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  101             RF_ACTIVE);
  102         if (!sc->sc_mem_res) {
  103                 device_printf(dev, "cannot allocate memory resources\n");
  104                 return (ENXIO);
  105         }
  106         if (bus_alloc_resources(dev, am335x_rtc_irq_spec, sc->sc_irq_res) != 0) {
  107                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  108                 device_printf(dev, "cannot allocate irq resources\n");
  109                 return (ENXIO);
  110         }
  111         RTC_LOCK_INIT(sc);
  112 
  113         /* Enable the RTC module. */
  114         ti_sysc_clock_enable(device_get_parent(dev));
  115         rev = RTC_READ4(sc, RTC_REVISION);
  116         device_printf(dev, "AM335X RTC v%d.%d.%d\n",
  117             (rev >> 8) & 0x7, (rev >> 6) & 0x3, rev & 0x3f);
  118         /* Unlock the RTC. */
  119         RTC_WRITE4(sc, RTC_KICK0R, RTC_KICK0R_PASS);
  120         RTC_WRITE4(sc, RTC_KICK1R, RTC_KICK1R_PASS);
  121         /* Stop the RTC, we don't need it right now. */
  122         RTC_WRITE4(sc, RTC_CTRL, 0);
  123         /* Disable interrupts. */
  124         RTC_WRITE4(sc, RTC_INTR, 0);
  125         /* Ack any pending interrupt. */
  126         RTC_WRITE4(sc, RTC_STATUS, RTC_STATUS_ALARM2 | RTC_STATUS_ALARM);
  127         /* Enable external clock (xtal) and 32 kHz clock. */
  128         RTC_WRITE4(sc, RTC_OSC, RTC_OSC_32KCLK_EN | RTC_OSC_32KCLK_SEL);
  129         /* Enable pmic_pwr_enable. */
  130         RTC_WRITE4(sc, RTC_PMIC, PMIC_PWR_ENABLE);
  131 
  132         return (0);
  133 }
  134 
  135 static int
  136 am335x_rtc_detach(device_t dev)
  137 {
  138         struct am335x_rtc_softc *sc;
  139 
  140         sc = device_get_softc(dev);
  141         if (sc->sc_irq_res[0] != NULL)
  142                 bus_release_resources(dev, am335x_rtc_irq_spec, sc->sc_irq_res);
  143         if (sc->sc_mem_res)
  144                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  145         RTC_LOCK_DESTROY(sc);
  146 
  147         return (0);
  148 }
  149 
  150 void
  151 am335x_rtc_pmic_pwr_toggle(void)
  152 {
  153         int timeout;
  154         struct clocktime ct;
  155         struct timespec ts;
  156 
  157         /*
  158          * We stop the RTC so we don't need to check the STATUS.BUSY bit
  159          * before update ALARM2 registers.
  160          */
  161         timeout = 10;
  162         RTC_WRITE4(rtc_sc, RTC_CTRL, 0);
  163         while (--timeout && RTC_READ4(rtc_sc, RTC_STATUS) & RTC_STATUS_RUN)
  164                 DELAY(100);
  165         if (timeout == 0) {
  166                 device_printf(rtc_sc->sc_dev, "RTC does not stop.\n");
  167                 return;
  168         }
  169         /* Program the ALARM2 to fire in 2 seconds. */
  170         ct.dow = 0;
  171         ct.nsec = 0;
  172         ct.sec = FROMBCD(RTC_READ4(rtc_sc, RTC_SECONDS) & 0x7f);
  173         ct.min = FROMBCD(RTC_READ4(rtc_sc, RTC_MINUTES) & 0x7f);
  174         ct.hour = FROMBCD(RTC_READ4(rtc_sc, RTC_HOURS) & 0x3f);
  175         ct.day = FROMBCD(RTC_READ4(rtc_sc, RTC_DAYS) & 0x3f);
  176         ct.mon = FROMBCD(RTC_READ4(rtc_sc, RTC_MONTHS) & 0x1f);
  177         ct.year = FROMBCD(RTC_READ4(rtc_sc, RTC_YEARS) & 0xff);
  178         ct.year += POSIX_BASE_YEAR;
  179         clock_ct_to_ts(&ct, &ts);
  180         ts.tv_sec += 2;
  181         clock_ts_to_ct(&ts, &ct);
  182         RTC_WRITE4(rtc_sc, RTC_ALARM2_SECONDS, TOBCD(ct.sec));
  183         RTC_WRITE4(rtc_sc, RTC_ALARM2_MINUTES, TOBCD(ct.min));
  184         RTC_WRITE4(rtc_sc, RTC_ALARM2_HOURS, TOBCD(ct.hour));
  185         RTC_WRITE4(rtc_sc, RTC_ALARM2_DAYS, TOBCD(ct.day));
  186         RTC_WRITE4(rtc_sc, RTC_ALARM2_MONTHS, TOBCD(ct.mon));
  187         RTC_WRITE4(rtc_sc, RTC_ALARM2_YEARS, TOBCD(ct.year - POSIX_BASE_YEAR));
  188         /* Enable ALARM2 interrupt. */
  189         RTC_WRITE4(rtc_sc, RTC_INTR, RTC_INTR_ALARM2);
  190         /* Start count. */
  191         RTC_WRITE4(rtc_sc, RTC_CTRL, RTC_CTRL_RUN);
  192 }
  193 
  194 static device_method_t am335x_rtc_methods[] = {
  195         DEVMETHOD(device_probe,         am335x_rtc_probe),
  196         DEVMETHOD(device_attach,        am335x_rtc_attach),
  197         DEVMETHOD(device_detach,        am335x_rtc_detach),
  198 
  199         DEVMETHOD_END
  200 };
  201 
  202 static driver_t am335x_rtc_driver = {
  203         "am335x_rtc",
  204         am335x_rtc_methods,
  205         sizeof(struct am335x_rtc_softc),
  206 };
  207 
  208 DRIVER_MODULE(am335x_rtc, simplebus, am335x_rtc_driver, 0, 0);
  209 MODULE_VERSION(am335x_rtc, 1);
  210 MODULE_DEPEND(am335x_rtc, simplebus, 1, 1, 1);
  211 MODULE_DEPEND(am335x_rtc, ti_sysc, 1, 1, 1);

Cache object: adb828267e706561488d4aa82894e518


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