1210397Sandrew/* 2210397Sandrew * Copyright (C) 2010 Andrew Turner 3210397Sandrew * All rights reserved. 4210397Sandrew * 5210397Sandrew * Redistribution and use in source and binary forms, with or without 6210397Sandrew * modification, are permitted provided that the following conditions 7210397Sandrew * are met: 8210397Sandrew * 1. Redistributions of source code must retain the above copyright 9210397Sandrew * notice, this list of conditions and the following disclaimer. 10210397Sandrew * 2. Redistributions in binary form must reproduce the above copyright 11210397Sandrew * notice, this list of conditions and the following disclaimer in the 12210397Sandrew * documentation and/or other materials provided with the distribution. 13210397Sandrew * 14210397Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15210397Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210397Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210397Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18210397Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210397Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210397Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210397Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210397Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210397Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210397Sandrew * SUCH DAMAGE. 25210397Sandrew * 26210397Sandrew */ 27210397Sandrew 28210397Sandrew#include <sys/cdefs.h> 29210397Sandrew__FBSDID("$FreeBSD$"); 30210397Sandrew#include <sys/param.h> 31210397Sandrew#include <sys/bus.h> 32210397Sandrew#include <sys/time.h> 33210397Sandrew#include <sys/clock.h> 34210397Sandrew#include <sys/resource.h> 35210397Sandrew#include <sys/systm.h> 36210397Sandrew#include <sys/rman.h> 37210397Sandrew#include <sys/kernel.h> 38210397Sandrew#include <sys/module.h> 39210397Sandrew 40210397Sandrew#include <machine/bus.h> 41210397Sandrew 42210397Sandrew#include <arm/s3c2xx0/s3c24x0reg.h> 43210397Sandrew 44210397Sandrew#include "clock_if.h" 45210397Sandrew 46210397Sandrew#define YEAR_BASE 2000 47210397Sandrew 48210397Sandrewstruct s3c2xx0_rtc_softc { 49210397Sandrew struct resource *mem_res; 50210397Sandrew}; 51210397Sandrew 52210397Sandrewstatic int 53210397Sandrews3c2xx0_rtc_probe(device_t dev) 54210397Sandrew{ 55210397Sandrew 56210397Sandrew device_set_desc(dev, "Samsung Integrated RTC"); 57210397Sandrew return (0); 58210397Sandrew} 59210397Sandrew 60210397Sandrewstatic int 61210397Sandrews3c2xx0_rtc_attach(device_t dev) 62210397Sandrew{ 63210397Sandrew struct s3c2xx0_rtc_softc *sc; 64210397Sandrew int error, rid; 65210397Sandrew 66210397Sandrew sc = device_get_softc(dev); 67210397Sandrew error = 0; 68210397Sandrew 69210397Sandrew rid = 0; 70210397Sandrew sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 71210397Sandrew RF_ACTIVE); 72210397Sandrew if (sc->mem_res == NULL) { 73210397Sandrew error = ENOMEM; 74210397Sandrew goto out; 75210397Sandrew } 76210397Sandrew 77210397Sandrew bus_write_1(sc->mem_res, RTC_RTCCON, RTCCON_RTCEN); 78210397Sandrew clock_register(dev, 1000000); 79210397Sandrew 80210397Sandrewout: 81210397Sandrew return (error); 82210397Sandrew} 83210397Sandrew 84210397Sandrewstatic int 85210397Sandrews3c2xx0_rtc_gettime(device_t dev, struct timespec *ts) 86210397Sandrew{ 87210397Sandrew struct s3c2xx0_rtc_softc *sc; 88210397Sandrew struct clocktime ct; 89210397Sandrew 90210397Sandrew#define READ_TIME() do { \ 91210397Sandrew ct.year = YEAR_BASE + FROMBCD(bus_read_1(sc->mem_res, RTC_BCDYEAR)); \ 92210397Sandrew ct.mon = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDMON)); \ 93210397Sandrew ct.dow = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDDAY)); \ 94210397Sandrew ct.day = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDDATE)); \ 95210397Sandrew ct.hour = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDHOUR)); \ 96210397Sandrew ct.min = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDMIN)); \ 97210397Sandrew ct.sec = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDSEC)); \ 98210397Sandrew} while (0) 99210397Sandrew 100210397Sandrew sc = device_get_softc(dev); 101210397Sandrew 102210397Sandrew ct.nsec = 0; 103210397Sandrew READ_TIME(); 104210397Sandrew /* 105210397Sandrew * Check if we could have read incorrect values 106210397Sandrew * as the values could have changed. 107210397Sandrew */ 108210397Sandrew if (ct.sec == 0) { 109210397Sandrew READ_TIME(); 110210397Sandrew } 111210397Sandrew 112210397Sandrew ct.dow = -1; 113210397Sandrew 114210397Sandrew#undef READ_TIME 115210397Sandrew return (clock_ct_to_ts(&ct, ts)); 116210397Sandrew} 117210397Sandrew 118210397Sandrewstatic int 119210397Sandrews3c2xx0_rtc_settime(device_t dev, struct timespec *ts) 120210397Sandrew{ 121210397Sandrew struct s3c2xx0_rtc_softc *sc; 122210397Sandrew struct clocktime ct; 123210397Sandrew 124210397Sandrew sc = device_get_softc(dev); 125210397Sandrew 126210397Sandrew /* Resolution: 1 sec */ 127210397Sandrew if (ts->tv_nsec >= 500000000) 128210397Sandrew ts->tv_sec++; 129210397Sandrew ts->tv_nsec = 0; 130210397Sandrew clock_ts_to_ct(ts, &ct); 131210397Sandrew 132210397Sandrew bus_write_1(sc->mem_res, RTC_BCDSEC, TOBCD(ct.sec)); 133210397Sandrew bus_write_1(sc->mem_res, RTC_BCDMIN, TOBCD(ct.min)); 134210397Sandrew bus_write_1(sc->mem_res, RTC_BCDHOUR, TOBCD(ct.hour)); 135210397Sandrew bus_write_1(sc->mem_res, RTC_BCDDATE, TOBCD(ct.day)); 136210397Sandrew bus_write_1(sc->mem_res, RTC_BCDDAY, TOBCD(ct.dow)); 137210397Sandrew bus_write_1(sc->mem_res, RTC_BCDMON, TOBCD(ct.mon)); 138210397Sandrew bus_write_1(sc->mem_res, RTC_BCDYEAR, TOBCD(ct.year - YEAR_BASE)); 139210397Sandrew 140210397Sandrew return (0); 141210397Sandrew} 142210397Sandrew 143210397Sandrewstatic device_method_t s3c2xx0_rtc_methods[] = { 144210397Sandrew DEVMETHOD(device_probe, s3c2xx0_rtc_probe), 145210397Sandrew DEVMETHOD(device_attach, s3c2xx0_rtc_attach), 146210397Sandrew 147210397Sandrew DEVMETHOD(clock_gettime, s3c2xx0_rtc_gettime), 148210397Sandrew DEVMETHOD(clock_settime, s3c2xx0_rtc_settime), 149210397Sandrew 150210397Sandrew { 0, 0 }, 151210397Sandrew}; 152210397Sandrew 153210397Sandrewstatic driver_t s3c2xx0_rtc_driver = { 154210397Sandrew "rtc", 155210397Sandrew s3c2xx0_rtc_methods, 156210397Sandrew sizeof(struct s3c2xx0_rtc_softc), 157210397Sandrew}; 158210397Sandrewstatic devclass_t s3c2xx0_rtc_devclass; 159210397Sandrew 160210397SandrewDRIVER_MODULE(s3c2xx0_rtc, s3c24x0, s3c2xx0_rtc_driver, s3c2xx0_rtc_devclass, 161210397Sandrew 0, 0); 162210397Sandrew 163