1 /* $NetBSD: ds1743.c,v 1.10 2014/11/20 16:34:25 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2001-2002 Wasabi Sysetms, Inc. 5 * Copyright (c) 1998 Mark Brinicombe. 6 * Copyright (c) 1998 Causality Limited. 7 * All rights reserved. 8 * 9 * Written by Mark Brinicombe, Causality Limited 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Mark Brinicombe 22 * for the NetBSD Project. 23 * 4. The name of the company nor the name of the author may be used to 24 * endorse or promote products derived from this software without specific 25 * prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS 28 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: ds1743.c,v 1.10 2014/11/20 16:34:25 christos Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <dev/clock_subr.h> 47 48 #include <machine/rtc.h> 49 #include <sys/bus.h> 50 51 #include <evbppc/walnut/dev/ds1743reg.h> 52 #include <evbppc/walnut/dev/pbusvar.h> 53 54 struct dsrtc_softc { 55 device_t sc_dev; 56 bus_space_tag_t sc_iot; 57 bus_space_handle_t sc_ioh; 58 struct todr_chip_handle sc_todr; 59 }; 60 61 static void dsrtcattach(device_t, device_t, void *); 62 static int dsrtcmatch(device_t, cfdata_t, void *); 63 #if 0 /* Nothing uses these yet */ 64 static int ds1743_ram_read(struct dsrtc_softc *, int); 65 static void ds1743_ram_write(struct dsrtc_softc *, int, int); 66 #endif 67 68 static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *); 69 static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *); 70 static inline u_char ds1743_read(struct dsrtc_softc *, int); 71 static inline void ds1743_write(struct dsrtc_softc *, int, u_char); 72 static u_char ds1743_lock(struct dsrtc_softc *, u_char); 73 static void ds1743_unlock(struct dsrtc_softc *, u_char); 74 75 /* device and attach structures */ 76 CFATTACH_DECL_NEW(ds1743rtc, sizeof(struct dsrtc_softc), 77 dsrtcmatch, dsrtcattach, NULL, NULL); 78 79 /* 80 * dsrtcmatch() 81 * 82 * Validate the IIC address to make sure its an RTC we understand 83 */ 84 int ds1743found = 0; 85 86 #define DS_SCRATCH_ADDR 0x1FF7 87 88 static int 89 dsrtcmatch(device_t parent, cfdata_t cf, void *aux) 90 { 91 struct pbus_attach_args *paa = aux; 92 int retval = !ds1743found; 93 bus_space_handle_t h; 94 u_int8_t x; 95 96 /* match only RTC devices */ 97 if (strcmp(paa->pb_name, cf->cf_name) != 0) 98 return 0; 99 100 if (bus_space_map(paa->pb_bt, paa->pb_addr, DS_SIZE, 0, &h)) { 101 printf("%s: can't map i/o space\n", paa->pb_name); 102 return 0; 103 } 104 105 /* Read one byte of what's supposed to be NVRAM */ 106 x = bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR); 107 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0xAA); 108 if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0xAA) { 109 retval = 0; 110 goto done; 111 } 112 113 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0x55); 114 if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0x55) { 115 retval = 0; 116 goto done; 117 } 118 119 /* Restore scratch byte value */ 120 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, x); 121 done: 122 bus_space_unmap(paa->pb_bt, h, DS_SIZE); 123 124 return retval; 125 } 126 127 /* 128 * dsrtcattach() 129 * 130 * Attach the rtc device 131 */ 132 133 static void 134 dsrtcattach(device_t parent, device_t self, void *aux) 135 { 136 struct dsrtc_softc *sc = device_private(self); 137 struct pbus_attach_args *paa = aux; 138 139 ds1743found = 1; 140 141 sc->sc_dev = self; 142 sc->sc_iot = paa->pb_bt; 143 if (bus_space_map(sc->sc_iot, paa->pb_addr, DS_SIZE, 0, &sc->sc_ioh)) { 144 printf(": can't map i/o space\n"); 145 return; 146 } 147 148 ds1743_unlock(sc, 0); /* Make sure the clock is running */ 149 if ((ds1743_read(sc, DS_DAY) & DS_CTL_BF) == 0) 150 printf(": lithium cell is dead, RTC unreliable"); 151 printf("\n"); 152 153 sc->sc_todr.todr_gettime_ymdhms = dsrtc_read; 154 sc->sc_todr.todr_settime_ymdhms = dsrtc_write; 155 sc->sc_todr.cookie = sc; 156 157 #ifdef DEBUG 158 { 159 struct clock_ymdhms dt; 160 dsrtc_read(&sc->sc_todr, &dt); 161 printf("RTC: %d/%d/%04d %d:%02d:%02d\n", 162 dt.dt_mon, dt.dt_day, dt.dt_year, 163 dt.dt_hour, dt.dt_min, dt.dt_sec); 164 } 165 #endif 166 167 todr_attach(&sc->sc_todr); 168 } 169 170 static inline u_char 171 ds1743_read(struct dsrtc_softc *sc, int addr) 172 { 173 174 return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr)); 175 } 176 177 static inline void 178 ds1743_write(struct dsrtc_softc *sc, int addr, u_char data) 179 { 180 181 bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data); 182 } 183 184 185 #if 0 /* Nothing uses these yet */ 186 static u_char 187 ds1743_ram_read(struct dsrtc_softc *sc, int addr) 188 { 189 190 if (addr >= DS_RAM_SIZE) 191 return(-1); 192 return(ds1743_read(sc, addr)); 193 } 194 195 static void 196 ds1743_ram_write(struct dsrtc_softc *sc, int addr, u_char val) 197 { 198 199 if (addr >= DS_RAM_SIZE) 200 return (-1); 201 ds1743_write(sc, addr, val); 202 } 203 #endif 204 205 #define BCD(x) ((((x) / 10) << 4) | (x % 10)) 206 #define unBCD(v, x) v = x; v = ((v >> 4) & 0xf) * 10 + (v & 0xf) 207 208 static u_char 209 ds1743_lock(struct dsrtc_softc *sc, u_char mode) 210 { 211 u_char octl, ctl; 212 213 octl = ds1743_read(sc, DS_CENTURY); 214 ctl = octl | (mode & DS_CTL_RW); 215 ds1743_write(sc, DS_CENTURY, ctl); /* Lock RTC for both reading and writing */ 216 return octl; 217 } 218 219 static void 220 ds1743_unlock(struct dsrtc_softc *sc, u_char key) 221 { 222 int ctl; 223 224 ctl = ds1743_read(sc, DS_CENTURY); 225 ctl = (ctl & 0x3f) | (key & DS_CTL_RW); 226 ds1743_write(sc, DS_CENTURY, ctl); /* Enable updates */ 227 } 228 229 static int 230 dsrtc_write(todr_chip_handle_t tch, struct clock_ymdhms *dt) 231 { 232 struct dsrtc_softc *sc = tch->cookie; 233 u_char key; 234 235 key = ds1743_lock(sc, DS_CTL_W); 236 237 ds1743_write(sc, DS_SECONDS, bintobcd(dt->dt_sec) & 0x7f); 238 ds1743_write(sc, DS_MINUTES, bintobcd(dt->dt_min) & 0x7f); 239 ds1743_write(sc, DS_HOURS, bintobcd(dt->dt_hour) & 0x3f); 240 ds1743_write(sc, DS_DATE, bintobcd(dt->dt_day) & 0x3f); 241 ds1743_write(sc, DS_MONTH, bintobcd(dt->dt_mon) & 0x1f); 242 ds1743_write(sc, DS_YEAR, bintobcd(dt->dt_year % 100)); 243 ds1743_write(sc, DS_CENTURY, ((ds1743_read(sc, DS_CENTURY) & DS_CTL_RW) 244 | bintobcd(dt->dt_year / 100))); 245 246 ds1743_unlock(sc, key); 247 return(0); 248 } 249 250 static int 251 dsrtc_read(todr_chip_handle_t tch, struct clock_ymdhms *dt) 252 { 253 struct dsrtc_softc *sc = tch->cookie; 254 u_char key; 255 256 key = ds1743_lock(sc, DS_CTL_R); 257 dt->dt_sec = bcdtobin(ds1743_read(sc, DS_SECONDS) & 0x7f); 258 dt->dt_min = bcdtobin(ds1743_read(sc, DS_MINUTES) & 0x7f); 259 dt->dt_hour = bcdtobin(ds1743_read(sc, DS_HOURS) & 0x3f); 260 dt->dt_day = bcdtobin(ds1743_read(sc, DS_DATE) & 0x3f); 261 dt->dt_mon = bcdtobin(ds1743_read(sc, DS_MONTH) & 0x1f); 262 dt->dt_year = 263 bcdtobin(ds1743_read(sc, DS_YEAR)) + 264 bcdtobin(ds1743_read(sc, DS_CENTURY) & ~DS_CTL_RW) * 100; 265 266 ds1743_unlock(sc, key); 267 return(0); 268 } 269