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
dsrtcmatch(device_t parent,cfdata_t cf,void * aux)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
dsrtcattach(device_t parent,device_t self,void * aux)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
ds1743_read(struct dsrtc_softc * sc,int addr)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
ds1743_write(struct dsrtc_softc * sc,int addr,u_char data)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
ds1743_lock(struct dsrtc_softc * sc,u_char mode)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
ds1743_unlock(struct dsrtc_softc * sc,u_char key)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
dsrtc_write(todr_chip_handle_t tch,struct clock_ymdhms * dt)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
dsrtc_read(todr_chip_handle_t tch,struct clock_ymdhms * dt)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