1 1.14 thorpej /* $NetBSD: dsrtc.c,v 1.14 2025/09/07 21:45:11 thorpej Exp $ */ 2 1.1 chris 3 1.1 chris /* 4 1.1 chris * Copyright (c) 1998 Mark Brinicombe. 5 1.1 chris * Copyright (c) 1998 Causality Limited. 6 1.1 chris * All rights reserved. 7 1.1 chris * 8 1.1 chris * Written by Mark Brinicombe, Causality Limited 9 1.1 chris * 10 1.1 chris * Redistribution and use in source and binary forms, with or without 11 1.1 chris * modification, are permitted provided that the following conditions 12 1.1 chris * are met: 13 1.1 chris * 1. Redistributions of source code must retain the above copyright 14 1.1 chris * notice, this list of conditions and the following disclaimer. 15 1.1 chris * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 chris * notice, this list of conditions and the following disclaimer in the 17 1.1 chris * documentation and/or other materials provided with the distribution. 18 1.1 chris * 3. All advertising materials mentioning features or use of this software 19 1.1 chris * must display the following acknowledgement: 20 1.1 chris * This product includes software developed by Mark Brinicombe 21 1.1 chris * for the NetBSD Project. 22 1.1 chris * 4. The name of the company nor the name of the author may be used to 23 1.1 chris * endorse or promote products derived from this software without specific 24 1.1 chris * prior written permission. 25 1.1 chris * 26 1.1 chris * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS 27 1.1 chris * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 1.1 chris * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 1.1 chris * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE 30 1.1 chris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 1.1 chris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 1.1 chris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 1.1 chris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 1.1 chris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 1.1 chris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 1.1 chris * SUCH DAMAGE. 37 1.1 chris */ 38 1.5 chris 39 1.5 chris #include <sys/cdefs.h> 40 1.14 thorpej __KERNEL_RCSID(0, "$NetBSD: dsrtc.c,v 1.14 2025/09/07 21:45:11 thorpej Exp $"); 41 1.1 chris 42 1.1 chris #include <sys/param.h> 43 1.1 chris #include <sys/systm.h> 44 1.1 chris #include <sys/kernel.h> 45 1.1 chris #include <sys/conf.h> 46 1.1 chris #include <sys/device.h> 47 1.1 chris 48 1.10 christos #include <dev/clock_subr.h> 49 1.1 chris #include <arm/footbridge/isa/ds1687reg.h> 50 1.1 chris 51 1.1 chris #include <dev/isa/isavar.h> 52 1.1 chris 53 1.1 chris #define NRTC_PORTS 2 54 1.1 chris 55 1.1 chris struct dsrtc_softc { 56 1.14 thorpej device_t sc_dev; 57 1.1 chris bus_space_tag_t sc_iot; 58 1.1 chris bus_space_handle_t sc_ioh; 59 1.10 christos struct todr_chip_handle sc_todr; 60 1.1 chris }; 61 1.1 chris 62 1.12 skrll void dsrtcattach(device_t parent, device_t self, void *aux); 63 1.12 skrll int dsrtcmatch(device_t parent, cfdata_t cf, void *aux); 64 1.9 gdamore int ds1687_read(struct dsrtc_softc *sc, int addr); 65 1.9 gdamore void ds1687_write(struct dsrtc_softc *sc, int addr, int data); 66 1.9 gdamore #if 0 67 1.9 gdamore int ds1687_ram_read(struct dsrtc_softc *sc, int addr); 68 1.9 gdamore void ds1687_ram_write(struct dsrtc_softc *sc, int addr, int data); 69 1.9 gdamore #endif 70 1.9 gdamore static void ds1687_bank_select(struct dsrtc_softc *, int); 71 1.10 christos static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *); 72 1.10 christos static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *); 73 1.1 chris 74 1.1 chris int 75 1.9 gdamore ds1687_read(struct dsrtc_softc *sc, int addr) 76 1.1 chris { 77 1.1 chris 78 1.1 chris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr); 79 1.1 chris return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG)); 80 1.1 chris } 81 1.1 chris 82 1.1 chris void 83 1.9 gdamore ds1687_write(struct dsrtc_softc *sc, int addr, int data) 84 1.1 chris { 85 1.1 chris 86 1.1 chris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr); 87 1.1 chris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data); 88 1.1 chris } 89 1.1 chris 90 1.1 chris static void 91 1.9 gdamore ds1687_bank_select(struct dsrtc_softc *sc, int bank) 92 1.1 chris { 93 1.1 chris int data; 94 1.1 chris 95 1.1 chris data = ds1687_read(sc, RTC_REG_A); 96 1.1 chris data &= ~RTC_REG_A_BANK_MASK; 97 1.1 chris if (bank) 98 1.1 chris data |= RTC_REG_A_BANK1; 99 1.1 chris ds1687_write(sc, RTC_REG_A, data); 100 1.1 chris } 101 1.1 chris 102 1.1 chris #if 0 103 1.1 chris /* Nothing uses these yet */ 104 1.1 chris int 105 1.9 gdamore ds1687_ram_read(struct dsrtc_softc *sc, int addr) 106 1.1 chris { 107 1.1 chris if (addr < RTC_PC_RAM_SIZE) 108 1.1 chris return(ds1687_read(sc, RTC_PC_RAM_START + addr)); 109 1.1 chris 110 1.1 chris addr -= RTC_PC_RAM_SIZE; 111 1.1 chris if (addr < RTC_BANK0_RAM_SIZE) 112 1.13 skrll return(ds1687_read(sc, RTC_BANK0_RAM_START + addr)); 113 1.1 chris 114 1.1 chris addr -= RTC_BANK0_RAM_SIZE; 115 1.1 chris if (addr < RTC_EXT_RAM_SIZE) { 116 1.1 chris int data; 117 1.1 chris 118 1.1 chris ds1687_bank_select(sc, 1); 119 1.1 chris ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr); 120 1.1 chris data = ds1687_read(sc, RTC_EXT_RAM_DATA); 121 1.1 chris ds1687_bank_select(sc, 0); 122 1.1 chris return(data); 123 1.1 chris } 124 1.1 chris return(-1); 125 1.1 chris } 126 1.1 chris 127 1.1 chris void 128 1.9 gdamore ds1687_ram_write(struct dsrtc_softc *sc, int addr, int val) 129 1.1 chris { 130 1.1 chris if (addr < RTC_PC_RAM_SIZE) 131 1.1 chris return(ds1687_write(sc, RTC_PC_RAM_START + addr, val)); 132 1.1 chris 133 1.1 chris addr -= RTC_PC_RAM_SIZE; 134 1.1 chris if (addr < RTC_BANK0_RAM_SIZE) 135 1.1 chris return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val)); 136 1.1 chris 137 1.1 chris addr -= RTC_BANK0_RAM_SIZE; 138 1.1 chris if (addr < RTC_EXT_RAM_SIZE) { 139 1.1 chris ds1687_bank_select(sc, 1); 140 1.1 chris ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr); 141 1.1 chris ds1687_write(sc, RTC_EXT_RAM_DATA, val); 142 1.1 chris ds1687_bank_select(sc, 0); 143 1.1 chris } 144 1.1 chris } 145 1.1 chris #endif 146 1.1 chris 147 1.1 chris static int 148 1.10 christos dsrtc_write(todr_chip_handle_t tc, struct clock_ymdhms *dt) 149 1.1 chris { 150 1.14 thorpej struct dsrtc_softc *sc = device_private(tc->todr_dev); 151 1.1 chris 152 1.10 christos ds1687_write(sc, RTC_SECONDS, dt->dt_sec); 153 1.10 christos ds1687_write(sc, RTC_MINUTES, dt->dt_min); 154 1.10 christos ds1687_write(sc, RTC_HOURS, dt->dt_hour); 155 1.10 christos ds1687_write(sc, RTC_DAYOFMONTH, dt->dt_day); 156 1.10 christos ds1687_write(sc, RTC_MONTH, dt->dt_mon); 157 1.10 christos ds1687_write(sc, RTC_YEAR, dt->dt_year % 100); 158 1.1 chris ds1687_bank_select(sc, 1); 159 1.10 christos ds1687_write(sc, RTC_CENTURY, dt->dt_year / 100); 160 1.1 chris ds1687_bank_select(sc, 0); 161 1.10 christos return(0); 162 1.1 chris } 163 1.1 chris 164 1.1 chris static int 165 1.10 christos dsrtc_read(todr_chip_handle_t tc, struct clock_ymdhms *dt) 166 1.1 chris { 167 1.14 thorpej struct dsrtc_softc *sc = device_private(tc->todr_dev); 168 1.1 chris 169 1.10 christos dt->dt_sec = ds1687_read(sc, RTC_SECONDS); 170 1.10 christos dt->dt_min = ds1687_read(sc, RTC_MINUTES); 171 1.10 christos dt->dt_hour = ds1687_read(sc, RTC_HOURS); 172 1.10 christos dt->dt_day = ds1687_read(sc, RTC_DAYOFMONTH); 173 1.10 christos dt->dt_mon = ds1687_read(sc, RTC_MONTH); 174 1.10 christos dt->dt_year = ds1687_read(sc, RTC_YEAR); 175 1.1 chris ds1687_bank_select(sc, 1); 176 1.10 christos dt->dt_year += ds1687_read(sc, RTC_CENTURY) * 100; 177 1.1 chris ds1687_bank_select(sc, 0); 178 1.1 chris 179 1.10 christos return(0); 180 1.1 chris } 181 1.1 chris 182 1.1 chris /* device and attach structures */ 183 1.11 skrll CFATTACH_DECL_NEW(ds1687rtc, sizeof(struct dsrtc_softc), 184 1.4 thorpej dsrtcmatch, dsrtcattach, NULL, NULL); 185 1.1 chris 186 1.1 chris /* 187 1.1 chris * dsrtcmatch() 188 1.1 chris * 189 1.1 chris * Validate the IIC address to make sure its an RTC we understand 190 1.1 chris */ 191 1.1 chris 192 1.1 chris int 193 1.11 skrll dsrtcmatch(device_t parent, cfdata_t cf, void *aux) 194 1.1 chris { 195 1.1 chris struct isa_attach_args *ia = aux; 196 1.1 chris 197 1.1 chris if (ia->ia_nio < 1 || 198 1.7 drochner ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 199 1.1 chris return (0); 200 1.1 chris 201 1.1 chris ia->ia_nio = 1; 202 1.1 chris ia->ia_io[0].ir_size = NRTC_PORTS; 203 1.1 chris 204 1.1 chris ia->ia_niomem = 0; 205 1.1 chris ia->ia_nirq = 0; 206 1.1 chris ia->ia_ndrq = 0; 207 1.1 chris 208 1.1 chris return(1); 209 1.1 chris } 210 1.1 chris 211 1.1 chris /* 212 1.1 chris * dsrtcattach() 213 1.1 chris * 214 1.1 chris * Attach the rtc device 215 1.1 chris */ 216 1.1 chris 217 1.1 chris void 218 1.11 skrll dsrtcattach(device_t parent, device_t self, void *aux) 219 1.1 chris { 220 1.11 skrll struct dsrtc_softc *sc = device_private(self); 221 1.1 chris struct isa_attach_args *ia = aux; 222 1.13 skrll 223 1.14 thorpej sc->sc_dev = self; 224 1.1 chris sc->sc_iot = ia->ia_iot; 225 1.1 chris if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, 226 1.1 chris ia->ia_io[0].ir_size, 0, &sc->sc_ioh)) { 227 1.11 skrll aprint_error(": cannot map I/O space\n"); 228 1.1 chris return; 229 1.1 chris } 230 1.1 chris 231 1.1 chris ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1); 232 1.1 chris ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR); 233 1.1 chris 234 1.1 chris if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT)) 235 1.11 skrll aprint_error(": lithium cell is dead, RTC unreliable"); 236 1.11 skrll aprint_normal("\n"); 237 1.1 chris 238 1.10 christos sc->sc_todr.todr_gettime_ymdhms = dsrtc_read; 239 1.10 christos sc->sc_todr.todr_settime_ymdhms = dsrtc_write; 240 1.14 thorpej sc->sc_todr.todr_dev = self; 241 1.10 christos todr_attach(&sc->sc_todr); 242 1.1 chris } 243 1.1 chris 244 1.1 chris /* End of dsrtc.c */ 245