1 1.25 thorpej /* $NetBSD: rtc.c,v 1.25 2025/09/07 21:45:13 thorpej Exp $ */ 2 1.1 gmcgarry 3 1.1 gmcgarry /* 4 1.20 rmind * Copyright (c) 1988 University of Utah. 5 1.1 gmcgarry * Copyright (c) 1982, 1990, 1993 6 1.1 gmcgarry * The Regents of the University of California. All rights reserved. 7 1.1 gmcgarry * 8 1.1 gmcgarry * This code is derived from software contributed to Berkeley by 9 1.1 gmcgarry * the Systems Programming Group of the University of Utah Computer 10 1.1 gmcgarry * Science Department. 11 1.1 gmcgarry * 12 1.1 gmcgarry * Redistribution and use in source and binary forms, with or without 13 1.1 gmcgarry * modification, are permitted provided that the following conditions 14 1.1 gmcgarry * are met: 15 1.1 gmcgarry * 1. Redistributions of source code must retain the above copyright 16 1.1 gmcgarry * notice, this list of conditions and the following disclaimer. 17 1.1 gmcgarry * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 gmcgarry * notice, this list of conditions and the following disclaimer in the 19 1.1 gmcgarry * documentation and/or other materials provided with the distribution. 20 1.9 agc * 3. Neither the name of the University nor the names of its contributors 21 1.9 agc * may be used to endorse or promote products derived from this software 22 1.9 agc * without specific prior written permission. 23 1.9 agc * 24 1.9 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.9 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.9 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.9 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.9 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.9 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.9 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.9 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.9 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.9 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.9 agc * SUCH DAMAGE. 35 1.9 agc * 36 1.9 agc * from: Utah $Hdr: clock.c 1.18 91/01/21$ 37 1.9 agc * 38 1.9 agc * @(#)clock.c 8.2 (Berkeley) 1/12/94 39 1.9 agc */ 40 1.1 gmcgarry 41 1.1 gmcgarry /* 42 1.1 gmcgarry * attachment for HP300 real-time clock (RTC) 43 1.1 gmcgarry */ 44 1.1 gmcgarry 45 1.3 gmcgarry #include <sys/cdefs.h> 46 1.25 thorpej __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.25 2025/09/07 21:45:13 thorpej Exp $"); 47 1.3 gmcgarry 48 1.1 gmcgarry #include <sys/param.h> 49 1.1 gmcgarry #include <sys/systm.h> 50 1.1 gmcgarry #include <sys/device.h> 51 1.1 gmcgarry 52 1.1 gmcgarry #include <hp300/dev/intiovar.h> 53 1.1 gmcgarry #include <hp300/dev/rtcreg.h> 54 1.1 gmcgarry 55 1.1 gmcgarry #include <dev/clock_subr.h> 56 1.1 gmcgarry 57 1.1 gmcgarry struct rtc_softc { 58 1.19 tsutsui device_t sc_dev; 59 1.1 gmcgarry bus_space_tag_t sc_bst; 60 1.1 gmcgarry bus_space_handle_t sc_bsh; 61 1.13 tsutsui struct todr_chip_handle sc_handle; 62 1.1 gmcgarry }; 63 1.1 gmcgarry 64 1.19 tsutsui static int rtcmatch(device_t, cfdata_t, void *); 65 1.19 tsutsui static void rtcattach(device_t, device_t, void *aux); 66 1.1 gmcgarry 67 1.19 tsutsui CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc), 68 1.6 thorpej rtcmatch, rtcattach, NULL, NULL); 69 1.1 gmcgarry 70 1.18 tsutsui static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 71 1.18 tsutsui static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); 72 1.12 tsutsui static uint8_t rtc_readreg(struct rtc_softc *, int); 73 1.12 tsutsui static uint8_t rtc_writereg(struct rtc_softc *, int, uint8_t); 74 1.1 gmcgarry 75 1.1 gmcgarry 76 1.1 gmcgarry static int 77 1.19 tsutsui rtcmatch(device_t parent, cfdata_t cf, void *aux) 78 1.1 gmcgarry { 79 1.1 gmcgarry struct intio_attach_args *ia = aux; 80 1.1 gmcgarry 81 1.21 tsutsui /* 425e doesn't have the traditional RTC at intio */ 82 1.21 tsutsui if (machineid == HP_425 && mmuid == MMUID_425_E) 83 1.21 tsutsui return 0; 84 1.21 tsutsui 85 1.4 gmcgarry if (strcmp("rtc", ia->ia_modname) != 0) 86 1.16 tsutsui return 0; 87 1.1 gmcgarry 88 1.16 tsutsui return 1; 89 1.1 gmcgarry } 90 1.1 gmcgarry 91 1.1 gmcgarry static void 92 1.19 tsutsui rtcattach(device_t parent, device_t self, void *aux) 93 1.1 gmcgarry { 94 1.19 tsutsui struct rtc_softc *sc = device_private(self); 95 1.1 gmcgarry struct intio_attach_args *ia = aux; 96 1.1 gmcgarry struct todr_chip_handle *todr_handle; 97 1.7 tsutsui bus_space_tag_t bst = ia->ia_bst; 98 1.1 gmcgarry 99 1.19 tsutsui sc->sc_dev = self; 100 1.7 tsutsui if (bus_space_map(bst, ia->ia_iobase, INTIO_DEVSIZE, 0, 101 1.1 gmcgarry &sc->sc_bsh)) { 102 1.19 tsutsui aprint_error(": can't map registers\n"); 103 1.1 gmcgarry return; 104 1.1 gmcgarry } 105 1.7 tsutsui 106 1.19 tsutsui aprint_normal("\n"); 107 1.19 tsutsui 108 1.7 tsutsui sc->sc_bst = bst; 109 1.1 gmcgarry 110 1.13 tsutsui todr_handle = &sc->sc_handle; 111 1.25 thorpej todr_handle->todr_dev = self; 112 1.18 tsutsui todr_handle->todr_gettime_ymdhms = rtc_gettime_ymdhms; 113 1.18 tsutsui todr_handle->todr_settime_ymdhms = rtc_settime_ymdhms; 114 1.1 gmcgarry 115 1.8 tsutsui todr_attach(todr_handle); 116 1.1 gmcgarry } 117 1.1 gmcgarry 118 1.1 gmcgarry static int 119 1.18 tsutsui rtc_gettime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt) 120 1.1 gmcgarry { 121 1.25 thorpej struct rtc_softc *sc = device_private(handle->todr_dev); 122 1.18 tsutsui int i, year; 123 1.18 tsutsui bool read_okay; 124 1.12 tsutsui uint8_t rtc_registers[NUM_RTC_REGS]; 125 1.1 gmcgarry 126 1.1 gmcgarry /* read rtc registers */ 127 1.18 tsutsui read_okay = false; 128 1.1 gmcgarry while (!read_okay) { 129 1.18 tsutsui read_okay = true; 130 1.1 gmcgarry for (i = 0; i < NUM_RTC_REGS; i++) 131 1.1 gmcgarry rtc_registers[i] = rtc_readreg(sc, i); 132 1.1 gmcgarry for (i = 0; i < NUM_RTC_REGS; i++) 133 1.1 gmcgarry if (rtc_registers[i] != rtc_readreg(sc, i)) 134 1.18 tsutsui read_okay = false; 135 1.1 gmcgarry } 136 1.1 gmcgarry 137 1.22 tsutsui #define rtc_to_decimal(a,b) (rtc_registers[a] * 10 + rtc_registers[b]) 138 1.1 gmcgarry 139 1.18 tsutsui dt->dt_sec = rtc_to_decimal(1, 0); 140 1.18 tsutsui dt->dt_min = rtc_to_decimal(3, 2); 141 1.18 tsutsui dt->dt_hour = (rtc_registers[5] & RTC_REG5_HOUR) * 10 + 142 1.18 tsutsui rtc_registers[4]; 143 1.18 tsutsui dt->dt_day = rtc_to_decimal(8, 7); 144 1.18 tsutsui dt->dt_mon = rtc_to_decimal(10, 9); 145 1.1 gmcgarry 146 1.1 gmcgarry year = rtc_to_decimal(12, 11) + RTC_BASE_YEAR; 147 1.1 gmcgarry if (year < POSIX_BASE_YEAR) 148 1.1 gmcgarry year += 100; 149 1.18 tsutsui dt->dt_year = year; 150 1.1 gmcgarry 151 1.1 gmcgarry #undef rtc_to_decimal 152 1.1 gmcgarry 153 1.16 tsutsui return 0; 154 1.1 gmcgarry } 155 1.1 gmcgarry 156 1.1 gmcgarry static int 157 1.18 tsutsui rtc_settime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt) 158 1.1 gmcgarry { 159 1.25 thorpej struct rtc_softc *sc = device_private(handle->todr_dev); 160 1.1 gmcgarry int i, year; 161 1.12 tsutsui uint8_t rtc_registers[NUM_RTC_REGS]; 162 1.1 gmcgarry 163 1.18 tsutsui year = dt->dt_year - RTC_BASE_YEAR; 164 1.1 gmcgarry if (year > 99) 165 1.1 gmcgarry year -= 100; 166 1.1 gmcgarry 167 1.1 gmcgarry #define decimal_to_rtc(a,b,n) \ 168 1.1 gmcgarry rtc_registers[a] = (n) % 10; \ 169 1.1 gmcgarry rtc_registers[b] = (n) / 10; 170 1.1 gmcgarry 171 1.18 tsutsui decimal_to_rtc(0, 1, dt->dt_sec); 172 1.18 tsutsui decimal_to_rtc(2, 3, dt->dt_min); 173 1.18 tsutsui decimal_to_rtc(7, 8, dt->dt_day); 174 1.18 tsutsui decimal_to_rtc(9, 10, dt->dt_mon); 175 1.1 gmcgarry decimal_to_rtc(11, 12, year); 176 1.1 gmcgarry 177 1.18 tsutsui rtc_registers[4] = dt->dt_hour % 10; 178 1.18 tsutsui rtc_registers[5] = ((dt->dt_hour / 10) & RTC_REG5_HOUR) | RTC_REG5_24HR; 179 1.1 gmcgarry 180 1.1 gmcgarry rtc_registers[6] = 0; 181 1.1 gmcgarry 182 1.1 gmcgarry #undef decimal_to_rtc 183 1.1 gmcgarry 184 1.1 gmcgarry /* write rtc registers */ 185 1.1 gmcgarry rtc_writereg(sc, 15, 13); /* reset prescalar */ 186 1.1 gmcgarry for (i = 0; i < NUM_RTC_REGS; i++) 187 1.1 gmcgarry if (rtc_registers[i] != 188 1.1 gmcgarry rtc_writereg(sc, i, rtc_registers[i])) 189 1.16 tsutsui return 1; 190 1.16 tsutsui return 0; 191 1.1 gmcgarry } 192 1.1 gmcgarry 193 1.12 tsutsui static uint8_t 194 1.1 gmcgarry rtc_readreg(struct rtc_softc *sc, int reg) 195 1.1 gmcgarry { 196 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 197 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 198 1.12 tsutsui uint8_t data; 199 1.1 gmcgarry int s = splvm(); 200 1.1 gmcgarry 201 1.1 gmcgarry data = reg; 202 1.1 gmcgarry intio_device_writecmd(bst, bsh, RTC_SET_REG, &data, 1); 203 1.1 gmcgarry intio_device_readcmd(bst, bsh, RTC_READ_REG, &data); 204 1.1 gmcgarry 205 1.1 gmcgarry splx(s); 206 1.16 tsutsui return data; 207 1.1 gmcgarry } 208 1.1 gmcgarry 209 1.12 tsutsui static uint8_t 210 1.12 tsutsui rtc_writereg(struct rtc_softc *sc, int reg, uint8_t data) 211 1.1 gmcgarry { 212 1.1 gmcgarry bus_space_tag_t bst = sc->sc_bst; 213 1.1 gmcgarry bus_space_handle_t bsh = sc->sc_bsh; 214 1.12 tsutsui uint8_t tmp; 215 1.1 gmcgarry int s = splvm(); 216 1.1 gmcgarry 217 1.1 gmcgarry tmp = (data << 4) | reg; 218 1.1 gmcgarry intio_device_writecmd(bst, bsh, RTC_SET_REG, &tmp, 1); 219 1.1 gmcgarry intio_device_writecmd(bst, bsh, RTC_WRITE_REG, NULL, 0); 220 1.1 gmcgarry intio_device_readcmd(bst, bsh, RTC_READ_REG, &tmp); 221 1.1 gmcgarry 222 1.1 gmcgarry splx(s); 223 1.16 tsutsui return tmp; 224 1.1 gmcgarry } 225