Annotation of sys/arch/landisk/dev/rs5c313.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: rs5c313.c,v 1.2 2006/10/23 20:26:25 miod Exp $ */
2: /* $NetBSD: rs5c313.c,v 1.1 2006/09/07 01:12:00 uwe Exp $ */
3: /* $NetBSD: rs5c313_landisk.c,v 1.1 2006/09/07 01:55:03 uwe Exp $ */
4:
5: /*-
6: * Copyright (c) 2002 The NetBSD Foundation, Inc.
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by the NetBSD
20: * Foundation, Inc. and its contributors.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32: * POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: /*
36: * RICOH RS5C313 Real Time Clock
37: */
38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/device.h>
42: #include <sys/kernel.h>
43:
44: #include <dev/clock_subr.h>
45: #include <sh/clock.h>
46:
47: #include <sh/devreg.h>
48: #include <sh/dev/scireg.h>
49:
50: #include <landisk/dev/rs5c313reg.h>
51: #include <landisk/landisk/landiskreg.h>
52:
53: struct rs5c313_softc {
54: struct device sc_dev;
55:
56: int sc_valid; /* oscillation halt sensing on init */
57: };
58:
59: /* chip access methods */
60: void rtc_begin(struct rs5c313_softc *);
61: void rtc_ce(struct rs5c313_softc *, int);
62: void rtc_dir(struct rs5c313_softc *, int);
63: void rtc_clk(struct rs5c313_softc *, int);
64: int rtc_read(struct rs5c313_softc *);
65: void rtc_write(struct rs5c313_softc *, int);
66:
67: int rs5c313_init(struct rs5c313_softc *);
68: int rs5c313_read_reg(struct rs5c313_softc *, int);
69: void rs5c313_write_reg(struct rs5c313_softc *, int, int);
70: void rs5c313_gettime(void *, time_t, struct clock_ymdhms *);
71: void rs5c313_settime(void *, struct clock_ymdhms *);
72:
73: int
74: rs5c313_init(struct rs5c313_softc *sc)
75: {
76: int status = 0;
77: int retry;
78:
79: rtc_ce(sc, 0);
80:
81: rtc_begin(sc);
82: rtc_ce(sc, 1);
83:
84: if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_XSTP) == 0) {
85: sc->sc_valid = 1;
86: goto done;
87: }
88:
89: sc->sc_valid = 0;
90: printf("%s: time not valid\n", sc->sc_dev.dv_xname);
91:
92: rs5c313_write_reg(sc, RS5C313_TINT, 0);
93: rs5c313_write_reg(sc, RS5C313_CTRL, (CTRL_BASE | CTRL_ADJ));
94:
95: for (retry = 1000; retry > 0; --retry) {
96: if (rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY)
97: delay(1);
98: else
99: break;
100: }
101:
102: if (retry == 0) {
103: status = EIO;
104: goto done;
105: }
106:
107: rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
108:
109: done:
110: rtc_ce(sc, 0);
111: return status;
112: }
113:
114: int
115: rs5c313_read_reg(struct rs5c313_softc *sc, int addr)
116: {
117: int data;
118:
119: /* output */
120: rtc_dir(sc, 1);
121:
122: /* control */
123: rtc_write(sc, 1); /* ignored */
124: rtc_write(sc, 1); /* R/#W = 1(READ) */
125: rtc_write(sc, 1); /* AD = 1 */
126: rtc_write(sc, 0); /* DT = 0 */
127:
128: /* address */
129: rtc_write(sc, addr & 0x8); /* A3 */
130: rtc_write(sc, addr & 0x4); /* A2 */
131: rtc_write(sc, addr & 0x2); /* A1 */
132: rtc_write(sc, addr & 0x1); /* A0 */
133:
134: /* input */
135: rtc_dir(sc, 0);
136:
137: /* ignore */
138: (void)rtc_read(sc);
139: (void)rtc_read(sc);
140: (void)rtc_read(sc);
141: (void)rtc_read(sc);
142:
143: /* data */
144: data = rtc_read(sc); /* D3 */
145: data <<= 1;
146: data |= rtc_read(sc); /* D2 */
147: data <<= 1;
148: data |= rtc_read(sc); /* D1 */
149: data <<= 1;
150: data |= rtc_read(sc); /* D0 */
151:
152: return data;
153: }
154:
155: void
156: rs5c313_write_reg(struct rs5c313_softc *sc, int addr, int data)
157: {
158: /* output */
159: rtc_dir(sc, 1);
160:
161: /* control */
162: rtc_write(sc, 1); /* ignored */
163: rtc_write(sc, 0); /* R/#W = 0 (WRITE) */
164: rtc_write(sc, 1); /* AD = 1 */
165: rtc_write(sc, 0); /* DT = 0 */
166:
167: /* address */
168: rtc_write(sc, addr & 0x8); /* A3 */
169: rtc_write(sc, addr & 0x4); /* A2 */
170: rtc_write(sc, addr & 0x2); /* A1 */
171: rtc_write(sc, addr & 0x1); /* A0 */
172:
173: /* control */
174: rtc_write(sc, 1); /* ignored */
175: rtc_write(sc, 0); /* R/#W = 0(WRITE) */
176: rtc_write(sc, 0); /* AD = 0 */
177: rtc_write(sc, 1); /* DT = 1 */
178:
179: /* data */
180: rtc_write(sc, data & 0x8); /* D3 */
181: rtc_write(sc, data & 0x4); /* D2 */
182: rtc_write(sc, data & 0x2); /* D1 */
183: rtc_write(sc, data & 0x1); /* D0 */
184: }
185:
186: void
187: rs5c313_gettime(void *cookie, time_t base, struct clock_ymdhms *dt)
188: {
189: struct rs5c313_softc *sc = cookie;
190: int retry;
191: int s;
192:
193: /*
194: * If chip had invalid data on init, don't bother reading
195: * bogus values.
196: */
197: if (sc->sc_valid == 0)
198: return;
199:
200: s = splhigh();
201:
202: rtc_begin(sc);
203: for (retry = 10; retry > 0; --retry) {
204: rtc_ce(sc, 1);
205:
206: rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
207: if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
208: break;
209:
210: rtc_ce(sc, 0);
211: delay(1);
212: }
213:
214: if (retry == 0) {
215: splx(s);
216: return;
217: }
218:
219: #define RTCGET(x, y) \
220: do { \
221: int ones = rs5c313_read_reg(sc, RS5C313_ ## y ## 1); \
222: int tens = rs5c313_read_reg(sc, RS5C313_ ## y ## 10); \
223: dt->dt_ ## x = tens * 10 + ones; \
224: } while (/* CONSTCOND */0)
225:
226: RTCGET(sec, SEC);
227: RTCGET(min, MIN);
228: RTCGET(hour, HOUR);
229: RTCGET(day, DAY);
230: RTCGET(mon, MON);
231: RTCGET(year, YEAR);
232: #undef RTCGET
233: dt->dt_wday = rs5c313_read_reg(sc, RS5C313_WDAY);
234:
235: rtc_ce(sc, 0);
236: splx(s);
237:
238: dt->dt_year = (dt->dt_year % 100) + 1900;
239: if (dt->dt_year < 1970) {
240: dt->dt_year += 100;
241: }
242: }
243:
244: void
245: rs5c313_settime(void *cookie, struct clock_ymdhms *dt)
246: {
247: struct rs5c313_softc *sc = cookie;
248: int retry;
249: int t;
250: int s;
251:
252: s = splhigh();
253:
254: rtc_begin(sc);
255: for (retry = 10; retry > 0; --retry) {
256: rtc_ce(sc, 1);
257:
258: rs5c313_write_reg(sc, RS5C313_CTRL, CTRL_BASE);
259: if ((rs5c313_read_reg(sc, RS5C313_CTRL) & CTRL_BSY) == 0)
260: break;
261:
262: rtc_ce(sc, 0);
263: delay(1);
264: }
265:
266: if (retry == 0) {
267: splx(s);
268: return;
269: }
270:
271: #define RTCSET(x, y) \
272: do { \
273: t = TOBCD(dt->dt_ ## y) & 0xff; \
274: rs5c313_write_reg(sc, RS5C313_ ## x ## 1, t & 0x0f); \
275: rs5c313_write_reg(sc, RS5C313_ ## x ## 10, (t >> 4) & 0x0f); \
276: } while (/* CONSTCOND */0)
277:
278: RTCSET(SEC, sec);
279: RTCSET(MIN, min);
280: RTCSET(HOUR, hour);
281: RTCSET(DAY, day);
282: RTCSET(MON, mon);
283:
284: #undef RTCSET
285:
286: t = dt->dt_year % 100;
287: t = TOBCD(t);
288: rs5c313_write_reg(sc, RS5C313_YEAR1, t & 0x0f);
289: rs5c313_write_reg(sc, RS5C313_YEAR10, (t >> 4) & 0x0f);
290:
291: rs5c313_write_reg(sc, RS5C313_WDAY, dt->dt_wday);
292:
293: rtc_ce(sc, 0);
294: splx(s);
295:
296: sc->sc_valid = 1;
297: }
298:
299: struct rtc_ops rs5c313_ops = {
300: NULL,
301: NULL, /* not used */
302: rs5c313_gettime,
303: rs5c313_settime
304: };
305:
306: void
307: rtc_begin(struct rs5c313_softc *sc)
308: {
309: SHREG_SCSPTR = SCSPTR_SPB1IO | SCSPTR_SPB1DT
310: | SCSPTR_SPB0IO | SCSPTR_SPB0DT;
311: delay(100);
312: }
313:
314: /*
315: * CE pin
316: */
317: void
318: rtc_ce(struct rs5c313_softc *sc, int onoff)
319: {
320: if (onoff)
321: _reg_write_1(LANDISK_PWRMNG, PWRMNG_RTC_CE);
322: else
323: _reg_write_1(LANDISK_PWRMNG, 0);
324: delay(600);
325: }
326:
327: /*
328: * SCLK pin is connnected to SPB0DT.
329: * SPB0DT is always in output mode, we set SPB0IO in rtc_begin.
330: */
331: void
332: rtc_clk(struct rs5c313_softc *sc, int onoff)
333: {
334: uint8_t r = SHREG_SCSPTR;
335:
336: if (onoff)
337: r |= SCSPTR_SPB0DT;
338: else
339: r &= ~SCSPTR_SPB0DT;
340: SHREG_SCSPTR = r;
341: }
342:
343: /*
344: * SIO pin is connected to SPB1DT.
345: * SPB1DT is output when SPB1IO is set.
346: */
347: void
348: rtc_dir(struct rs5c313_softc *sc, int output)
349: {
350: uint8_t r = SHREG_SCSPTR;
351:
352: if (output)
353: r |= SCSPTR_SPB1IO;
354: else
355: r &= ~SCSPTR_SPB1IO;
356: SHREG_SCSPTR = r;
357: }
358:
359: /*
360: * Read bit from SPB1DT pin.
361: */
362: int
363: rtc_read(struct rs5c313_softc *sc)
364: {
365: int bit;
366:
367: delay(300);
368:
369: bit = (SHREG_SCSPTR & SCSPTR_SPB1DT) ? 1 : 0;
370:
371: rtc_clk(sc, 0);
372: delay(300);
373: rtc_clk(sc, 1);
374:
375: return bit;
376: }
377:
378: /*
379: * Write bit via SPB1DT pin.
380: */
381: void
382: rtc_write(struct rs5c313_softc *sc, int bit)
383: {
384: uint8_t r = SHREG_SCSPTR;
385:
386: if (bit)
387: r |= SCSPTR_SPB1DT;
388: else
389: r &= ~SCSPTR_SPB1DT;
390: SHREG_SCSPTR = r;
391:
392: delay(300);
393:
394: rtc_clk(sc, 0);
395: delay(300);
396: rtc_clk(sc, 1);
397: }
398:
399: /* autoconf glue */
400: int rs5c313_landisk_match(struct device *, void *, void *);
401: void rs5c313_landisk_attach(struct device *, struct device *, void *);
402:
403: const struct cfattach rsclock_ca = {
404: sizeof (struct rs5c313_softc),
405: rs5c313_landisk_match, rs5c313_landisk_attach
406: };
407:
408: struct cfdriver rsclock_cd = {
409: 0, "rsclock", DV_DULL
410: };
411:
412: int
413: rs5c313_landisk_match(struct device *parent, void *vcf, void *aux)
414: {
415: static int matched = 0;
416:
417: if (matched)
418: return (0);
419:
420: return (matched = 1);
421: }
422:
423: void
424: rs5c313_landisk_attach(struct device *parent, struct device *self, void *aux)
425: {
426: struct rs5c313_softc *sc = (void *)self;
427:
428: printf(": RS5C313 real time clock\n");
429:
430: if (rs5c313_init(sc) != 0) {
431: printf("%s: init failed\n", self->dv_xname);
432: return;
433: }
434:
435: rs5c313_ops._cookie = sc;
436: sh_clock_init(SH_CLOCK_NORTC, &rs5c313_ops);
437: }
CVSweb