xref: /trueos/sys/dev/iicbus/ds133x.c (revision b972b67ed72b5687a023c92602aaef64163b2f59)
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 
77 enum {
78 	DS1337,
79 	DS1338,
80 	DS1339,
81 };
82 
83 struct ds133x_softc {
84 	int		sc_type;
85 	device_t	sc_dev;
86 };
87 
88 static int
ds133x_read(device_t dev,uint8_t address,uint8_t * data,uint8_t size)89 ds133x_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 
99 static int
ds133x_write(device_t dev,uint8_t address,uint8_t * data,uint8_t size)100 ds133x_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 
116 static int
ds133x_detect(device_t dev,int * sc_type)117 ds133x_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 
185 static int
ds133x_init(device_t dev,uint8_t cs_reg,uint8_t cs_bit,uint8_t osf_reg,uint8_t osf_bit)186 ds133x_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 
216 static void
ds133x_identify(driver_t * driver,device_t parent)217 ds133x_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 
224 static int
ds133x_probe(device_t dev)225 ds133x_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 
252 static int
ds133x_attach(device_t dev)253 ds133x_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 
271 static uint8_t
ds133x_get_hours(uint8_t val)272 ds133x_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 
286 static int
ds133x_gettime(device_t dev,struct timespec * ts)287 ds133x_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 
316 static int
ds133x_settime(device_t dev,struct timespec * ts)317 ds133x_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 
342 static 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 
353 static driver_t ds133x_driver = {
354 	DS133X_DEVNAME,
355 	ds133x_methods,
356 	sizeof(struct ds133x_softc),
357 };
358 
359 static devclass_t ds133x_devclass;
360 
361 DRIVER_MODULE(ds133x, iicbus, ds133x_driver, ds133x_devclass, 0, 0);
362 MODULE_VERSION(ds133x, 1);
363 MODULE_DEPEND(ds133x, iicbus, 1, 1, 1);
364