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