s3c24x0_rtc.c revision 296373
1/* 2 * Copyright (C) 2010 Andrew Turner 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 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: releng/10.3/sys/arm/samsung/s3c2xx0/s3c24x0_rtc.c 272103 2014-09-25 11:38:26Z gavin $"); 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/time.h> 33#include <sys/clock.h> 34#include <sys/resource.h> 35#include <sys/systm.h> 36#include <sys/rman.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39 40#include <machine/bus.h> 41 42#include <arm/samsung/s3c2xx0/s3c24x0reg.h> 43 44#include "clock_if.h" 45 46#define YEAR_BASE 2000 47 48struct s3c2xx0_rtc_softc { 49 struct resource *mem_res; 50}; 51 52static int 53s3c2xx0_rtc_probe(device_t dev) 54{ 55 56 device_set_desc(dev, "Samsung Integrated RTC"); 57 return (0); 58} 59 60static int 61s3c2xx0_rtc_attach(device_t dev) 62{ 63 struct s3c2xx0_rtc_softc *sc; 64 int error, rid; 65 66 sc = device_get_softc(dev); 67 error = 0; 68 69 rid = 0; 70 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 71 RF_ACTIVE); 72 if (sc->mem_res == NULL) { 73 error = ENOMEM; 74 goto out; 75 } 76 77 bus_write_1(sc->mem_res, RTC_RTCCON, RTCCON_RTCEN); 78 clock_register(dev, 1000000); 79 80out: 81 return (error); 82} 83 84static int 85s3c2xx0_rtc_gettime(device_t dev, struct timespec *ts) 86{ 87 struct s3c2xx0_rtc_softc *sc; 88 struct clocktime ct; 89 90#define READ_TIME() do { \ 91 ct.year = YEAR_BASE + FROMBCD(bus_read_1(sc->mem_res, RTC_BCDYEAR)); \ 92 ct.mon = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDMON)); \ 93 ct.dow = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDDAY)); \ 94 ct.day = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDDATE)); \ 95 ct.hour = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDHOUR)); \ 96 ct.min = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDMIN)); \ 97 ct.sec = FROMBCD(bus_read_1(sc->mem_res, RTC_BCDSEC)); \ 98} while (0) 99 100 sc = device_get_softc(dev); 101 102 ct.nsec = 0; 103 READ_TIME(); 104 /* 105 * Check if we could have read incorrect values 106 * as the values could have changed. 107 */ 108 if (ct.sec == 0) { 109 READ_TIME(); 110 } 111 112 ct.dow = -1; 113 114#undef READ_TIME 115 return (clock_ct_to_ts(&ct, ts)); 116} 117 118static int 119s3c2xx0_rtc_settime(device_t dev, struct timespec *ts) 120{ 121 struct s3c2xx0_rtc_softc *sc; 122 struct clocktime ct; 123 124 sc = device_get_softc(dev); 125 126 /* Resolution: 1 sec */ 127 if (ts->tv_nsec >= 500000000) 128 ts->tv_sec++; 129 ts->tv_nsec = 0; 130 clock_ts_to_ct(ts, &ct); 131 132 bus_write_1(sc->mem_res, RTC_BCDSEC, TOBCD(ct.sec)); 133 bus_write_1(sc->mem_res, RTC_BCDMIN, TOBCD(ct.min)); 134 bus_write_1(sc->mem_res, RTC_BCDHOUR, TOBCD(ct.hour)); 135 bus_write_1(sc->mem_res, RTC_BCDDATE, TOBCD(ct.day)); 136 bus_write_1(sc->mem_res, RTC_BCDDAY, TOBCD(ct.dow)); 137 bus_write_1(sc->mem_res, RTC_BCDMON, TOBCD(ct.mon)); 138 bus_write_1(sc->mem_res, RTC_BCDYEAR, TOBCD(ct.year - YEAR_BASE)); 139 140 return (0); 141} 142 143static device_method_t s3c2xx0_rtc_methods[] = { 144 DEVMETHOD(device_probe, s3c2xx0_rtc_probe), 145 DEVMETHOD(device_attach, s3c2xx0_rtc_attach), 146 147 DEVMETHOD(clock_gettime, s3c2xx0_rtc_gettime), 148 DEVMETHOD(clock_settime, s3c2xx0_rtc_settime), 149 150 { 0, 0 }, 151}; 152 153static driver_t s3c2xx0_rtc_driver = { 154 "rtc", 155 s3c2xx0_rtc_methods, 156 sizeof(struct s3c2xx0_rtc_softc), 157}; 158static devclass_t s3c2xx0_rtc_devclass; 159 160DRIVER_MODULE(s3c2xx0_rtc, s3c24x0, s3c2xx0_rtc_driver, s3c2xx0_rtc_devclass, 161 0, 0); 162 163