xref: /netbsd-src/sys/arch/sh3/dev/rtc.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
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.2 2007/03/30 00:32:58 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 	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