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
123struct 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 */
132static 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
150static uint8_t
151bitreverse(uint8_t x)
152{
153
154	return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
155}
156
157static int
158s390rtc_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
183static int
184s390rtc_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
204static int
205s390rtc_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
228static void
229s390rtc_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
274static int
275s390rtc_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
288static int
289s390rtc_detach(device_t dev)
290{
291
292	clock_unregister(dev);
293	return (0);
294}
295
296static int
297s390rtc_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
326static int
327s390rtc_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
350static 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
361static driver_t s390rtc_driver = {
362	S390_DEVNAME,
363	s390rtc_methods,
364	sizeof(struct s390rtc_softc),
365};
366static devclass_t s390rtc_devclass;
367
368DRIVER_MODULE(s35390a, iicbus, s390rtc_driver, s390rtc_devclass, NULL, NULL);
369MODULE_VERSION(s35390a, 1);
370MODULE_DEPEND(s35390a, iicbus, 1, 1, 1);
371