1/*-- 2 * Copyright (c) 2012 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Paul Fleischer <paul@xpg.dk> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29#include <sys/cdefs.h> 30#include <sys/types.h> 31#include <sys/param.h> 32#include <sys/device.h> 33#include <sys/bus.h> 34#include <sys/time.h> 35 36#include <dev/clock_subr.h> 37 38#include <arm/s3c2xx0/s3c24x0var.h> 39#include <arm/s3c2xx0/s3c2440var.h> 40#include <arm/s3c2xx0/s3c2440reg.h> 41 42#ifdef SSRTC_DEBUG 43#define DPRINTF(s) do { printf s; } while (/*CONSTCOND*/0) 44#else 45#define DPRINTF(s) do {} while (/*CONSTCOND*/0) 46#endif 47 48/* As the RTC keeps track of Leap years, we need to use the right zero-year */ 49#define SSRTC_YEAR_ZERO 2000 50 51struct ssrtc_softc { 52 device_t sc_dev; 53 bus_space_tag_t sc_iot; 54 bus_space_handle_t sc_ioh; 55 struct todr_chip_handle sc_todr; 56}; 57 58static int ssrtc_match(device_t, cfdata_t, void *); 59static void ssrtc_attach(device_t, device_t, void *); 60 61CFATTACH_DECL_NEW(ssrtc, sizeof(struct ssrtc_softc), 62 ssrtc_match, ssrtc_attach, NULL, NULL); 63 64static int ssrtc_todr_gettime(struct todr_chip_handle *, struct timeval *); 65static int ssrtc_todr_settime(struct todr_chip_handle *, struct timeval *); 66 67static int 68ssrtc_match(device_t parent, cfdata_t cf, void *aux) 69{ 70 return 1; 71} 72 73static void 74ssrtc_attach(device_t parent, device_t self, void *aux) 75{ 76 struct ssrtc_softc *sc = device_private(self); 77 struct s3c2xx0_attach_args *sa = aux; 78 79 sc->sc_dev = self; 80 sc->sc_iot = sa->sa_iot; 81 82 if (bus_space_map(sc->sc_iot, S3C2440_RTC_BASE, 83 S3C2440_RTC_SIZE, 0, &sc->sc_ioh)) { 84 aprint_error(": failed to map registers"); 85 return; 86 } 87 aprint_normal(": RTC \n"); 88 89 sc->sc_todr.cookie = sc; 90 sc->sc_todr.todr_gettime = ssrtc_todr_gettime; 91 sc->sc_todr.todr_settime = ssrtc_todr_settime; 92 sc->sc_todr.todr_setwen = NULL; 93 94 todr_attach(&sc->sc_todr); 95} 96 97static int 98ssrtc_todr_gettime(struct todr_chip_handle *h, struct timeval *tv) 99{ 100 struct ssrtc_softc *sc = h->cookie; 101 struct clock_ymdhms dt; 102 uint8_t reg; 103 104 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDSEC); 105 DPRINTF(("BCDSEC: %02X\n", reg)); 106 dt.dt_sec = FROMBCD(reg); 107 108 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDMIN); 109 DPRINTF(("BCDMIN: %02X\n", reg)); 110 dt.dt_min = FROMBCD(reg); 111 112 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDHOUR); 113 DPRINTF(("BCDHOUR: %02X\n", reg)); 114 dt.dt_hour = FROMBCD(reg); 115 116 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDDATE); 117 DPRINTF(("BCDDATE: %02X\n", reg)); 118 dt.dt_day = FROMBCD(reg); 119 120 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDDAY); 121 DPRINTF(("BCDDAY: %02X\n", reg)); 122 dt.dt_wday = FROMBCD(reg); 123 124 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDMON); 125 DPRINTF(("BCDMON: %02X\n", reg)); 126 dt.dt_mon = FROMBCD(reg); 127 128 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_BCDYEAR); 129 DPRINTF(("BCDYEAR: %02X\n", reg)); 130 dt.dt_year = SSRTC_YEAR_ZERO + FROMBCD(reg); 131 132 DPRINTF(("Seconds: %d\n", dt.dt_sec)); 133 DPRINTF(("Minutes: %d\n", dt.dt_min)); 134 DPRINTF(("Hour: %d\n", dt.dt_hour)); 135 DPRINTF(("Mon: %d\n", dt.dt_mon)); 136 DPRINTF(("Date: %d\n", dt.dt_day)); 137 DPRINTF(("Day: %d\n", dt.dt_wday)); 138 DPRINTF(("Year: %d\n", dt.dt_year)); 139 140 tv->tv_sec = clock_ymdhms_to_secs(&dt); 141 tv->tv_usec = 0; 142 143 return 0; 144} 145 146static int 147ssrtc_todr_settime(struct todr_chip_handle *h, struct timeval *tv) 148{ 149 struct ssrtc_softc *sc = h->cookie; 150 struct clock_ymdhms dt; 151 uint8_t reg; 152 153 clock_secs_to_ymdhms(tv->tv_sec, &dt); 154 155 DPRINTF(("ssrtc_todr_settime")); 156 157 /* Set RTCEN */ 158 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_RTCCON); 159 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_RTCCON, reg | RTCCON_RTCEN); 160 161 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDSEC, TOBCD(dt.dt_sec)); 162 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDMIN, TOBCD(dt.dt_min)); 163 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDHOUR, TOBCD(dt.dt_hour)); 164 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDDATE, TOBCD(dt.dt_day)); 165 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDDAY, TOBCD(dt.dt_wday)); 166 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDMON, TOBCD(dt.dt_mon)); 167 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_BCDYEAR, TOBCD(dt.dt_year-SSRTC_YEAR_ZERO)); 168 169 /* Clear RTCEN */ 170 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_RTCCON); 171 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_RTCCON, reg & ~RTCCON_RTCEN); 172 return 0; 173} 174