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