1 /* $NetBSD: rtc.c,v 1.8 2010/05/22 15:51:32 tsutsui 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.8 2010/05/22 15:51:32 tsutsui 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 u_int sc_year0; 59 }; 60 61 static int rtc_match(device_t, cfdata_t, void *); 62 static void rtc_attach(device_t, device_t, void *); 63 64 CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc), 65 rtc_match, rtc_attach, NULL, NULL); 66 67 68 /* todr(9) methods */ 69 static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 70 static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 71 72 #ifndef SH3_RTC_BASEYEAR 73 #define SH3_RTC_BASEYEAR 1900 74 #endif 75 u_int sh3_rtc_baseyear = SH3_RTC_BASEYEAR; 76 77 static int 78 rtc_match(device_t parent, cfdata_t cfp, void *aux) 79 { 80 81 return 1; 82 } 83 84 85 static void 86 rtc_attach(device_t parent, device_t self, void *aux) 87 { 88 struct rtc_softc *sc; 89 uint8_t r; 90 prop_number_t prop_rtc_baseyear; 91 #ifdef RTC_DEBUG 92 char bits[128]; 93 #endif 94 95 aprint_naive("\n"); 96 aprint_normal("\n"); 97 98 sc = device_private(self); 99 sc->sc_dev = self; 100 101 r = _reg_read_1(SH_(RCR2)); 102 103 #ifdef RTC_DEBUG 104 snprintb(bits, sizeof(bits), SH_RCR2_BITS, r); 105 aprint_debug_dev(sc->sc_dev, "RCR2=%s\n", bits); 106 #endif 107 108 /* Was the clock running? */ 109 if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE 110 | SH_RCR2_START)) 111 sc->sc_valid = 1; 112 else { 113 sc->sc_valid = 0; 114 aprint_error_dev(sc->sc_dev, "WARNING: clock was stopped\n"); 115 } 116 117 /* Disable carry and alarm interrupts */ 118 _reg_write_1(SH_(RCR1), 0); 119 120 /* Clock runs, no periodic interrupts, no 30-sec adjustment */ 121 _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START); 122 123 sc->sc_todr.cookie = sc; 124 sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms; 125 sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms; 126 127 prop_rtc_baseyear = prop_dictionary_get(device_properties(self), 128 "sh3_rtc_baseyear"); 129 if (prop_rtc_baseyear != NULL) { 130 sh3_rtc_baseyear = 131 (u_int)prop_number_integer_value(prop_rtc_baseyear); 132 #ifdef RTC_DEBUG 133 aprint_debug_dev(self, 134 "using baseyear %u passed via device property\n", 135 sh3_rtc_baseyear); 136 #endif 137 } 138 sc->sc_year0 = sh3_rtc_baseyear; 139 140 todr_attach(&sc->sc_todr); 141 142 #ifdef RTC_DEBUG 143 { 144 struct clock_ymdhms dt; 145 rtc_gettime_ymdhms(&sc->sc_todr, &dt); 146 } 147 #endif 148 149 if (!pmf_device_register(self, NULL, NULL)) 150 aprint_error_dev(self, "unable to establish power handler\n"); 151 } 152 153 154 static int 155 rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt) 156 { 157 struct rtc_softc *sc = h->cookie; 158 unsigned int year; 159 int retry = 8; 160 161 if (!sc->sc_valid) { 162 #ifdef RTC_DEBUG 163 aprint_debug_dev(sc->sc_dev, "gettime: not valid\n"); 164 /* but proceed and read/print it anyway */ 165 #else 166 return EIO; 167 #endif 168 } 169 170 /* disable carry interrupt */ 171 _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE); 172 173 do { 174 uint8_t r = _reg_read_1(SH_(RCR1)); 175 r &= ~SH_RCR1_CF; 176 r |= SH_RCR1_AF; /* don't clear alarm flag */ 177 _reg_write_1(SH_(RCR1), r); 178 179 if (CPU_IS_SH3) 180 year = _reg_read_1(SH3_RYRCNT); 181 else 182 year = _reg_read_2(SH4_RYRCNT) & 0x00ff; 183 dt->dt_year = FROMBCD(year); 184 185 /* read counter */ 186 #define RTCGET(x, y) \ 187 dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT))) 188 189 RTCGET(mon, MON); 190 RTCGET(wday, WK); 191 RTCGET(day, DAY); 192 RTCGET(hour, HR); 193 RTCGET(min, MIN); 194 RTCGET(sec, SEC); 195 #undef RTCGET 196 } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0); 197 198 if (retry == 0) { 199 #ifdef RTC_DEBUG 200 aprint_debug_dev(sc->sc_dev, "gettime: retry failed\n"); 201 #endif 202 return EIO; 203 } 204 205 dt->dt_year += sc->sc_year0; 206 if (dt->dt_year < POSIX_BASE_YEAR) 207 dt->dt_year += 100; 208 209 #ifdef RTC_DEBUG 210 aprint_debug_dev(sc->sc_dev, 211 "gettime: %04d-%02d-%02d %02d:%02d:%02d\n", 212 dt->dt_year, dt->dt_mon, dt->dt_day, 213 dt->dt_hour, dt->dt_min, dt->dt_sec); 214 215 if (!sc->sc_valid) 216 return EIO; 217 #endif 218 219 return 0; 220 } 221 222 223 static int 224 rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt) 225 { 226 struct rtc_softc *sc = h->cookie; 227 unsigned int year; 228 uint8_t r; 229 230 year = dt->dt_year - sc->sc_year0; 231 if (year > 99) 232 year -= 100; 233 234 year = TOBCD(year); 235 236 r = _reg_read_1(SH_(RCR2)); 237 238 /* stop clock */ 239 _reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET); 240 241 /* set time */ 242 if (CPU_IS_SH3) 243 _reg_write_1(SH3_RYRCNT, year); 244 else 245 _reg_write_2(SH4_RYRCNT, year); 246 247 #define RTCSET(x, y) \ 248 _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y)) 249 250 RTCSET(MON, mon); 251 RTCSET(WK, wday); 252 RTCSET(DAY, day); 253 RTCSET(HR, hour); 254 RTCSET(MIN, min); 255 RTCSET(SEC, sec); 256 257 #undef RTCSET 258 259 /* start clock */ 260 _reg_write_1(SH_(RCR2), r); 261 sc->sc_valid = 1; 262 263 #ifdef RTC_DEBUG 264 aprint_debug_dev(sc->sc_dev, 265 "settime: %04d-%02d-%02d %02d:%02d:%02d\n", 266 dt->dt_year, dt->dt_mon, dt->dt_day, 267 dt->dt_hour, dt->dt_min, dt->dt_sec); 268 #endif 269 270 return 0; 271 } 272