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