1 /* $NetBSD: dsrtc.c,v 1.11 2009/07/21 07:35:55 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.11 2009/07/21 07:35:55 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 55 struct dsrtc_softc { 56 struct device sc_dev; 57 bus_space_tag_t sc_iot; 58 bus_space_handle_t sc_ioh; 59 struct todr_chip_handle sc_todr; 60 }; 61 62 void dsrtcattach(struct device *parent, struct device *self, void *aux); 63 int dsrtcmatch(struct device *parent, struct cfdata *cf, void *aux); 64 int ds1687_read(struct dsrtc_softc *sc, int addr); 65 void ds1687_write(struct dsrtc_softc *sc, int addr, int data); 66 #if 0 67 int ds1687_ram_read(struct dsrtc_softc *sc, int addr); 68 void ds1687_ram_write(struct dsrtc_softc *sc, int addr, int data); 69 #endif 70 static void ds1687_bank_select(struct dsrtc_softc *, int); 71 static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *); 72 static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *); 73 74 int 75 ds1687_read(struct dsrtc_softc *sc, int addr) 76 { 77 78 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr); 79 return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG)); 80 } 81 82 void 83 ds1687_write(struct dsrtc_softc *sc, int addr, int data) 84 { 85 86 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr); 87 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data); 88 } 89 90 static void 91 ds1687_bank_select(struct dsrtc_softc *sc, int bank) 92 { 93 int data; 94 95 data = ds1687_read(sc, RTC_REG_A); 96 data &= ~RTC_REG_A_BANK_MASK; 97 if (bank) 98 data |= RTC_REG_A_BANK1; 99 ds1687_write(sc, RTC_REG_A, data); 100 } 101 102 #if 0 103 /* Nothing uses these yet */ 104 int 105 ds1687_ram_read(struct dsrtc_softc *sc, int addr) 106 { 107 if (addr < RTC_PC_RAM_SIZE) 108 return(ds1687_read(sc, RTC_PC_RAM_START + addr)); 109 110 addr -= RTC_PC_RAM_SIZE; 111 if (addr < RTC_BANK0_RAM_SIZE) 112 return(ds1687_read(sc, RTC_BANK0_RAM_START + addr)); 113 114 addr -= RTC_BANK0_RAM_SIZE; 115 if (addr < RTC_EXT_RAM_SIZE) { 116 int data; 117 118 ds1687_bank_select(sc, 1); 119 ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr); 120 data = ds1687_read(sc, RTC_EXT_RAM_DATA); 121 ds1687_bank_select(sc, 0); 122 return(data); 123 } 124 return(-1); 125 } 126 127 void 128 ds1687_ram_write(struct dsrtc_softc *sc, int addr, int val) 129 { 130 if (addr < RTC_PC_RAM_SIZE) 131 return(ds1687_write(sc, RTC_PC_RAM_START + addr, val)); 132 133 addr -= RTC_PC_RAM_SIZE; 134 if (addr < RTC_BANK0_RAM_SIZE) 135 return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val)); 136 137 addr -= RTC_BANK0_RAM_SIZE; 138 if (addr < RTC_EXT_RAM_SIZE) { 139 ds1687_bank_select(sc, 1); 140 ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr); 141 ds1687_write(sc, RTC_EXT_RAM_DATA, val); 142 ds1687_bank_select(sc, 0); 143 } 144 } 145 #endif 146 147 static int 148 dsrtc_write(todr_chip_handle_t tc, struct clock_ymdhms *dt) 149 { 150 struct dsrtc_softc *sc = tc->cookie; 151 152 ds1687_write(sc, RTC_SECONDS, dt->dt_sec); 153 ds1687_write(sc, RTC_MINUTES, dt->dt_min); 154 ds1687_write(sc, RTC_HOURS, dt->dt_hour); 155 ds1687_write(sc, RTC_DAYOFMONTH, dt->dt_day); 156 ds1687_write(sc, RTC_MONTH, dt->dt_mon); 157 ds1687_write(sc, RTC_YEAR, dt->dt_year % 100); 158 ds1687_bank_select(sc, 1); 159 ds1687_write(sc, RTC_CENTURY, dt->dt_year / 100); 160 ds1687_bank_select(sc, 0); 161 return(0); 162 } 163 164 static int 165 dsrtc_read(todr_chip_handle_t tc, struct clock_ymdhms *dt) 166 { 167 struct dsrtc_softc *sc = tc->cookie; 168 169 dt->dt_sec = ds1687_read(sc, RTC_SECONDS); 170 dt->dt_min = ds1687_read(sc, RTC_MINUTES); 171 dt->dt_hour = ds1687_read(sc, RTC_HOURS); 172 dt->dt_day = ds1687_read(sc, RTC_DAYOFMONTH); 173 dt->dt_mon = ds1687_read(sc, RTC_MONTH); 174 dt->dt_year = ds1687_read(sc, RTC_YEAR); 175 ds1687_bank_select(sc, 1); 176 dt->dt_year += ds1687_read(sc, RTC_CENTURY) * 100; 177 ds1687_bank_select(sc, 0); 178 179 return(0); 180 } 181 182 /* device and attach structures */ 183 CFATTACH_DECL_NEW(ds1687rtc, sizeof(struct dsrtc_softc), 184 dsrtcmatch, dsrtcattach, NULL, NULL); 185 186 /* 187 * dsrtcmatch() 188 * 189 * Validate the IIC address to make sure its an RTC we understand 190 */ 191 192 int 193 dsrtcmatch(device_t parent, cfdata_t cf, void *aux) 194 { 195 struct isa_attach_args *ia = aux; 196 197 if (ia->ia_nio < 1 || 198 ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 199 return (0); 200 201 ia->ia_nio = 1; 202 ia->ia_io[0].ir_size = NRTC_PORTS; 203 204 ia->ia_niomem = 0; 205 ia->ia_nirq = 0; 206 ia->ia_ndrq = 0; 207 208 return(1); 209 } 210 211 /* 212 * dsrtcattach() 213 * 214 * Attach the rtc device 215 */ 216 217 void 218 dsrtcattach(device_t parent, device_t self, void *aux) 219 { 220 struct dsrtc_softc *sc = device_private(self); 221 struct isa_attach_args *ia = aux; 222 223 sc->sc_iot = ia->ia_iot; 224 if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, 225 ia->ia_io[0].ir_size, 0, &sc->sc_ioh)) { 226 aprint_error(": cannot map I/O space\n"); 227 return; 228 } 229 230 ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1); 231 ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR); 232 233 if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT)) 234 aprint_error(": lithium cell is dead, RTC unreliable"); 235 aprint_normal("\n"); 236 237 sc->sc_todr.todr_gettime_ymdhms = dsrtc_read; 238 sc->sc_todr.todr_settime_ymdhms = dsrtc_write; 239 sc->sc_todr.cookie = sc; 240 todr_attach(&sc->sc_todr); 241 } 242 243 /* End of dsrtc.c */ 244