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