1 /* $NetBSD: rtc.c,v 1.6 2008/12/16 22:35:25 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.6 2008/12/16 22:35:25 christos Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/device.h> 38 #include <sys/malloc.h> 39 #include <sys/systm.h> 40 #ifdef GPROF 41 #include <sys/gmon.h> 42 #endif 43 44 #include <dev/clock_subr.h> 45 46 #include <sh3/rtcreg.h> 47 48 #if defined(DEBUG) && !defined(RTC_DEBUG) 49 #define RTC_DEBUG 50 #endif 51 52 53 struct rtc_softc { 54 device_t sc_dev; 55 56 int sc_valid; 57 struct todr_chip_handle sc_todr; 58 }; 59 60 static int rtc_match(device_t, cfdata_t, void *); 61 static void rtc_attach(device_t, device_t, void *); 62 63 CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc), 64 rtc_match, rtc_attach, NULL, NULL); 65 66 67 /* todr(9) methods */ 68 static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 69 static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 70 71 72 73 static int 74 rtc_match(device_t parent, cfdata_t cfp, void *aux) 75 { 76 77 return 1; 78 } 79 80 81 static void 82 rtc_attach(device_t parent, device_t self, void *aux) 83 { 84 struct rtc_softc *sc; 85 uint8_t r; 86 #ifdef RTC_DEBUG 87 char bits[128]; 88 #endif 89 90 aprint_naive("\n"); 91 aprint_normal("\n"); 92 93 sc = device_private(self); 94 sc->sc_dev = self; 95 96 r = _reg_read_1(SH_(RCR2)); 97 98 #ifdef RTC_DEBUG 99 snprintb(bits, sizeof(bits), SH_RCR2_BITS, r); 100 aprint_debug_dev(sc->sc_dev, "RCR2=%s\n", bits); 101 #endif 102 103 /* Was the clock running? */ 104 if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE 105 | SH_RCR2_START)) 106 sc->sc_valid = 1; 107 else { 108 sc->sc_valid = 0; 109 aprint_error_dev(sc->sc_dev, "WARNING: clock was stopped\n"); 110 } 111 112 /* Disable carry and alarm interrupts */ 113 _reg_write_1(SH_(RCR1), 0); 114 115 /* Clock runs, no periodic interrupts, no 30-sec adjustment */ 116 _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START); 117 118 sc->sc_todr.cookie = sc; 119 sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms; 120 sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms; 121 122 todr_attach(&sc->sc_todr); 123 124 #ifdef RTC_DEBUG 125 { 126 struct clock_ymdhms dt; 127 rtc_gettime_ymdhms(&sc->sc_todr, &dt); 128 } 129 #endif 130 } 131 132 133 static int 134 rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt) 135 { 136 struct rtc_softc *sc = h->cookie; 137 unsigned int year; 138 int retry = 8; 139 140 if (!sc->sc_valid) { 141 #ifdef RTC_DEBUG 142 aprint_debug_dev(sc->sc_dev, "gettime: not valid\n"); 143 /* but proceed and read/print it anyway */ 144 #else 145 return EIO; 146 #endif 147 } 148 149 /* disable carry interrupt */ 150 _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE); 151 152 do { 153 uint8_t r = _reg_read_1(SH_(RCR1)); 154 r &= ~SH_RCR1_CF; 155 r |= SH_RCR1_AF; /* don't clear alarm flag */ 156 _reg_write_1(SH_(RCR1), r); 157 158 if (CPU_IS_SH3) 159 year = _reg_read_1(SH3_RYRCNT); 160 else 161 year = _reg_read_2(SH4_RYRCNT) & 0x00ff; 162 dt->dt_year = FROMBCD(year); 163 164 /* read counter */ 165 #define RTCGET(x, y) \ 166 dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT))) 167 168 RTCGET(mon, MON); 169 RTCGET(wday, WK); 170 RTCGET(day, DAY); 171 RTCGET(hour, HR); 172 RTCGET(min, MIN); 173 RTCGET(sec, SEC); 174 #undef RTCGET 175 } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0); 176 177 if (retry == 0) { 178 #ifdef RTC_DEBUG 179 aprint_debug_dev(sc->sc_dev, "gettime: retry failed\n"); 180 #endif 181 return EIO; 182 } 183 184 dt->dt_year += 1900; 185 if (dt->dt_year < POSIX_BASE_YEAR) 186 dt->dt_year += 100; 187 188 #ifdef RTC_DEBUG 189 aprint_debug_dev(sc->sc_dev, 190 "gettime: %04d-%02d-%02d %02d:%02d:%02d\n", 191 dt->dt_year, dt->dt_mon, dt->dt_day, 192 dt->dt_hour, dt->dt_min, dt->dt_sec); 193 194 if (!sc->sc_valid) 195 return EIO; 196 #endif 197 198 return 0; 199 } 200 201 202 static int 203 rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt) 204 { 205 struct rtc_softc *sc = h->cookie; 206 unsigned int year; 207 uint8_t r; 208 209 year = TOBCD(dt->dt_year % 100); 210 211 r = _reg_read_1(SH_(RCR2)); 212 213 /* stop clock */ 214 _reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET); 215 216 /* set time */ 217 if (CPU_IS_SH3) 218 _reg_write_1(SH3_RYRCNT, year); 219 else 220 _reg_write_2(SH4_RYRCNT, year); 221 222 #define RTCSET(x, y) \ 223 _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y)) 224 225 RTCSET(MON, mon); 226 RTCSET(WK, wday); 227 RTCSET(DAY, day); 228 RTCSET(HR, hour); 229 RTCSET(MIN, min); 230 RTCSET(SEC, sec); 231 232 #undef RTCSET 233 234 /* start clock */ 235 _reg_write_1(SH_(RCR2), r); 236 sc->sc_valid = 1; 237 238 #ifdef RTC_DEBUG 239 aprint_debug_dev(sc->sc_dev, 240 "settime: %04d-%02d-%02d %02d:%02d:%02d\n", 241 dt->dt_year, dt->dt_mon, dt->dt_day, 242 dt->dt_hour, dt->dt_min, dt->dt_sec); 243 #endif 244 245 return 0; 246 } 247