1277042Sloos/*- 2277042Sloos * Copyright (c) 2015 Luiz Otavio O Souza <loos@FreeBSD.org> 3277042Sloos * All rights reserved. 4277042Sloos * 5277042Sloos * Redistribution and use in source and binary forms, with or without 6277042Sloos * modification, are permitted provided that the following conditions 7277042Sloos * are met: 8277042Sloos * 1. Redistributions of source code must retain the above copyright 9277042Sloos * notice, this list of conditions and the following disclaimer. 10277042Sloos * 2. Redistributions in binary form must reproduce the above copyright 11277042Sloos * notice, this list of conditions and the following disclaimer in the 12277042Sloos * documentation and/or other materials provided with the distribution. 13277042Sloos * 14277042Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15277042Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16277042Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17277042Sloos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18277042Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19277042Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20277042Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21277042Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22277042Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23277042Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24277042Sloos * SUCH DAMAGE. 25277042Sloos */ 26277042Sloos 27277042Sloos#include <sys/cdefs.h> 28277042Sloos__FBSDID("$FreeBSD: releng/10.3/sys/arm/ti/am335x/am335x_rtc.c 279462 2015-03-01 00:57:01Z dim $"); 29277042Sloos 30277042Sloos#include <sys/param.h> 31277042Sloos#include <sys/systm.h> 32277042Sloos#include <sys/bus.h> 33277042Sloos#include <sys/clock.h> 34277042Sloos#include <sys/kernel.h> 35277042Sloos#include <sys/lock.h> 36277042Sloos#include <sys/module.h> 37277042Sloos#include <sys/mutex.h> 38277042Sloos#include <sys/rman.h> 39277042Sloos 40277042Sloos#include <machine/bus.h> 41277042Sloos 42277042Sloos#include <dev/ofw/ofw_bus_subr.h> 43277042Sloos#include <arm/ti/ti_prcm.h> 44277042Sloos#include <arm/ti/am335x/am335x_rtcvar.h> 45277042Sloos#include <arm/ti/am335x/am335x_rtcreg.h> 46277042Sloos 47277042Sloos#define RTC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 48277042Sloos#define RTC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 49277042Sloos#define RTC_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 50277042Sloos device_get_nameunit(_sc->sc_dev), "am335x_rtc", MTX_DEF) 51277042Sloos#define RTC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 52277042Sloos 53277042Sloos#define RTC_READ4(_sc, reg) \ 54277042Sloos bus_read_4((_sc)->sc_mem_res, reg) 55277042Sloos#define RTC_WRITE4(_sc, reg, value) \ 56277042Sloos bus_write_4((_sc)->sc_mem_res, reg, value) 57277042Sloos 58277042Sloos#define RTC_MAXIRQS 2 59277042Sloos 60277042Sloosstruct am335x_rtc_softc { 61277042Sloos device_t sc_dev; 62277042Sloos struct mtx sc_mtx; 63277042Sloos struct resource *sc_irq_res[RTC_MAXIRQS]; 64277042Sloos struct resource *sc_mem_res; 65277042Sloos}; 66277042Sloos 67277042Sloosstatic struct am335x_rtc_softc *rtc_sc = NULL; 68277042Sloosstatic struct resource_spec am335x_rtc_irq_spec[] = { 69277042Sloos { SYS_RES_IRQ, 0, RF_ACTIVE }, 70277042Sloos { SYS_RES_IRQ, 1, RF_ACTIVE }, 71277042Sloos { -1, 0, 0 } 72277042Sloos}; 73277042Sloos 74277042Sloosstatic int 75277042Sloosam335x_rtc_probe(device_t dev) 76277042Sloos{ 77277042Sloos 78277042Sloos if (!ofw_bus_status_okay(dev)) 79277042Sloos return (ENXIO); 80277042Sloos if (!ofw_bus_is_compatible(dev, "ti,da830-rtc")) 81277042Sloos return (ENXIO); 82277042Sloos device_set_desc(dev, "AM335x RTC (power management mode)"); 83277042Sloos 84277042Sloos return (BUS_PROBE_DEFAULT); 85277042Sloos} 86277042Sloos 87277042Sloosstatic int 88277042Sloosam335x_rtc_attach(device_t dev) 89277042Sloos{ 90277042Sloos int rid; 91277042Sloos struct am335x_rtc_softc *sc; 92277042Sloos uint32_t rev; 93277042Sloos 94277042Sloos if (rtc_sc != NULL) 95277042Sloos return (ENXIO); 96277042Sloos rtc_sc = sc = device_get_softc(dev); 97277042Sloos sc->sc_dev = dev; 98277042Sloos rid = 0; 99277042Sloos sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 100277042Sloos RF_ACTIVE); 101277042Sloos if (!sc->sc_mem_res) { 102277042Sloos device_printf(dev, "cannot allocate memory resources\n"); 103277042Sloos return (ENXIO); 104277042Sloos } 105277042Sloos if (bus_alloc_resources(dev, am335x_rtc_irq_spec, sc->sc_irq_res) != 0) { 106277042Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 107277042Sloos device_printf(dev, "cannot allocate irq resources\n"); 108277042Sloos return (ENXIO); 109277042Sloos } 110277042Sloos RTC_LOCK_INIT(sc); 111277042Sloos 112277042Sloos /* Enable the RTC module. */ 113277042Sloos ti_prcm_clk_enable(RTC_CLK); 114277042Sloos rev = RTC_READ4(sc, RTC_REVISION); 115277042Sloos device_printf(dev, "AM335X RTC v%d.%d.%d\n", 116277042Sloos (rev >> 8) & 0x7, (rev >> 6) & 0x3, rev & 0x3f); 117277042Sloos /* Unlock the RTC. */ 118277042Sloos RTC_WRITE4(sc, RTC_KICK0R, RTC_KICK0R_PASS); 119277042Sloos RTC_WRITE4(sc, RTC_KICK1R, RTC_KICK1R_PASS); 120277042Sloos /* Stop the RTC, we don't need it right now. */ 121277042Sloos RTC_WRITE4(sc, RTC_CTRL, 0); 122277042Sloos /* Disable interrupts. */ 123277042Sloos RTC_WRITE4(sc, RTC_INTR, 0); 124277042Sloos /* Ack any pending interrupt. */ 125277042Sloos RTC_WRITE4(sc, RTC_STATUS, RTC_STATUS_ALARM2 | RTC_STATUS_ALARM); 126277042Sloos /* Enable external clock (xtal) and 32 kHz clock. */ 127277042Sloos RTC_WRITE4(sc, RTC_OSC, RTC_OSC_32KCLK_EN | RTC_OSC_32KCLK_SEL); 128277042Sloos /* Enable pmic_pwr_enable. */ 129277042Sloos RTC_WRITE4(sc, RTC_PMIC, PMIC_PWR_ENABLE); 130277042Sloos 131277042Sloos return (0); 132277042Sloos} 133277042Sloos 134277042Sloosstatic int 135277042Sloosam335x_rtc_detach(device_t dev) 136277042Sloos{ 137277042Sloos struct am335x_rtc_softc *sc; 138277042Sloos 139277042Sloos sc = device_get_softc(dev); 140279462Sdim if (sc->sc_irq_res[0] != NULL) 141277042Sloos bus_release_resources(dev, am335x_rtc_irq_spec, sc->sc_irq_res); 142277042Sloos if (sc->sc_mem_res) 143277042Sloos bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 144277042Sloos RTC_LOCK_DESTROY(sc); 145277042Sloos 146277042Sloos return (0); 147277042Sloos} 148277042Sloos 149277042Sloosvoid 150277042Sloosam335x_rtc_pmic_pwr_toggle(void) 151277042Sloos{ 152277042Sloos int timeout; 153277042Sloos struct clocktime ct; 154277042Sloos struct timespec ts; 155277042Sloos 156277042Sloos /* 157277042Sloos * We stop the RTC so we don't need to check the STATUS.BUSY bit 158277042Sloos * before update ALARM2 registers. 159277042Sloos */ 160277042Sloos timeout = 10; 161277042Sloos RTC_WRITE4(rtc_sc, RTC_CTRL, 0); 162277042Sloos while (--timeout && RTC_READ4(rtc_sc, RTC_STATUS) & RTC_STATUS_RUN) 163277042Sloos DELAY(100); 164277042Sloos if (timeout == 0) { 165277042Sloos device_printf(rtc_sc->sc_dev, "RTC does not stop.\n"); 166277042Sloos return; 167277042Sloos } 168277042Sloos /* Program the ALARM2 to fire in 2 seconds. */ 169277042Sloos ct.dow = 0; 170277042Sloos ct.nsec = 0; 171277042Sloos ct.sec = FROMBCD(RTC_READ4(rtc_sc, RTC_SECONDS) & 0x7f); 172277042Sloos ct.min = FROMBCD(RTC_READ4(rtc_sc, RTC_MINUTES) & 0x7f); 173277042Sloos ct.hour = FROMBCD(RTC_READ4(rtc_sc, RTC_HOURS) & 0x3f); 174277042Sloos ct.day = FROMBCD(RTC_READ4(rtc_sc, RTC_DAYS) & 0x3f); 175277042Sloos ct.mon = FROMBCD(RTC_READ4(rtc_sc, RTC_MONTHS) & 0x1f); 176277042Sloos ct.year = FROMBCD(RTC_READ4(rtc_sc, RTC_YEARS) & 0xff); 177277042Sloos ct.year += POSIX_BASE_YEAR; 178277042Sloos clock_ct_to_ts(&ct, &ts); 179277042Sloos ts.tv_sec += 2; 180277042Sloos clock_ts_to_ct(&ts, &ct); 181277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_SECONDS, TOBCD(ct.sec)); 182277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_MINUTES, TOBCD(ct.min)); 183277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_HOURS, TOBCD(ct.hour)); 184277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_DAYS, TOBCD(ct.day)); 185277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_MONTHS, TOBCD(ct.mon)); 186277042Sloos RTC_WRITE4(rtc_sc, RTC_ALARM2_YEARS, TOBCD(ct.year - POSIX_BASE_YEAR)); 187277042Sloos /* Enable ALARM2 interrupt. */ 188277042Sloos RTC_WRITE4(rtc_sc, RTC_INTR, RTC_INTR_ALARM2); 189277042Sloos /* Start count. */ 190277042Sloos RTC_WRITE4(rtc_sc, RTC_CTRL, RTC_CTRL_RUN); 191277042Sloos} 192277042Sloos 193277042Sloosstatic device_method_t am335x_rtc_methods[] = { 194277042Sloos DEVMETHOD(device_probe, am335x_rtc_probe), 195277042Sloos DEVMETHOD(device_attach, am335x_rtc_attach), 196277042Sloos DEVMETHOD(device_detach, am335x_rtc_detach), 197277042Sloos 198277042Sloos DEVMETHOD_END 199277042Sloos}; 200277042Sloos 201277042Sloosstatic driver_t am335x_rtc_driver = { 202277042Sloos "am335x_rtc", 203277042Sloos am335x_rtc_methods, 204277042Sloos sizeof(struct am335x_rtc_softc), 205277042Sloos}; 206277042Sloos 207277042Sloosstatic devclass_t am335x_rtc_devclass; 208277042Sloos 209277042SloosDRIVER_MODULE(am335x_rtc, simplebus, am335x_rtc_driver, am335x_rtc_devclass, 0, 0); 210277042SloosMODULE_VERSION(am335x_rtc, 1); 211277042SloosMODULE_DEPEND(am335x_rtc, simplebus, 1, 1, 1); 212