]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/s35390a.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / s35390a.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
3  *
4  * Copyright (c) 2012 Yusuke Tanaka
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*-
30  * Copyright (c) 2011 Frank Wille.
31  * All rights reserved.
32  *
33  * Written by Frank Wille for The NetBSD Project.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
45  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
48  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54  * POSSIBILITY OF SUCH DAMAGE.
55  */
56
57 #include <sys/cdefs.h>
58 __FBSDID("$FreeBSD$");
59
60 /*
61  * Driver for Seiko Instruments S-35390A Real-time Clock
62  */
63
64 #include "opt_platform.h"
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/bus.h>
69 #include <sys/clock.h>
70 #include <sys/kernel.h>
71 #include <sys/module.h>
72
73 #include <dev/iicbus/iicbus.h>
74 #include <dev/iicbus/iiconf.h>
75
76 #ifdef FDT
77 #include <dev/ofw/openfirm.h>
78 #include <dev/ofw/ofw_bus.h>
79 #include <dev/ofw/ofw_bus_subr.h>
80 #endif
81
82 #include "clock_if.h"
83 #include "iicbus_if.h"
84
85 #define S390_DEVNAME            "s35390a_rtc"
86 #define S390_DEVCODE            0x6     /* 0110 */
87 /*
88  * S-35390A uses 4-bit device code + 3-bit command in the slave address
89  * field.  The possible combination is 0x60-0x6f including the R/W bit.
90  * 0x60 means an write access to status register 1.
91  */
92 #define S390_ADDR               (S390_DEVCODE << 4)
93
94 /* Registers are encoded into the slave address */
95 #define S390_STATUS1            (0 << 1)
96 #define S390_STATUS2            (1 << 1)
97 #define S390_REALTIME1          (2 << 1)
98 #define S390_REALTIME2          (3 << 1)
99 #define S390_INT1_1             (4 << 1)
100 #define S390_INT1_2             (5 << 1)
101 #define S390_CLOCKADJ           (6 << 1)
102 #define S390_FREE               (7 << 1)
103
104 /* Status1 bits */
105 #define S390_ST1_POC            (1 << 7)
106 #define S390_ST1_BLD            (1 << 6)
107 #define S390_ST1_24H            (1 << 1)
108 #define S390_ST1_RESET          (1 << 0)
109
110 /* Status2 bits */
111 #define S390_ST2_TEST           (1 << 7)
112
113 /* Realtime1 data bytes */
114 #define S390_RT1_NBYTES         7
115 #define S390_RT1_YEAR           0
116 #define S390_RT1_MONTH          1
117 #define S390_RT1_DAY            2
118 #define S390_RT1_WDAY           3
119 #define S390_RT1_HOUR           4
120 #define S390_RT1_MINUTE         5
121 #define S390_RT1_SECOND         6
122
123 struct s390rtc_softc {
124         device_t        sc_dev;
125         uint16_t        sc_addr;
126 };
127
128 /*
129  * S-35390A interprets bits in each byte on SDA in reverse order.
130  * bitreverse() reverses the bits in uint8_t.
131  */
132 static const uint8_t nibbletab[] = {
133         /* 0x0 0000 -> 0000 */  0x0,
134         /* 0x1 0001 -> 1000 */  0x8,
135         /* 0x2 0010 -> 0100 */  0x4,
136         /* 0x3 0011 -> 1100 */  0xc,
137         /* 0x4 0100 -> 0010 */  0x2,
138         /* 0x5 0101 -> 1010 */  0xa,
139         /* 0x6 0110 -> 0110 */  0x6,
140         /* 0x7 0111 -> 1110 */  0xe,
141         /* 0x8 1000 -> 0001 */  0x1,
142         /* 0x9 1001 -> 1001 */  0x9,
143         /* 0xa 1010 -> 0101 */  0x5,
144         /* 0xb 1011 -> 1101 */  0xd,
145         /* 0xc 1100 -> 0011 */  0x3,
146         /* 0xd 1101 -> 1011 */  0xb,
147         /* 0xe 1110 -> 0111 */  0x7,
148         /* 0xf 1111 -> 1111 */  0xf, };
149
150 static uint8_t
151 bitreverse(uint8_t x)
152 {
153
154         return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
155 }
156
157 static int
158 s390rtc_read(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
159 {
160         struct s390rtc_softc *sc = device_get_softc(dev);
161         struct iic_msg msg[] = {
162                 {
163                         .slave = sc->sc_addr | reg,
164                         .flags = IIC_M_RD,
165                         .len = len,
166                         .buf = buf,
167                 },
168         };
169         int i;
170         int error;
171
172         error = iicbus_transfer_excl(dev, msg, 1, IIC_WAIT);
173         if (error)
174                 return (error);
175
176         /* this chip returns each byte in reverse order */
177         for (i = 0; i < len; ++i)
178                 buf[i] = bitreverse(buf[i]);
179
180         return (0);
181 }
182
183 static int
184 s390rtc_write(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
185 {
186         struct s390rtc_softc *sc = device_get_softc(dev);
187         struct iic_msg msg[] = {
188                 {
189                         .slave = sc->sc_addr | reg,
190                         .flags = IIC_M_WR,
191                         .len = len,
192                         .buf = buf,
193                 },
194         };
195         int i;
196
197         /* this chip expects each byte in reverse order */
198         for (i = 0; i < len; ++i)
199                 buf[i] = bitreverse(buf[i]);
200
201         return (iicbus_transfer_excl(dev, msg, 1, IIC_WAIT));
202 }
203
204 static int
205 s390rtc_probe(device_t dev)
206 {
207
208 #ifdef FDT
209         if (!ofw_bus_status_okay(dev))
210                 return (ENXIO);
211
212         if (!ofw_bus_is_compatible(dev, "sii,s35390a"))
213                 return (ENXIO);
214 #else
215         if (iicbus_get_addr(dev) != S390_ADDR) {
216                 if (bootverbose)
217                         device_printf(dev, "slave address mismatch. "
218                             "(%02x != %02x)\n", iicbus_get_addr(dev),
219                             S390_ADDR);
220                 return (ENXIO);
221         }
222 #endif
223         device_set_desc(dev, "Seiko Instruments S-35390A RTC");
224
225         return (BUS_PROBE_DEFAULT);
226 }
227
228 static void
229 s390rtc_start(void *arg)
230 {
231         device_t dev;
232         uint8_t reg;
233         int error;
234
235         dev = arg;
236
237         /* Reset the chip and turn on 24h mode, after power-off or battery. */
238         error = s390rtc_read(dev, S390_STATUS1, &reg, 1);
239         if (error) {
240                 device_printf(dev, "%s: cannot read status1 register\n",
241                      __func__);
242                 return;
243         }
244         if (reg & (S390_ST1_POC | S390_ST1_BLD)) {
245                 reg |= S390_ST1_24H | S390_ST1_RESET;
246                 error = s390rtc_write(dev, S390_STATUS1, &reg, 1);
247                 if (error) {
248                         device_printf(dev,
249                             "%s: cannot initialize\n", __func__);
250                         return;
251                 }
252         }
253
254         /* Disable the test mode, when enabled. */
255         error = s390rtc_read(dev, S390_STATUS2, &reg, 1);
256         if (error) {
257                 device_printf(dev, "%s: cannot read status2 register\n",
258                     __func__);
259                 return;
260         }
261         if (reg & S390_ST2_TEST) {
262                 reg &= ~S390_ST2_TEST;
263                 error = s390rtc_write(dev, S390_STATUS2, &reg, 1);
264                 if (error) {
265                         device_printf(dev,
266                             "%s: cannot disable the test mode\n", __func__);
267                         return;
268                 }
269         }
270
271         clock_register(dev, 1000000);   /* 1 second resolution */
272 }
273
274 static int
275 s390rtc_attach(device_t dev)
276 {
277         struct s390rtc_softc *sc;
278
279         sc = device_get_softc(dev);
280         sc->sc_dev = dev;
281         sc->sc_addr = iicbus_get_addr(dev);
282
283         config_intrhook_oneshot(s390rtc_start, dev);
284
285         return (0);
286 }
287
288 static int
289 s390rtc_detach(device_t dev)
290 {
291
292         clock_unregister(dev);
293         return (0);
294 }
295
296 static int
297 s390rtc_gettime(device_t dev, struct timespec *ts)
298 {
299         uint8_t bcd[S390_RT1_NBYTES];
300         struct bcd_clocktime bct;
301         int error;
302
303         error = s390rtc_read(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES);
304         if (error) {
305                 device_printf(dev, "%s: cannot read realtime1 register\n",
306                     __func__);
307                 return (error);
308         }
309
310         /*
311          * Convert the register values into something useable.
312          */
313         bct.nsec = 0;
314         bct.sec  = bcd[S390_RT1_SECOND];
315         bct.min  = bcd[S390_RT1_MINUTE];
316         bct.hour = bcd[S390_RT1_HOUR] & 0x3f;
317         bct.day  = bcd[S390_RT1_DAY];
318         bct.dow  = bcd[S390_RT1_WDAY] & 0x07;
319         bct.mon  = bcd[S390_RT1_MONTH];
320         bct.year = bcd[S390_RT1_YEAR];
321
322         clock_dbgprint_bcd(dev, CLOCK_DBG_READ, &bct); 
323         return (clock_bcd_to_ts(&bct, ts, false));
324 }
325
326 static int
327 s390rtc_settime(device_t dev, struct timespec *ts)
328 {
329         uint8_t bcd[S390_RT1_NBYTES];
330         struct bcd_clocktime bct;
331
332         clock_ts_to_bcd(ts, &bct, false);
333         clock_dbgprint_bcd(dev, CLOCK_DBG_WRITE, &bct); 
334
335         /*
336          * Convert our time representation into something the S-xx390
337          * can understand.
338          */
339         bcd[S390_RT1_SECOND] = bct.sec;
340         bcd[S390_RT1_MINUTE] = bct.min;
341         bcd[S390_RT1_HOUR]   = bct.hour;
342         bcd[S390_RT1_DAY]    = bct.day;
343         bcd[S390_RT1_WDAY]   = bct.dow;
344         bcd[S390_RT1_MONTH]  = bct.mon;
345         bcd[S390_RT1_YEAR]   = bct.year & 0xff;
346
347         return (s390rtc_write(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES));
348 }
349
350 static device_method_t s390rtc_methods[] = {
351         DEVMETHOD(device_probe,         s390rtc_probe),
352         DEVMETHOD(device_attach,        s390rtc_attach),
353         DEVMETHOD(device_detach,        s390rtc_detach),
354
355         DEVMETHOD(clock_gettime,        s390rtc_gettime),
356         DEVMETHOD(clock_settime,        s390rtc_settime),
357
358         DEVMETHOD_END
359 };
360
361 static driver_t s390rtc_driver = {
362         S390_DEVNAME,
363         s390rtc_methods,
364         sizeof(struct s390rtc_softc),
365 };
366 static devclass_t s390rtc_devclass;
367
368 DRIVER_MODULE(s35390a, iicbus, s390rtc_driver, s390rtc_devclass, NULL, NULL);
369 MODULE_VERSION(s35390a, 1);
370 MODULE_DEPEND(s35390a, iicbus, 1, 1, 1);