msm6242b.c revision 1.1 1 /* $NetBSD: msm6242b.c,v 1.1 2012/11/14 01:52:48 rkujawa Exp $ */
2
3 /*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Radoslaw Kujawa.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33
34 #include <sys/param.h>
35 #include <sys/device.h>
36 #include <sys/bus.h>
37
38 #include <dev/clock_subr.h>
39
40 #include <dev/ic/msm6242bvar.h>
41 #include <dev/ic/msm6242breg.h>
42
43 /* #define MSM6242B_DEBUG 1 */
44
45 static int msm6242b_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
46 int msm6242b_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
47
48 bool msm6242b_hold(struct msm6242b_softc *sc);
49 void msm6242b_free(struct msm6242b_softc *sc);
50 static uint8_t msm6242b_read(struct msm6242b_softc *, uint8_t);
51 static void msm6242b_write(struct msm6242b_softc *, uint8_t, uint8_t);
52 static void msm6242b_set(struct msm6242b_softc *, uint8_t, uint8_t);
53 static void msm6242b_unset(struct msm6242b_softc *, uint8_t, uint8_t);
54
55 void
56 msm6242b_attach(struct msm6242b_softc *sc)
57 {
58 struct clock_ymdhms dt;
59
60 todr_chip_handle_t handle;
61 aprint_normal(": OKI MSM6242B\n");
62
63 handle = &sc->sc_handle;
64 handle->cookie = sc;
65 handle->todr_gettime = NULL;
66 handle->todr_settime = NULL;
67 handle->todr_gettime_ymdhms = msm6242b_gettime_ymdhms;
68 handle->todr_settime_ymdhms = msm6242b_settime_ymdhms;
69 handle->todr_setwen = NULL;
70
71 if (msm6242b_gettime_ymdhms(handle, &dt) != 0) {
72 aprint_error_dev(sc->sc_dev, "RTC does not work correctly\n");
73 return;
74 }
75
76 #ifdef MSM6242B_DEBUG
77 aprint_normal_dev(sc->sc_dev, "the time is %d %d %d %d %d %d\n",
78 dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec);
79 #endif
80 /* MSM6242B_DEBUG */
81 todr_attach(handle);
82 }
83
84 static int
85 msm6242b_gettime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
86 {
87 struct msm6242b_softc *sc;
88
89 sc = handle->cookie;
90 /* XXX: splsched(); */
91
92 if(!msm6242b_hold(sc))
93 return (ENXIO);
94
95 dt->dt_sec = msm6242b_read(sc, MSM6242B_10SECOND) * 10 +
96 msm6242b_read(sc, MSM6242B_1SECOND);
97 dt->dt_min = msm6242b_read(sc, MSM6242B_10MINUTE) * 10 +
98 msm6242b_read(sc, MSM6242B_1MINUTE);
99 dt->dt_hour = (msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
100 MSM6242B_10HOUR_MASK) * 10 + msm6242b_read(sc, MSM6242B_1HOUR);
101 dt->dt_day = msm6242b_read(sc, MSM6242B_10DAY) * 10 +
102 msm6242b_read(sc, MSM6242B_1DAY);
103 dt->dt_mon = msm6242b_read(sc, MSM6242B_10MONTH) * 10 +
104 msm6242b_read(sc, MSM6242B_1MONTH);
105 dt->dt_year = msm6242b_read(sc, MSM6242B_10YEAR) * 10 +
106 msm6242b_read(sc, MSM6242B_1YEAR);
107 dt->dt_wday = msm6242b_read(sc, MSM6242B_WEEK);
108
109 #ifdef MSM6242B_DEBUG
110 aprint_normal_dev(sc->sc_dev, "the time is %d %d %d %d %d %d\n",
111 dt->dt_year, dt->dt_mon, dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec);
112 #endif
113
114 /* handle 12h mode */
115 if ((msm6242b_read(sc, MSM6242B_CONTROL_F) &
116 MSM6242B_CONTROL_F_24H) == 0) {
117 if ((msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
118 MSM6242B_PMAM_BIT) == 0 && dt->dt_hour == 12)
119 dt->dt_hour = 0;
120 else if ((msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
121 MSM6242B_PMAM_BIT) && dt->dt_hour != 12);
122 dt->dt_hour += 12;
123 }
124
125 msm6242b_free(sc);
126
127 dt->dt_year += MSM6242B_BASE_YEAR;
128 if (dt->dt_year < POSIX_BASE_YEAR)
129 dt->dt_year += 100;
130
131 if ((dt->dt_hour > 23) ||
132 (dt->dt_day > 31) ||
133 (dt->dt_mon > 12) ||
134 (dt->dt_year > 2036))
135 return (EINVAL);
136
137 return 0;
138 }
139
140 bool
141 msm6242b_hold(struct msm6242b_softc *sc)
142 {
143 int try;
144
145 #define TRY_MAX 10
146 for (try = 0; try < TRY_MAX; try++) {
147 msm6242b_set(sc, MSM6242B_CONTROL_D, MSM6242B_CONTROL_D_HOLD);
148 if (msm6242b_read(sc, MSM6242B_CONTROL_D)
149 & MSM6242B_CONTROL_D_BUSY) {
150 aprint_normal_dev(sc->sc_dev, "gotta idle\n");
151 msm6242b_unset(sc, MSM6242B_CONTROL_D,
152 MSM6242B_CONTROL_D_HOLD);
153 delay(70);
154 } else {
155 aprint_normal_dev(sc->sc_dev, "not busy\n");
156 break;
157 }
158 }
159
160 if (try == TRY_MAX) {
161 aprint_error_dev(sc->sc_dev, "can't hold the chip\n");
162 return false;
163 }
164 return true;
165 }
166
167 void
168 msm6242b_free(struct msm6242b_softc *sc)
169 {
170 msm6242b_unset(sc, MSM6242B_CONTROL_D, MSM6242B_CONTROL_D_HOLD);
171 }
172
173 static uint8_t
174 msm6242b_read(struct msm6242b_softc *sc, uint8_t reg)
175 {
176 uint8_t r;
177 r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg) & MSM6242B_MASK;
178 return r;
179 }
180
181 static void
182 msm6242b_write(struct msm6242b_softc *sc, uint8_t reg, uint8_t val)
183 {
184 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
185 }
186
187 static void
188 msm6242b_set(struct msm6242b_softc *sc, uint8_t reg, uint8_t bits)
189 {
190 uint8_t v;
191 v = msm6242b_read(sc, reg) | bits;
192 msm6242b_write(sc, reg, v);
193 }
194
195 static void
196 msm6242b_unset(struct msm6242b_softc *sc, uint8_t reg, uint8_t bits)
197 {
198 uint8_t v;
199 v = msm6242b_read(sc, reg) & ~bits;
200 msm6242b_write(sc, reg, v);
201 }
202
203 int
204 msm6242b_settime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
205 {
206 struct msm6242b_softc *sc;
207 int ampm;
208 /* XXX: splsched(); */
209
210 sc = handle->cookie;
211
212 if(!msm6242b_hold(sc))
213 return (ENXIO);
214
215 ampm = 0;
216 if ((msm6242b_read(sc, MSM6242B_CONTROL_F) &
217 MSM6242B_CONTROL_F_24H) == 0) {
218 if (dt->dt_hour >= 12) {
219 ampm = MSM6242B_CONTROL_F_24H;
220 if (dt->dt_hour != 12)
221 dt->dt_hour -= 12;
222 } else if (dt->dt_hour == 0) {
223 dt->dt_hour = 12;
224 }
225 }
226
227 msm6242b_write(sc, MSM6242B_10HOUR_PMAM, (dt->dt_hour / 10) | ampm);
228 msm6242b_write(sc, MSM6242B_1HOUR, dt->dt_hour % 10);
229 msm6242b_write(sc, MSM6242B_10SECOND, dt->dt_sec / 10);
230 msm6242b_write(sc, MSM6242B_1SECOND, dt->dt_sec % 10);
231 msm6242b_write(sc, MSM6242B_10MINUTE, dt->dt_min / 10);
232 msm6242b_write(sc, MSM6242B_1MINUTE, dt->dt_min % 10);
233 msm6242b_write(sc, MSM6242B_10DAY, dt->dt_day / 10);
234 msm6242b_write(sc, MSM6242B_1DAY, dt->dt_day % 10);
235 msm6242b_write(sc, MSM6242B_10MONTH, dt->dt_mon / 10);
236 msm6242b_write(sc, MSM6242B_1MONTH, dt->dt_mon % 10);
237 msm6242b_write(sc, MSM6242B_10YEAR, (dt->dt_mon / 10) % 10);
238 msm6242b_write(sc, MSM6242B_1YEAR, dt->dt_mon % 10);
239 msm6242b_write(sc, MSM6242B_WEEK, dt->dt_wday);
240
241 msm6242b_free(sc);
242
243 return 0;
244 }
245
246