rtc.c revision 1.3 1 /*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by UCHIYAMA Yasushi.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the NetBSD
19 * Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.3 2008/03/27 00:31:06 uwe Exp $");
39
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
44 #include <sys/systm.h>
45 #ifdef GPROF
46 #include <sys/gmon.h>
47 #endif
48
49 #include <dev/clock_subr.h>
50
51 #include <sh3/rtcreg.h>
52
53 #if defined(DEBUG) && !defined(RTC_DEBUG)
54 #define RTC_DEBUG
55 #endif
56
57
58 struct rtc_softc {
59 device_t sc_dev;
60
61 int sc_valid;
62 struct todr_chip_handle sc_todr;
63 };
64
65 static int rtc_match(device_t, cfdata_t, void *);
66 static void rtc_attach(device_t, device_t, void *);
67
68 CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc),
69 rtc_match, rtc_attach, NULL, NULL);
70
71
72 /* todr(9) methods */
73 static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
74 static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
75
76
77
78 static int
79 rtc_match(device_t parent, cfdata_t cfp, void *aux)
80 {
81
82 return 1;
83 }
84
85
86 static void
87 rtc_attach(device_t parent, device_t self, void *aux)
88 {
89 struct rtc_softc *sc;
90 uint8_t r;
91 #ifdef RTC_DEBUG
92 char bits[128];
93 #endif
94
95 aprint_naive("\n");
96 aprint_normal("\n");
97
98 sc = device_private(self);
99 sc->sc_dev = self;
100
101 r = _reg_read_1(SH_(RCR2));
102
103 #ifdef RTC_DEBUG
104 aprint_debug_dev(sc->sc_dev, "RCR2=%s\n",
105 bitmask_snprintf(r, SH_RCR2_BITS, bits, sizeof(bits)));
106 #endif
107
108 /* Was the clock running? */
109 if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE
110 | SH_RCR2_START))
111 sc->sc_valid = 1;
112 else {
113 sc->sc_valid = 0;
114 aprint_error_dev(sc->sc_dev, "WARNING: clock was stopped\n");
115 }
116
117 /* Disable carry and alarm interrupts */
118 _reg_write_1(SH_(RCR1), 0);
119
120 /* Clock runs, no periodic interrupts, no 30-sec adjustment */
121 _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
122
123 sc->sc_todr.cookie = sc;
124 sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms;
125 sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms;
126
127 todr_attach(&sc->sc_todr);
128
129 #ifdef RTC_DEBUG
130 {
131 struct clock_ymdhms dt;
132 rtc_gettime_ymdhms(&sc->sc_todr, &dt);
133 }
134 #endif
135 }
136
137
138 static int
139 rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
140 {
141 struct rtc_softc *sc = h->cookie;
142 unsigned int year;
143 int retry = 8;
144
145 if (!sc->sc_valid) {
146 #ifdef RTC_DEBUG
147 aprint_debug_dev(sc->sc_dev, "gettime: not valid\n");
148 /* but proceed and read/print it anyway */
149 #else
150 return EIO;
151 #endif
152 }
153
154 /* disable carry interrupt */
155 _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
156
157 do {
158 uint8_t r = _reg_read_1(SH_(RCR1));
159 r &= ~SH_RCR1_CF;
160 r |= SH_RCR1_AF; /* don't clear alarm flag */
161 _reg_write_1(SH_(RCR1), r);
162
163 if (CPU_IS_SH3)
164 year = _reg_read_1(SH3_RYRCNT);
165 else
166 year = _reg_read_2(SH4_RYRCNT) & 0x00ff;
167 dt->dt_year = FROMBCD(year);
168
169 /* read counter */
170 #define RTCGET(x, y) \
171 dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
172
173 RTCGET(mon, MON);
174 RTCGET(wday, WK);
175 RTCGET(day, DAY);
176 RTCGET(hour, HR);
177 RTCGET(min, MIN);
178 RTCGET(sec, SEC);
179 #undef RTCGET
180 } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
181
182 if (retry == 0) {
183 #ifdef RTC_DEBUG
184 aprint_debug_dev(sc->sc_dev, "gettime: retry failed\n");
185 #endif
186 return EIO;
187 }
188
189 dt->dt_year += 1900;
190 if (dt->dt_year < POSIX_BASE_YEAR)
191 dt->dt_year += 100;
192
193 #ifdef RTC_DEBUG
194 aprint_debug_dev(sc->sc_dev,
195 "gettime: %04d-%02d-%02d %02d:%02d:%02d\n",
196 dt->dt_year, dt->dt_mon, dt->dt_day,
197 dt->dt_hour, dt->dt_min, dt->dt_sec);
198
199 if (!sc->sc_valid)
200 return EIO;
201 #endif
202
203 return 0;
204 }
205
206
207 static int
208 rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
209 {
210 struct rtc_softc *sc = h->cookie;
211 unsigned int year;
212 uint8_t r;
213
214 year = TOBCD(dt->dt_year % 100);
215
216 r = _reg_read_1(SH_(RCR2));
217
218 /* stop clock */
219 _reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET);
220
221 /* set time */
222 if (CPU_IS_SH3)
223 _reg_write_1(SH3_RYRCNT, year);
224 else
225 _reg_write_2(SH4_RYRCNT, year);
226
227 #define RTCSET(x, y) \
228 _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
229
230 RTCSET(MON, mon);
231 RTCSET(WK, wday);
232 RTCSET(DAY, day);
233 RTCSET(HR, hour);
234 RTCSET(MIN, min);
235 RTCSET(SEC, sec);
236
237 #undef RTCSET
238
239 /* start clock */
240 _reg_write_1(SH_(RCR2), r);
241 sc->sc_valid = 1;
242
243 #ifdef RTC_DEBUG
244 aprint_debug_dev(sc->sc_dev,
245 "settime: %04d-%02d-%02d %02d:%02d:%02d\n",
246 dt->dt_year, dt->dt_mon, dt->dt_day,
247 dt->dt_hour, dt->dt_min, dt->dt_sec);
248 #endif
249
250 return 0;
251 }
252