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