1 /* $NetBSD: ds1743.c,v 1.7 2006/09/18 22:05:47 gdamore 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.7 2006/09/18 22:05:47 gdamore 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 <machine/bus.h> 50 51 #include <evbppc/walnut/dev/ds1743reg.h> 52 #include <evbppc/walnut/dev/pbusvar.h> 53 54 struct dsrtc_softc { 55 struct device 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(struct device *, struct device *, void *); 62 static int dsrtcmatch(struct device *, struct cfdata *, 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(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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux) 135 { 136 struct dsrtc_softc *sc = (struct dsrtc_softc *)self; 137 struct pbus_attach_args *paa = aux; 138 139 ds1743found = 1; 140 141 sc->sc_iot = paa->pb_bt; 142 if (bus_space_map(sc->sc_iot, paa->pb_addr, DS_SIZE, 0, &sc->sc_ioh)) { 143 printf(": can't map i/o space\n"); 144 return; 145 } 146 147 ds1743_unlock(sc, 0); /* Make sure the clock is running */ 148 if ((ds1743_read(sc, DS_DAY) & DS_CTL_BF) == 0) 149 printf(": lithium cell is dead, RTC unreliable"); 150 printf("\n"); 151 152 #ifdef DEBUG 153 { 154 rtc_t rtc; 155 dsrtc_read(sc, &rtc); 156 printf("RTC: %d/%d/%02d%02d %d:%02d:%02d\n", 157 rtc.rtc_mon, rtc.rtc_day, rtc.rtc_cen, rtc.rtc_year, 158 rtc.rtc_hour, rtc.rtc_min, rtc.rtc_sec); 159 } 160 #endif 161 162 sc->sc_todr.todr_gettime_ymdhms = dsrtc_read; 163 sc->sc_todr.todr_settime_ymdhms = dsrtc_write; 164 sc->sc_todr.cookie = sc; 165 todr_attach(&sc->sc_todr); 166 } 167 168 static inline u_char 169 ds1743_read(struct dsrtc_softc *sc, int addr) 170 { 171 172 return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr)); 173 } 174 175 static inline void 176 ds1743_write(struct dsrtc_softc *sc, int addr, u_char data) 177 { 178 179 bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data); 180 } 181 182 183 #if 0 /* Nothing uses these yet */ 184 static u_char 185 ds1743_ram_read(struct dsrtc_softc *sc, int addr) 186 { 187 188 if (addr >= DS_RAM_SIZE) 189 return(-1); 190 return(ds1743_read(sc, addr)); 191 } 192 193 static void 194 ds1743_ram_write(struct dsrtc_softc *sc, int addr, u_char val) 195 { 196 197 if (addr >= DS_RAM_SIZE) 198 return (-1); 199 ds1743_write(sc, addr, val); 200 } 201 #endif 202 203 #define BCD(x) ((((x) / 10) << 4) | (x % 10)) 204 #define unBCD(v, x) v = x; v = ((v >> 4) & 0xf) * 10 + (v & 0xf) 205 206 static u_char 207 ds1743_lock(struct dsrtc_softc *sc, u_char mode) 208 { 209 u_char octl, ctl; 210 211 octl = ds1743_read(sc, DS_CENTURY); 212 ctl = octl | (mode & DS_CTL_RW); 213 ds1743_write(sc, DS_CENTURY, ctl); /* Lock RTC for both reading and writing */ 214 return octl; 215 } 216 217 static void 218 ds1743_unlock(struct dsrtc_softc *sc, u_char key) 219 { 220 int ctl; 221 222 ctl = ds1743_read(sc, DS_CENTURY); 223 ctl = (ctl & 0x3f) | (key & DS_CTL_RW); 224 ds1743_write(sc, DS_CENTURY, ctl); /* Enable updates */ 225 } 226 227 static int 228 dsrtc_write(todr_chip_handle_t tch, struct clock_ymdhms *dt) 229 { 230 struct dsrtc_softc *sc = tch->cookie; 231 u_char key; 232 233 key = ds1743_lock(sc, DS_CTL_W); 234 235 ds1743_write(sc, DS_SECONDS, TOBCD(dt->dt_sec) & 0x7f); 236 ds1743_write(sc, DS_MINUTES, TOBCD(dt->dt_min) & 0x7f); 237 ds1743_write(sc, DS_HOURS, TOBCD(dt->dt_hour) & 0x3f); 238 ds1743_write(sc, DS_DATE, TOBCD(dt->dt_day) & 0x3f); 239 ds1743_write(sc, DS_MONTH, TOBCD(dt->dt_mon) & 0x1f); 240 ds1743_write(sc, DS_YEAR, TOBCD(dt->dt_year % 100)); 241 ds1743_write(sc, DS_CENTURY, ((ds1743_read(sc, DS_CENTURY) & DS_CTL_RW) 242 | TOBCD(dt->dt_year / 100))); 243 244 ds1743_unlock(sc, key); 245 return(0); 246 } 247 248 static int 249 dsrtc_read(todr_chip_handle_t tch, struct clock_ymdhms *dt) 250 { 251 struct dsrtc_softc *sc = tch->cookie; 252 u_char key; 253 254 key = ds1743_lock(sc, DS_CTL_R); 255 dt->dt_sec = FROMBCD(ds1743_read(sc, DS_SECONDS) & 0x7f); 256 dt->dt_min = FROMBCD(ds1743_read(sc, DS_MINUTES) & 0x7f); 257 dt->dt_hour = FROMBCD(ds1743_read(sc, DS_HOURS) & 0x3f); 258 dt->dt_day = FROMBCD(ds1743_read(sc, DS_DATE) & 0x3f); 259 dt->dt_mon = FROMBCD(ds1743_read(sc, DS_MONTH) & 0x1f); 260 dt->dt_year = 261 FROMBCD(ds1743_read(sc, DS_YEAR)) + 262 FROMBCD(ds1743_read(sc, DS_CENTURY) & ~DS_CTL_RW) * 100; 263 264 ds1743_unlock(sc, key); 265 return(0); 266 } 267