1 /* $NetBSD: ds1743.c,v 1.6 2005/12/11 12:17:13 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.6 2005/12/11 12:17:13 christos Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 47 #include <machine/rtc.h> 48 #include <machine/bus.h> 49 50 #include <evbppc/walnut/dev/ds1743reg.h> 51 #include <evbppc/walnut/dev/todclockvar.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 }; 59 60 static void dsrtcattach(struct device *, struct device *, void *); 61 static int dsrtcmatch(struct device *, struct cfdata *, void *); 62 #if 0 /* Nothing uses these yet */ 63 static int ds1743_ram_read(struct dsrtc_softc *, int); 64 static void ds1743_ram_write(struct dsrtc_softc *, int, int); 65 #endif 66 67 static int dsrtc_read(void *, rtc_t *); 68 static int dsrtc_write(void *, rtc_t *); 69 static inline u_char ds1743_read(struct dsrtc_softc *, int); 70 static inline void ds1743_write(struct dsrtc_softc *, int, u_char); 71 static u_char ds1743_lock(struct dsrtc_softc *, u_char); 72 static void ds1743_unlock(struct dsrtc_softc *, u_char); 73 74 /* device and attach structures */ 75 CFATTACH_DECL(ds1743rtc, sizeof(struct dsrtc_softc), 76 dsrtcmatch, dsrtcattach, NULL, NULL); 77 78 /* 79 * dsrtcmatch() 80 * 81 * Validate the IIC address to make sure its an RTC we understand 82 */ 83 int ds1743found = 0; 84 85 #define DS_SCRATCH_ADDR 0x1FF7 86 87 static int 88 dsrtcmatch(struct device *parent, struct cfdata *cf, void *aux) 89 { 90 struct pbus_attach_args *paa = aux; 91 int retval = !ds1743found; 92 bus_space_handle_t h; 93 u_int8_t x; 94 95 /* match only RTC devices */ 96 if (strcmp(paa->pb_name, cf->cf_name) != 0) 97 return 0; 98 99 if (bus_space_map(paa->pb_bt, paa->pb_addr, DS_SIZE, 0, &h)) { 100 printf("%s: can't map i/o space\n", paa->pb_name); 101 return 0; 102 } 103 104 /* Read one byte of what's supposed to be NVRAM */ 105 x = bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR); 106 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0xAA); 107 if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0xAA) { 108 retval = 0; 109 goto done; 110 } 111 112 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0x55); 113 if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0x55) { 114 retval = 0; 115 goto done; 116 } 117 118 /* Restore scratch byte value */ 119 bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, x); 120 done: 121 bus_space_unmap(paa->pb_bt, h, DS_SIZE); 122 123 return retval; 124 } 125 126 /* 127 * dsrtcattach() 128 * 129 * Attach the rtc device 130 */ 131 132 static void 133 dsrtcattach(struct device *parent, struct device *self, void *aux) 134 { 135 struct dsrtc_softc *sc = (struct dsrtc_softc *)self; 136 struct pbus_attach_args *paa = aux; 137 struct todclock_attach_args ta; 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 163 ta.ta_name = "todclock"; 164 ta.ta_rtc_arg = sc; 165 ta.ta_rtc_write = dsrtc_write; 166 ta.ta_rtc_read = dsrtc_read; 167 ta.ta_flags = 0; 168 config_found(self, &ta, NULL); 169 } 170 171 static inline u_char 172 ds1743_read(struct dsrtc_softc *sc, int addr) 173 { 174 175 return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr)); 176 } 177 178 static inline void 179 ds1743_write(struct dsrtc_softc *sc, int addr, u_char data) 180 { 181 182 bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data); 183 } 184 185 186 #if 0 /* Nothing uses these yet */ 187 static u_char 188 ds1743_ram_read(struct dsrtc_softc *sc, int addr) 189 { 190 191 if (addr >= DS_RAM_SIZE) 192 return(-1); 193 return(ds1743_read(sc, addr)); 194 } 195 196 static void 197 ds1743_ram_write(struct dsrtc_softc *sc, int addr, u_char val) 198 { 199 200 if (addr >= DS_RAM_SIZE) 201 return (-1); 202 ds1743_write(sc, addr, val); 203 } 204 #endif 205 206 #define BCD(x) ((((x) / 10) << 4) | (x % 10)) 207 #define unBCD(v, x) v = x; v = ((v >> 4) & 0xf) * 10 + (v & 0xf) 208 209 static u_char 210 ds1743_lock(struct dsrtc_softc *sc, u_char mode) 211 { 212 u_char octl, ctl; 213 214 octl = ds1743_read(sc, DS_CENTURY); 215 ctl = octl | (mode & DS_CTL_RW); 216 ds1743_write(sc, DS_CENTURY, ctl); /* Lock RTC for both reading and writing */ 217 return octl; 218 } 219 220 static void 221 ds1743_unlock(struct dsrtc_softc *sc, u_char key) 222 { 223 int ctl; 224 225 ctl = ds1743_read(sc, DS_CENTURY); 226 ctl = (ctl & 0x3f) | (key & DS_CTL_RW); 227 ds1743_write(sc, DS_CENTURY, ctl); /* Enable updates */ 228 } 229 230 static int 231 dsrtc_write(void * arg, rtc_t * rtc) 232 { 233 struct dsrtc_softc *sc = arg; 234 u_char key; 235 236 key = ds1743_lock(sc, DS_CTL_W); 237 238 ds1743_write(sc, DS_SECONDS, BCD(rtc->rtc_sec) & 0x7f); 239 ds1743_write(sc, DS_MINUTES, BCD(rtc->rtc_min) & 0x7f); 240 ds1743_write(sc, DS_HOURS, BCD(rtc->rtc_hour) & 0x3f); 241 ds1743_write(sc, DS_DATE, BCD(rtc->rtc_day) & 0x3f); 242 ds1743_write(sc, DS_MONTH, BCD(rtc->rtc_mon) & 0x1f); 243 ds1743_write(sc, DS_YEAR, BCD(rtc->rtc_year)); 244 ds1743_write(sc, DS_CENTURY, ((ds1743_read(sc, DS_CENTURY) & DS_CTL_RW) 245 | BCD(rtc->rtc_cen))); 246 247 ds1743_unlock(sc, key); 248 dsrtc_read(arg, rtc); 249 return(1); 250 } 251 252 static int 253 dsrtc_read(void *arg, rtc_t *rtc) 254 { 255 struct dsrtc_softc *sc = arg; 256 u_char key; 257 258 key = ds1743_lock(sc, DS_CTL_R); 259 rtc->rtc_micro = 0; 260 rtc->rtc_centi = 0; 261 unBCD(rtc->rtc_sec, ds1743_read(sc, DS_SECONDS) & 0x7f); 262 unBCD(rtc->rtc_min, ds1743_read(sc, DS_MINUTES) & 0x7f); 263 unBCD(rtc->rtc_hour, ds1743_read(sc, DS_HOURS) & 0x3f); 264 unBCD(rtc->rtc_day, ds1743_read(sc, DS_DATE) & 0x3f); 265 unBCD(rtc->rtc_mon, ds1743_read(sc, DS_MONTH) & 0x1f); 266 unBCD(rtc->rtc_year, ds1743_read(sc, DS_YEAR)); 267 unBCD(rtc->rtc_cen, ds1743_read(sc, DS_CENTURY) & ~DS_CTL_RW); 268 269 ds1743_unlock(sc, key); 270 return(1); 271 } 272