1239507Shrs/*-
2239507Shrs * Copyright (c) 2012 Yusuke Tanaka
3239507Shrs * All rights reserved.
4239507Shrs *
5239507Shrs * Redistribution and use in source and binary forms, with or without
6239507Shrs * modification, are permitted provided that the following conditions
7239507Shrs * are met:
8239507Shrs * 1. Redistributions of source code must retain the above copyright
9239507Shrs *    notice, this list of conditions and the following disclaimer.
10239507Shrs * 2. Redistributions in binary form must reproduce the above copyright
11239507Shrs *    notice, this list of conditions and the following disclaimer in the
12239507Shrs *    documentation and/or other materials provided with the distribution.
13239507Shrs *
14239507Shrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15239507Shrs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16239507Shrs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17239507Shrs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18239507Shrs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19239507Shrs * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20239507Shrs * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21239507Shrs * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22239507Shrs * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239507Shrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239507Shrs * SUCH DAMAGE.
25239507Shrs */
26239507Shrs
27239507Shrs/*-
28239507Shrs * Copyright (c) 2011 Frank Wille.
29239507Shrs * All rights reserved.
30239507Shrs *
31239507Shrs * Written by Frank Wille for The NetBSD Project.
32239507Shrs *
33239507Shrs * Redistribution and use in source and binary forms, with or without
34239507Shrs * modification, are permitted provided that the following conditions
35239507Shrs * are met:
36239507Shrs * 1. Redistributions of source code must retain the above copyright
37239507Shrs *    notice, this list of conditions and the following disclaimer.
38239507Shrs * 2. Redistributions in binary form must reproduce the above copyright
39239507Shrs *    notice, this list of conditions and the following disclaimer in the
40239507Shrs *    documentation and/or other materials provided with the distribution.
41239507Shrs *
42239507Shrs * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
43239507Shrs * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
44239507Shrs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45239507Shrs * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
46239507Shrs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
47239507Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
48239507Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
49239507Shrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50239507Shrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51239507Shrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52239507Shrs * POSSIBILITY OF SUCH DAMAGE.
53239507Shrs */
54239507Shrs
55239507Shrs#include <sys/cdefs.h>
56239507Shrs__FBSDID("$FreeBSD$");
57239507Shrs
58239507Shrs/*
59239507Shrs * Driver for Seiko Instruments S-35390A Real-time Clock
60239507Shrs */
61239507Shrs
62239507Shrs#include <sys/param.h>
63239507Shrs#include <sys/systm.h>
64239507Shrs#include <sys/bus.h>
65239507Shrs#include <sys/clock.h>
66239507Shrs#include <sys/kernel.h>
67239507Shrs#include <sys/module.h>
68239507Shrs
69239507Shrs#include <dev/iicbus/iicbus.h>
70239507Shrs#include <dev/iicbus/iiconf.h>
71239507Shrs
72239507Shrs#include "clock_if.h"
73239507Shrs#include "iicbus_if.h"
74239507Shrs
75239507Shrs#define S390_DEVNAME		"s35390a_rtc"
76239507Shrs#define S390_DEVCODE		0x6	/* 0110 */
77239507Shrs/*
78239507Shrs * S-35390A uses 4-bit device code + 3-bit command in the slave address
79239507Shrs * field.  The possible combination is 0x60-0x6f including the R/W bit.
80239507Shrs * 0x60 means an write access to status register 1.
81239507Shrs */
82239507Shrs#define S390_ADDR		(S390_DEVCODE << 4)
83239507Shrs
84239507Shrs/* Registers are encoded into the slave address */
85239507Shrs#define S390_STATUS1		(0 << 1)
86239507Shrs#define S390_STATUS2		(1 << 1)
87239507Shrs#define S390_REALTIME1		(2 << 1)
88239507Shrs#define S390_REALTIME2		(3 << 1)
89239507Shrs#define S390_INT1_1		(4 << 1)
90239507Shrs#define S390_INT1_2		(5 << 1)
91239507Shrs#define S390_CLOCKADJ		(6 << 1)
92239507Shrs#define S390_FREE		(7 << 1)
93239507Shrs
94239507Shrs/* Status1 bits */
95239507Shrs#define S390_ST1_POC		(1 << 7)
96239507Shrs#define S390_ST1_BLD		(1 << 6)
97239507Shrs#define S390_ST1_24H		(1 << 1)
98239507Shrs#define S390_ST1_RESET		(1 << 0)
99239507Shrs
100239507Shrs/* Status2 bits */
101239507Shrs#define S390_ST2_TEST		(1 << 7)
102239507Shrs
103239507Shrs/* Realtime1 data bytes */
104239507Shrs#define S390_RT1_NBYTES		7
105239507Shrs#define S390_RT1_YEAR		0
106239507Shrs#define S390_RT1_MONTH		1
107239507Shrs#define S390_RT1_DAY		2
108239507Shrs#define S390_RT1_WDAY		3
109239507Shrs#define S390_RT1_HOUR		4
110239507Shrs#define S390_RT1_MINUTE		5
111239507Shrs#define S390_RT1_SECOND		6
112239507Shrs
113239507Shrsstruct s390rtc_softc {
114239507Shrs	device_t	sc_dev;
115239507Shrs	uint16_t	sc_addr;
116239507Shrs};
117239507Shrs
118239507Shrs/*
119239507Shrs * S-35390A interprets bits in each byte on SDA in reverse order.
120239507Shrs * bitreverse() reverses the bits in uint8_t.
121239507Shrs */
122239507Shrsstatic const uint8_t nibbletab[] = {
123239507Shrs	/* 0x0 0000 -> 0000 */	0x0,
124239507Shrs	/* 0x1 0001 -> 1000 */	0x8,
125239507Shrs	/* 0x2 0010 -> 0100 */	0x4,
126239507Shrs	/* 0x3 0011 -> 1100 */	0xc,
127239507Shrs	/* 0x4 0100 -> 0010 */	0x2,
128239507Shrs	/* 0x5 0101 -> 1010 */	0xa,
129239507Shrs	/* 0x6 0110 -> 0110 */	0x6,
130239507Shrs	/* 0x7 0111 -> 1110 */	0xe,
131239507Shrs	/* 0x8 1000 -> 0001 */	0x1,
132239507Shrs	/* 0x9 1001 -> 1001 */	0x9,
133239507Shrs	/* 0xa 1010 -> 0101 */	0x5,
134239507Shrs	/* 0xb 1011 -> 1101 */	0xd,
135239507Shrs	/* 0xc 1100 -> 0011 */	0x3,
136239507Shrs	/* 0xd 1101 -> 1011 */	0xb,
137239507Shrs	/* 0xe 1110 -> 0111 */	0x7,
138239507Shrs	/* 0xf 1111 -> 1111 */	0xf, };
139239507Shrs
140239507Shrsstatic uint8_t
141239507Shrsbitreverse(uint8_t x)
142239507Shrs{
143239507Shrs
144239507Shrs	return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
145239507Shrs}
146239507Shrs
147239507Shrsstatic int
148239507Shrss390rtc_read(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
149239507Shrs{
150239507Shrs	struct s390rtc_softc *sc = device_get_softc(dev);
151239507Shrs	struct iic_msg msg[] = {
152239507Shrs		{
153239507Shrs			.slave = sc->sc_addr | reg,
154239507Shrs			.flags = IIC_M_RD,
155239507Shrs			.len = len,
156239507Shrs			.buf = buf,
157239507Shrs		},
158239507Shrs	};
159239507Shrs	int i;
160239507Shrs	int error;
161239507Shrs
162239507Shrs	error = iicbus_transfer(dev, msg, 1);
163239507Shrs	if (error)
164239507Shrs		return (error);
165239507Shrs
166239507Shrs	/* this chip returns each byte in reverse order */
167239507Shrs	for (i = 0; i < len; ++i)
168239507Shrs		buf[i] = bitreverse(buf[i]);
169239507Shrs
170239507Shrs	return (0);
171239507Shrs}
172239507Shrs
173239507Shrsstatic int
174239507Shrss390rtc_write(device_t dev, uint8_t reg, uint8_t *buf, size_t len)
175239507Shrs{
176239507Shrs	struct s390rtc_softc *sc = device_get_softc(dev);
177239507Shrs	struct iic_msg msg[] = {
178239507Shrs		{
179239507Shrs			.slave = sc->sc_addr | reg,
180239507Shrs			.flags = IIC_M_WR,
181239507Shrs			.len = len,
182239507Shrs			.buf = buf,
183239507Shrs		},
184239507Shrs	};
185239507Shrs	int i;
186239507Shrs
187239507Shrs	/* this chip expects each byte in reverse order */
188239507Shrs	for (i = 0; i < len; ++i)
189239507Shrs		buf[i] = bitreverse(buf[i]);
190239507Shrs
191239507Shrs	return (iicbus_transfer(dev, msg, 1));
192239507Shrs}
193239507Shrs
194239507Shrsstatic int
195239507Shrss390rtc_probe(device_t dev)
196239507Shrs{
197239507Shrs
198239507Shrs	if (iicbus_get_addr(dev) != S390_ADDR) {
199239507Shrs		if (bootverbose)
200239507Shrs			device_printf(dev, "slave address mismatch. "
201239507Shrs			    "(%02x != %02x)\n", iicbus_get_addr(dev),
202239507Shrs			    S390_ADDR);
203239507Shrs		return (ENXIO);
204239507Shrs	}
205239507Shrs	device_set_desc(dev, "Seiko Instruments S-35390A Real-time Clock");
206239507Shrs
207239507Shrs	return (BUS_PROBE_SPECIFIC);
208239507Shrs}
209239507Shrs
210239507Shrsstatic int
211239507Shrss390rtc_attach(device_t dev)
212239507Shrs{
213239507Shrs	struct s390rtc_softc *sc;
214239507Shrs	uint8_t reg;
215239507Shrs	int error;
216239507Shrs
217239507Shrs	sc = device_get_softc(dev);
218239507Shrs	sc->sc_dev = dev;
219239507Shrs	sc->sc_addr = iicbus_get_addr(dev);
220239507Shrs
221239507Shrs	/* Reset the chip and turn on 24h mode, after power-off or battery. */
222239507Shrs	error = s390rtc_read(dev, S390_STATUS1, &reg, 1);
223239507Shrs	if (error) {
224239507Shrs		device_printf(dev, "%s: cannot read status1 register\n",
225239507Shrs		     __func__);
226239507Shrs		return (error);
227239507Shrs	}
228239507Shrs	if (reg & (S390_ST1_POC | S390_ST1_BLD)) {
229239507Shrs		reg |= S390_ST1_24H | S390_ST1_RESET;
230239507Shrs		error = s390rtc_write(dev, S390_STATUS1, &reg, 1);
231239507Shrs		if (error) {
232239507Shrs			device_printf(dev, "%s: cannot initialize\n", __func__);
233239507Shrs			return (error);
234239507Shrs		}
235239507Shrs	}
236239507Shrs
237239507Shrs	/* Disable the test mode, when enabled. */
238239507Shrs	error = s390rtc_read(dev, S390_STATUS2, &reg, 1);
239239507Shrs	if (error) {
240239507Shrs		device_printf(dev, "%s: cannot read status2 register\n",
241239507Shrs		    __func__);
242239507Shrs		return (error);
243239507Shrs	}
244239507Shrs	if (reg & S390_ST2_TEST) {
245239507Shrs		reg &= ~S390_ST2_TEST;
246239507Shrs		error = s390rtc_write(dev, S390_STATUS2, &reg, 1);
247239507Shrs		if (error) {
248239507Shrs			device_printf(dev,
249239507Shrs			    "%s: cannot disable the test mode\n", __func__);
250239507Shrs			return (error);
251239507Shrs		}
252239507Shrs	}
253239507Shrs
254239507Shrs	clock_register(dev, 1000000);   /* 1 second resolution */
255239507Shrs	return (0);
256239507Shrs}
257239507Shrs
258239507Shrsstatic int
259239507Shrss390rtc_gettime(device_t dev, struct timespec *ts)
260239507Shrs{
261239507Shrs	uint8_t bcd[S390_RT1_NBYTES];
262239507Shrs	struct clocktime ct;
263239507Shrs	int error;
264239507Shrs
265239507Shrs	error = s390rtc_read(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES);
266239507Shrs	if (error) {
267239507Shrs		device_printf(dev, "%s: cannot read realtime1 register\n",
268239507Shrs		    __func__);
269239507Shrs		return (error);
270239507Shrs	}
271239507Shrs
272239507Shrs	/*
273239507Shrs	 * Convert the register values into something useable.
274239507Shrs	 */
275239507Shrs	ct.nsec = 0;
276239507Shrs	ct.sec = FROMBCD(bcd[S390_RT1_SECOND]);
277239507Shrs	ct.min = FROMBCD(bcd[S390_RT1_MINUTE]);
278239507Shrs	ct.hour = FROMBCD(bcd[S390_RT1_HOUR] & 0x3f);
279239507Shrs	ct.day = FROMBCD(bcd[S390_RT1_DAY]);
280239507Shrs	ct.dow = bcd[S390_RT1_WDAY] & 0x07;
281239507Shrs	ct.mon = FROMBCD(bcd[S390_RT1_MONTH]);
282239507Shrs	ct.year = FROMBCD(bcd[S390_RT1_YEAR]) + 2000;
283239507Shrs
284239507Shrs	return (clock_ct_to_ts(&ct, ts));
285239507Shrs}
286239507Shrs
287239507Shrsstatic int
288239507Shrss390rtc_settime(device_t dev, struct timespec *ts)
289239507Shrs{
290239507Shrs	uint8_t bcd[S390_RT1_NBYTES];
291239507Shrs	struct clocktime ct;
292239507Shrs
293239507Shrs	clock_ts_to_ct(ts, &ct);
294239507Shrs
295239507Shrs	/*
296239507Shrs	 * Convert our time representation into something the S-xx390
297239507Shrs	 * can understand.
298239507Shrs	 */
299239507Shrs	bcd[S390_RT1_SECOND] = TOBCD(ct.sec);
300239507Shrs	bcd[S390_RT1_MINUTE] = TOBCD(ct.min);
301239507Shrs	bcd[S390_RT1_HOUR] = TOBCD(ct.hour);
302239507Shrs	bcd[S390_RT1_DAY] = TOBCD(ct.day);
303239507Shrs	bcd[S390_RT1_WDAY] = ct.dow;
304239507Shrs	bcd[S390_RT1_MONTH] = TOBCD(ct.mon);
305239507Shrs	bcd[S390_RT1_YEAR] = TOBCD(ct.year % 100);
306239507Shrs
307239507Shrs	return (s390rtc_write(dev, S390_REALTIME1, bcd, S390_RT1_NBYTES));
308239507Shrs}
309239507Shrs
310239507Shrsstatic device_method_t s390rtc_methods[] = {
311239507Shrs	DEVMETHOD(device_probe,		s390rtc_probe),
312239507Shrs	DEVMETHOD(device_attach,	s390rtc_attach),
313239507Shrs
314239507Shrs	DEVMETHOD(clock_gettime,	s390rtc_gettime),
315239507Shrs	DEVMETHOD(clock_settime,	s390rtc_settime),
316239507Shrs
317239507Shrs	DEVMETHOD_END
318239507Shrs};
319239507Shrs
320239507Shrsstatic driver_t s390rtc_driver = {
321239507Shrs	S390_DEVNAME,
322239507Shrs	s390rtc_methods,
323239507Shrs	sizeof(struct s390rtc_softc),
324239507Shrs};
325239507Shrsstatic devclass_t s390rtc_devclass;
326239507Shrs
327239507ShrsDRIVER_MODULE(s35390a, iicbus, s390rtc_driver, s390rtc_devclass, NULL, NULL);
328239507ShrsMODULE_VERSION(s35390a, 1);
329239507ShrsMODULE_DEPEND(s35390a, iicbus, 1, 1, 1);
330