lpc_rtc.c revision 261410
1170754Sdelphij/*- 2170754Sdelphij * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> 3170754Sdelphij * All rights reserved. 4170754Sdelphij * 5170754Sdelphij * Redistribution and use in source and binary forms, with or without 6170754Sdelphij * modification, are permitted provided that the following conditions 7170754Sdelphij * are met: 8170754Sdelphij * 1. Redistributions of source code must retain the above copyright 9170754Sdelphij * notice, this list of conditions and the following disclaimer. 10170754Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11170754Sdelphij * notice, this list of conditions and the following disclaimer in the 12170754Sdelphij * documentation and/or other materials provided with the distribution. 13170754Sdelphij * 14170754Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15170754Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16170754Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17170754Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18170754Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19170754Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20170754Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21170754Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22170754Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23170754Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24170754Sdelphij * SUCH DAMAGE. 25170754Sdelphij * 26170754Sdelphij */ 27170754Sdelphij#include <sys/cdefs.h> 28170754Sdelphij__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_rtc.c 261410 2014-02-02 19:17:28Z ian $"); 29170754Sdelphij 30170754Sdelphij#include <sys/param.h> 31170754Sdelphij#include <sys/bus.h> 32239360Sobrien#include <sys/time.h> 33170754Sdelphij#include <sys/clock.h> 34170754Sdelphij#include <sys/resource.h> 35170754Sdelphij#include <sys/systm.h> 36170754Sdelphij#include <sys/rman.h> 37170754Sdelphij#include <sys/kernel.h> 38170754Sdelphij#include <sys/module.h> 39170754Sdelphij 40170754Sdelphij#include <machine/bus.h> 41170754Sdelphij#include <machine/resource.h> 42170754Sdelphij 43170754Sdelphij#include <dev/ofw/ofw_bus.h> 44170754Sdelphij#include <dev/ofw/ofw_bus_subr.h> 45170754Sdelphij 46170754Sdelphij#include <arm/lpc/lpcreg.h> 47170754Sdelphij 48170754Sdelphij#include "clock_if.h" 49170754Sdelphij 50170754Sdelphijstruct lpc_rtc_softc { 51170754Sdelphij device_t lr_dev; 52170754Sdelphij struct resource * lr_mem_res; 53170754Sdelphij bus_space_tag_t lr_bst; 54170754Sdelphij bus_space_handle_t lr_bsh; 55170754Sdelphij}; 56170754Sdelphij 57170754Sdelphijstatic int lpc_rtc_probe(device_t dev); 58170754Sdelphijstatic int lpc_rtc_attach(device_t dev); 59170754Sdelphijstatic int lpc_rtc_gettime(device_t dev, struct timespec *ts); 60239360Sobrienstatic int lpc_rtc_settime(device_t, struct timespec *); 61170754Sdelphij 62170754Sdelphijstatic int 63239360Sobrienlpc_rtc_probe(device_t dev) 64170754Sdelphij{ 65296568Struckman 66170754Sdelphij if (!ofw_bus_status_okay(dev)) 67170754Sdelphij return (ENXIO); 68170754Sdelphij 69170754Sdelphij if (!ofw_bus_is_compatible(dev, "lpc,rtc")) 70170754Sdelphij return (ENXIO); 71170754Sdelphij 72170754Sdelphij device_set_desc(dev, "LPC32x0 real time clock"); 73170754Sdelphij return (BUS_PROBE_DEFAULT); 74170754Sdelphij} 75170754Sdelphij 76170754Sdelphijstatic int 77170754Sdelphijlpc_rtc_attach(device_t dev) 78170754Sdelphij{ 79170754Sdelphij struct lpc_rtc_softc *sc = device_get_softc(dev); 80170754Sdelphij int rid = 0; 81170754Sdelphij 82170754Sdelphij sc->lr_dev = dev; 83170754Sdelphij 84170754Sdelphij clock_register(dev, 1000000); 85170754Sdelphij 86170754Sdelphij sc->lr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 87170754Sdelphij RF_ACTIVE); 88170754Sdelphij if (!sc->lr_mem_res) { 89170754Sdelphij device_printf(dev, "cannot allocate memory window\n"); 90170754Sdelphij return (ENXIO); 91170754Sdelphij } 92170754Sdelphij 93170754Sdelphij sc->lr_bst = rman_get_bustag(sc->lr_mem_res); 94170754Sdelphij sc->lr_bsh = rman_get_bushandle(sc->lr_mem_res); 95170754Sdelphij 96170754Sdelphij return (0); 97170754Sdelphij} 98170754Sdelphij 99170754Sdelphijstatic int 100170754Sdelphijlpc_rtc_gettime(device_t dev, struct timespec *ts) 101170754Sdelphij{ 102170754Sdelphij struct lpc_rtc_softc *sc = device_get_softc(dev); 103170754Sdelphij 104170754Sdelphij ts->tv_sec = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_UCOUNT); 105170754Sdelphij ts->tv_nsec = 0; 106170754Sdelphij 107170754Sdelphij return (0); 108170754Sdelphij} 109170754Sdelphij 110170754Sdelphijstatic int 111170754Sdelphijlpc_rtc_settime(device_t dev, struct timespec *ts) 112170754Sdelphij{ 113170754Sdelphij struct lpc_rtc_softc *sc = device_get_softc(dev); 114170754Sdelphij uint32_t ctrl; 115170754Sdelphij 116170754Sdelphij /* Stop RTC */ 117170754Sdelphij ctrl = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL); 118170754Sdelphij bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL, ctrl | LPC_RTC_CTRL_DISABLE); 119170754Sdelphij 120170754Sdelphij /* Write actual value */ 121170754Sdelphij bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_UCOUNT, ts->tv_sec); 122170754Sdelphij 123170754Sdelphij /* Start RTC */ 124170754Sdelphij ctrl = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL); 125170754Sdelphij bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL, ctrl & ~LPC_RTC_CTRL_DISABLE); 126170754Sdelphij 127170754Sdelphij return (0); 128170754Sdelphij} 129170754Sdelphij 130170754Sdelphijstatic device_method_t lpc_rtc_methods[] = { 131170754Sdelphij /* Device interface */ 132170754Sdelphij DEVMETHOD(device_probe, lpc_rtc_probe), 133170754Sdelphij DEVMETHOD(device_attach, lpc_rtc_attach), 134170754Sdelphij 135170754Sdelphij /* Clock interface */ 136170754Sdelphij DEVMETHOD(clock_gettime, lpc_rtc_gettime), 137170754Sdelphij DEVMETHOD(clock_settime, lpc_rtc_settime), 138170754Sdelphij 139170754Sdelphij { 0, 0 }, 140170754Sdelphij}; 141170754Sdelphij 142170754Sdelphijstatic driver_t lpc_rtc_driver = { 143170754Sdelphij "rtc", 144170754Sdelphij lpc_rtc_methods, 145170754Sdelphij sizeof(struct lpc_rtc_softc), 146170754Sdelphij}; 147170754Sdelphij 148170754Sdelphijstatic devclass_t lpc_rtc_devclass; 149170754Sdelphij 150170754SdelphijDRIVER_MODULE(rtc, simplebus, lpc_rtc_driver, lpc_rtc_devclass, 0, 0); 151170754Sdelphij