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