1/*-
2 * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>,
3 *                    Rafal Jaworowski <raj@FreeBSD.org>,
4 *                    Piotr Ziecik <kosmo@semihalf.com>.
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, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30/*
31 * Dallas Semiconductor DS133X RTC sitting on the I2C bus.
32 */
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/clock.h>
38#include <sys/time.h>
39#include <sys/bus.h>
40#include <sys/resource.h>
41#include <sys/rman.h>
42
43#include <dev/iicbus/iicbus.h>
44#include <dev/iicbus/iiconf.h>
45
46#include "iicbus_if.h"
47#include "clock_if.h"
48
49#define DS133X_DEVNAME		"ds133x_rtc"
50
51#define	DS133X_ADDR		0xd0	/* slave address */
52#define	DS133X_DATE_REG		0x0
53#define	DS133X_CTRL_REG		0x0e
54#define	DS133X_OSCD_FLAG	0x80
55#define	DS133X_OSF_FLAG		0x80
56
57#define	DS133X_24H_FLAG		0x40	/* 24 hours mode. */
58#define	DS133X_PM_FLAG		0x20	/* AM/PM bit. */
59#define	DS133X_CENT_FLAG	0x80	/* Century selector. */
60#define	DS133X_CENT_SHIFT	7
61
62#define	DS1338_REG_CLOCK_HALT	0x00
63#define	DS1338_REG_CONTROL	0x07
64#define	DS1338_CLOCK_HALT	(1 << 7)
65#define	DS1338_OSC_STOP		(1 << 5)
66
67#define	DS1339_REG_CONTROL	0x0E
68#define	DS1339_REG_STATUS	0x0F
69#define	DS1339_OSC_STOP		(1 << 7)
70#define	DS1339_ENABLE_OSC	(1 << 7)
71#define	DS1339_BBSQI		(1 << 5)
72
73#define	HALFSEC			500000000	/* 1/2 of second. */
74
75#define MAX_IIC_DATA_SIZE	7
76
77enum {
78	DS1337,
79	DS1338,
80	DS1339,
81};
82
83struct ds133x_softc {
84	int		sc_type;
85	device_t	sc_dev;
86};
87
88static int
89ds133x_read(device_t dev, uint8_t address, uint8_t *data, uint8_t size)
90{
91	struct iic_msg msg[] = {
92	    { DS133X_ADDR, IIC_M_WR, 1,	&address },
93	    { DS133X_ADDR, IIC_M_RD, size, data },
94	};
95
96	return (iicbus_transfer(dev, msg, 2));
97}
98
99static int
100ds133x_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size)
101{
102	uint8_t buffer[MAX_IIC_DATA_SIZE + 1];
103	struct iic_msg msg[] = {
104		{ DS133X_ADDR, IIC_M_WR, size + 1, buffer },
105	};
106
107	if (size > MAX_IIC_DATA_SIZE)
108		return (ENOMEM);
109
110	buffer[0] = address;
111	memcpy(buffer + 1, data, size);
112
113	return (iicbus_transfer(dev, msg, 1));
114}
115
116static int
117ds133x_detect(device_t dev, int *sc_type)
118{
119	int error;
120	uint8_t reg, orig;
121
122	/*
123	 * Check for DS1338. At address 0x0F this chip has RAM, however
124	 * DS1337 and DS1339 have status register. Bits 6-2 in status
125	 * register will be always read as 0.
126	 */
127
128	if ((error = ds133x_read(dev, DS1339_REG_STATUS, &reg, 1)))
129		return (error);
130
131	orig = reg;
132	reg |= 0x7C;
133
134	if ((error = ds133x_write(dev, DS1339_REG_STATUS, &reg, 1)))
135		return (error);
136
137	if ((error = ds133x_read(dev, DS1339_REG_STATUS, &reg, 1)))
138		return (error);
139
140	if ((reg & 0x7C) != 0) {
141		/* This is DS1338 */
142
143		if ((error = ds133x_write(dev, DS1339_REG_STATUS, &orig, 1)))
144			return (error);
145
146		*sc_type = DS1338;
147
148		return (0);
149	}
150
151	/*
152	 * Now Check for DS1337. Bit 5 in control register of this chip will be
153	 * allways read as 0. In DS1339 changing of this bit is safe until
154	 * chip is powered up.
155	 */
156
157	if ((error = ds133x_read(dev, DS1339_REG_CONTROL, &reg, 1)))
158		return (error);
159
160	orig = reg;
161	reg |= DS1339_BBSQI;
162
163	if ((error = ds133x_write(dev, DS1339_REG_CONTROL, &reg, 1)))
164		return (error);
165
166	if ((error = ds133x_read(dev, DS1339_REG_CONTROL, &reg, 1)))
167		return (error);
168
169	if ((reg & DS1339_BBSQI) != 0) {
170		/* This is DS1339 */
171
172		if ((error = ds133x_write(dev, DS1339_REG_CONTROL, &orig, 1)))
173			return (error);
174
175		*sc_type = DS1339;
176		return (0);
177	}
178
179	/* This is DS1337 */
180	*sc_type = DS1337;
181
182	return (0);
183}
184
185static int
186ds133x_init(device_t dev, uint8_t cs_reg, uint8_t cs_bit, uint8_t osf_reg,
187    uint8_t osf_bit)
188{
189	int error;
190	uint8_t reg;
191
192	if ((error = ds133x_read(dev, cs_reg, &reg, 1)))
193		return (error);
194
195	if (reg & cs_bit) {	/* If clock is stopped - start it */
196		reg &= ~cs_bit;
197		if ((error = ds133x_write(dev, cs_reg, &reg, 1)))
198			return (error);
199	}
200
201	if ((error = ds133x_read(dev, osf_reg, &reg, 1)))
202		return (error);
203
204	if (reg & osf_bit) {	/* Clear oscillator stop flag */
205		device_printf(dev, "RTC oscillator was stopped. Check system"
206		    " time and RTC battery.\n");
207		reg &= ~osf_bit;
208		if ((error = ds133x_write(dev, osf_reg, &reg, 1)))
209			return (error);
210	}
211
212	return (0);
213}
214
215
216static void
217ds133x_identify(driver_t *driver, device_t parent)
218{
219
220	if (device_find_child(parent, DS133X_DEVNAME, -1) == NULL)
221		BUS_ADD_CHILD(parent, 0, DS133X_DEVNAME, -1);
222}
223
224static int
225ds133x_probe(device_t dev)
226{
227	struct ds133x_softc *sc;
228	int error;
229
230	sc = device_get_softc(dev);
231
232	if ((error = ds133x_detect(dev, &sc->sc_type)))
233		return (error);
234
235	switch (sc->sc_type) {
236	case DS1337:
237		device_set_desc(dev, "Dallas Semiconductor DS1337 RTC");
238		break;
239	case DS1338:
240		device_set_desc(dev, "Dallas Semiconductor DS1338 RTC");
241		break;
242	case DS1339:
243		device_set_desc(dev, "Dallas Semiconductor DS1339 RTC");
244		break;
245	default:
246		break;
247	}
248
249	return (0);
250}
251
252static int
253ds133x_attach(device_t dev)
254{
255	struct ds133x_softc *sc = device_get_softc(dev);
256
257	sc->sc_dev = dev;
258
259	if (sc->sc_type == DS1338)
260		ds133x_init(dev, DS1338_REG_CLOCK_HALT, DS1338_CLOCK_HALT,
261		    DS1338_REG_CONTROL, DS1338_OSC_STOP);
262	else
263		ds133x_init(dev, DS1339_REG_CONTROL, DS1339_ENABLE_OSC,
264		    DS1339_REG_STATUS, DS1339_OSC_STOP);
265
266	clock_register(dev, 1000000);
267
268	return (0);
269}
270
271static uint8_t
272ds133x_get_hours(uint8_t val)
273{
274	uint8_t ret;
275
276	if (!(val & DS133X_24H_FLAG))
277		ret = FROMBCD(val & 0x3f);
278	else if (!(val & DS133X_PM_FLAG))
279		ret = FROMBCD(val & 0x1f);
280	else
281		ret = FROMBCD(val & 0x1f) + 12;
282
283	return (ret);
284}
285
286static int
287ds133x_gettime(device_t dev, struct timespec *ts)
288{
289	struct ds133x_softc *sc = device_get_softc(dev);
290	struct clocktime ct;
291	uint8_t date[7];
292	int error;
293
294	error = ds133x_read(dev, DS133X_DATE_REG, date, 7);
295	if (error == 0) {
296		ct.nsec = 0;
297		ct.sec = FROMBCD(date[0] & 0x7f);
298		ct.min = FROMBCD(date[1] & 0x7f);
299		ct.hour = ds133x_get_hours(date[2]);
300		ct.dow = FROMBCD(date[3] & 0x07) - 1;
301		ct.day = FROMBCD(date[4] & 0x3f);
302		ct.mon = FROMBCD(date[5] & 0x1f);
303
304		if (sc->sc_type == DS1338)
305			ct.year = 2000 + FROMBCD(date[6]);
306		else
307			ct.year = 1900 + FROMBCD(date[6]) +
308			    ((date[5] & DS133X_CENT_FLAG) >> DS133X_CENT_SHIFT) * 100;
309
310		error = clock_ct_to_ts(&ct, ts);
311	}
312
313	return (error);
314}
315
316static int
317ds133x_settime(device_t dev, struct timespec *ts)
318{
319	struct ds133x_softc *sc = device_get_softc(dev);
320	struct clocktime ct;
321	uint8_t date[7];
322
323	clock_ts_to_ct(ts, &ct);
324
325	date[0] = TOBCD(ct.nsec >= HALFSEC ? ct.sec + 1 : ct.sec) & 0x7f;
326	date[1] = TOBCD(ct.min) & 0x7f;
327	date[2] = TOBCD(ct.hour) & 0x3f;	/* We use 24-hours mode. */
328	date[3] = TOBCD(ct.dow + 1) & 0x07;
329	date[4] = TOBCD(ct.day) & 0x3f;
330	date[5] = TOBCD(ct.mon) & 0x1f;
331	if (sc->sc_type == DS1338)
332		date[6] = TOBCD(ct.year - 2000);
333	else if (ct.year >= 2000) {
334		date[5] |= DS133X_CENT_FLAG;
335		date[6] = TOBCD(ct.year - 2000);
336	} else
337		date[6] = TOBCD(ct.year - 1900);
338
339	return (ds133x_write(dev, DS133X_DATE_REG, date, 7));
340}
341
342static device_method_t ds133x_methods[] = {
343	DEVMETHOD(device_identify,	ds133x_identify),
344	DEVMETHOD(device_probe,		ds133x_probe),
345	DEVMETHOD(device_attach,	ds133x_attach),
346
347	DEVMETHOD(clock_gettime,	ds133x_gettime),
348	DEVMETHOD(clock_settime,	ds133x_settime),
349
350	DEVMETHOD_END
351};
352
353static driver_t ds133x_driver = {
354	DS133X_DEVNAME,
355	ds133x_methods,
356	sizeof(struct ds133x_softc),
357};
358
359static devclass_t ds133x_devclass;
360
361DRIVER_MODULE(ds133x, iicbus, ds133x_driver, ds133x_devclass, 0, 0);
362MODULE_VERSION(ds133x, 1);
363MODULE_DEPEND(ds133x, iicbus, 1, 1, 1);
364