rtc.c revision 1.1.14.1 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.1.14.1 2007/04/10 13:23:14 ad 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 struct device sc_dev;
60
61 int sc_valid;
62 struct todr_chip_handle sc_todr;
63 };
64
65 static int rtc_match(struct device *, struct cfdata *, void *);
66 static void rtc_attach(struct device *, struct device *, void *);
67
68 CFATTACH_DECL(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(struct device *parent, struct cfdata *cfp, void *aux)
80 {
81
82 return 1;
83 }
84
85
86 static void
87 rtc_attach(struct device *parent, struct device *self, void *aux)
88 {
89 struct rtc_softc *sc = (void *)self;
90 uint8_t r;
91 #ifdef RTC_DEBUG
92 char bits[128];
93 #endif
94
95 printf("\n");
96
97 r = _reg_read_1(SH_(RCR2));
98
99 #ifdef RTC_DEBUG
100 printf("%s: RCR2=%s\n", sc->sc_dev.dv_xname,
101 bitmask_snprintf(r, SH_RCR2_BITS, bits, sizeof(bits)));
102 #endif
103
104 /* Was the clock running? */
105 if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE
106 | SH_RCR2_START))
107 sc->sc_valid = 1;
108 else {
109 sc->sc_valid = 0;
110 printf("%s: WARNING: clock was stopped\n",
111 sc->sc_dev.dv_xname);
112 }
113
114 /* Disable carry and alarm interrupts */
115 _reg_write_1(SH_(RCR1), 0);
116
117 /* Clock runs, no periodic interrupts, no 30-sec adjustment */
118 _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
119
120 sc->sc_todr.cookie = sc;
121 sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms;
122 sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms;
123
124 todr_attach(&sc->sc_todr);
125
126 #ifdef RTC_DEBUG
127 {
128 struct clock_ymdhms dt;
129 rtc_gettime_ymdhms(&sc->sc_todr, &dt);
130 }
131 #endif
132 }
133
134
135 static int
136 rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
137 {
138 struct rtc_softc *sc = h->cookie;
139 unsigned int year;
140 int retry = 8;
141
142 if (!sc->sc_valid) {
143 #ifdef RTC_DEBUG
144 printf("RTC: gettime: not valid\n");
145 /* but proceed and read/print it anyway */
146 #else
147 return EIO;
148 #endif
149 }
150
151 /* disable carry interrupt */
152 _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
153
154 do {
155 uint8_t r = _reg_read_1(SH_(RCR1));
156 r &= ~SH_RCR1_CF;
157 r |= SH_RCR1_AF; /* don't clear alarm flag */
158 _reg_write_1(SH_(RCR1), r);
159
160 if (CPU_IS_SH3)
161 year = _reg_read_1(SH3_RYRCNT);
162 else
163 year = _reg_read_2(SH4_RYRCNT) & 0x00ff;
164 dt->dt_year = FROMBCD(year);
165
166 /* read counter */
167 #define RTCGET(x, y) \
168 dt->dt_ ## x = FROMBCD(_reg_read_1(SH_(R ## y ## CNT)))
169
170 RTCGET(mon, MON);
171 RTCGET(wday, WK);
172 RTCGET(day, DAY);
173 RTCGET(hour, HR);
174 RTCGET(min, MIN);
175 RTCGET(sec, SEC);
176 #undef RTCGET
177 } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
178
179 if (retry == 0) {
180 #ifdef RTC_DEBUG
181 printf("RTC: gettime: retry failed\n");
182 #endif
183 return EIO;
184 }
185
186 dt->dt_year += 1900;
187 if (dt->dt_year < POSIX_BASE_YEAR)
188 dt->dt_year += 100;
189
190 #ifdef RTC_DEBUG
191 printf("RTC: gettime: %04d-%02d-%02d %02d:%02d:%02d\n",
192 dt->dt_year, dt->dt_mon, dt->dt_day,
193 dt->dt_hour, dt->dt_min, dt->dt_sec);
194
195 if (!sc->sc_valid)
196 return EIO;
197 #endif
198
199 return 0;
200 }
201
202
203 static int
204 rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
205 {
206 struct rtc_softc *sc = h->cookie;
207 unsigned int year;
208 uint8_t r;
209
210 year = TOBCD(dt->dt_year % 100);
211
212 r = _reg_read_1(SH_(RCR2));
213
214 /* stop clock */
215 _reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET);
216
217 /* set time */
218 if (CPU_IS_SH3)
219 _reg_write_1(SH3_RYRCNT, year);
220 else
221 _reg_write_2(SH4_RYRCNT, year);
222
223 #define RTCSET(x, y) \
224 _reg_write_1(SH_(R ## x ## CNT), TOBCD(dt->dt_ ## y))
225
226 RTCSET(MON, mon);
227 RTCSET(WK, wday);
228 RTCSET(DAY, day);
229 RTCSET(HR, hour);
230 RTCSET(MIN, min);
231 RTCSET(SEC, sec);
232
233 #undef RTCSET
234
235 /* start clock */
236 _reg_write_1(SH_(RCR2), r);
237 sc->sc_valid = 1;
238
239 #ifdef RTC_DEBUG
240 printf("RTC: settime: %04d-%02d-%02d %02d:%02d:%02d\n",
241 dt->dt_year, dt->dt_mon, dt->dt_day,
242 dt->dt_hour, dt->dt_min, dt->dt_sec);
243 #endif
244
245 return 0;
246 }
247