ds13rtc.c revision 322473
1322473Sian/*-
2322473Sian * Copyright (c) 2017 Ian Lepore <ian@freebsd.org>
3322473Sian * All rights reserved.
4322473Sian *
5322473Sian * Redistribution and use in source and binary forms, with or without
6322473Sian * modification, are permitted provided that the following conditions
7322473Sian * are met:
8322473Sian * 1. Redistributions of source code must retain the above copyright
9322473Sian *    notice, this list of conditions and the following disclaimer.
10322473Sian * 2. Redistributions in binary form must reproduce the above copyright
11322473Sian *    notice, this list of conditions and the following disclaimer in the
12322473Sian *    documentation and/or other materials provided with the distribution.
13322473Sian *
14322473Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15322473Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16322473Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17322473Sian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18322473Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19322473Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20322473Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21322473Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22322473Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23322473Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24322473Sian * SUCH DAMAGE.
25322473Sian */
26322473Sian
27322473Sian#include <sys/cdefs.h>
28322473Sian__FBSDID("$FreeBSD: head/sys/dev/iicbus/ds13rtc.c 322473 2017-08-13 21:02:40Z ian $");
29322473Sian
30322473Sian/*
31322473Sian * Driver for Dallas/Maxim DS13xx real-time clock/calendar chips:
32322473Sian *
33322473Sian * - DS1307 = Original/basic rtc + 56 bytes ram; 5v only.
34322473Sian * - DS1308 = Updated 1307, available in 1.8v-5v variations.
35322473Sian * - DS1337 = Like 1308, integrated xtal, 32khz output on at powerup.
36322473Sian * - DS1338 = Like 1308, integrated xtal.
37322473Sian * - DS1339 = Like 1337, integrated xtal, integrated trickle charger.
38322473Sian * - DS1340 = Like 1338, ST M41T00 compatible.
39322473Sian * - DS1341 = Like 1338, can slave-sync osc to external clock signal.
40322473Sian * - DS1342 = Like 1341 but requires different xtal.
41322473Sian * - DS1371 = 32-bit binary counter, watchdog timer.
42322473Sian * - DS1372 = 32-bit binary counter, 64-bit unique id in rom.
43322473Sian * - DS1374 = 32-bit binary counter, watchdog timer, trickle charger.
44322473Sian * - DS1375 = Like 1308 but only 16 bytes ram.
45322473Sian * - DS1388 = Rtc, watchdog timer, 512 bytes eeprom (not sram).
46322473Sian *
47322473Sian * This driver supports only basic timekeeping functions.  It provides no access
48322473Sian * to or control over any other functionality provided by the chips.
49322473Sian */
50322473Sian
51322473Sian#include "opt_platform.h"
52322473Sian
53322473Sian#include <sys/param.h>
54322473Sian#include <sys/systm.h>
55322473Sian#include <sys/bus.h>
56322473Sian#include <sys/clock.h>
57322473Sian#include <sys/endian.h>
58322473Sian#include <sys/kernel.h>
59322473Sian#include <sys/libkern.h>
60322473Sian#include <sys/module.h>
61322473Sian
62322473Sian#include <dev/iicbus/iicbus.h>
63322473Sian#include <dev/iicbus/iiconf.h>
64322473Sian#ifdef FDT
65322473Sian#include <dev/ofw/openfirm.h>
66322473Sian#include <dev/ofw/ofw_bus.h>
67322473Sian#include <dev/ofw/ofw_bus_subr.h>
68322473Sian#endif
69322473Sian
70322473Sian#include "clock_if.h"
71322473Sian#include "iicbus_if.h"
72322473Sian
73322473Sian/*
74322473Sian * I2C address 1101 000x
75322473Sian */
76322473Sian#define	DS13xx_ADDR		0xd0
77322473Sian
78322473Sian/*
79322473Sian * Registers, bits within them, and masks for the various chip types.
80322473Sian */
81322473Sian
82322473Sian#define	DS13xx_R_NONE		0xff	/* Placeholder */
83322473Sian
84322473Sian#define	DS130x_R_CONTROL	0x07
85322473Sian#define	DS133x_R_CONTROL	0x0e
86322473Sian#define	DS1340_R_CONTROL	0x07
87322473Sian#define	DS1341_R_CONTROL	0x0e
88322473Sian#define	DS1371_R_CONTROL	0x07
89322473Sian#define	DS1372_R_CONTROL	0x07
90322473Sian#define	DS1374_R_CONTROL	0x07
91322473Sian#define	DS1375_R_CONTROL	0x0e
92322473Sian#define	DS1388_R_CONTROL	0x0c
93322473Sian
94322473Sian#define	DS13xx_R_SECOND		0x00
95322473Sian#define	DS1388_R_SECOND		0x01
96322473Sian
97322473Sian#define	DS130x_R_STATUS		DS13xx_R_NONE
98322473Sian#define	DS133x_R_STATUS		0x0f
99322473Sian#define	DS1340_R_STATUS		0x09
100322473Sian#define	DS137x_R_STATUS		0x08
101322473Sian#define	DS1388_R_STATUS		0x0b
102322473Sian
103322473Sian#define	DS13xx_B_STATUS_OSF	0x80	/* OSF is 1<<7 in status and sec regs */
104322473Sian#define	DS13xx_B_HOUR_AMPM	0x40	/* AMPM mode is bit 1<<6 */
105322473Sian#define	DS13xx_B_HOUR_PM	0x20	/* PM hours indicated by 1<<5 */
106322473Sian#define	DS13xx_B_MONTH_CENTURY	0x80	/* 21st century indicated by 1<<7 */
107322473Sian
108322473Sian#define	DS13xx_M_SECOND		0x7f	/* Masks for all BCD time regs... */
109322473Sian#define	DS13xx_M_MINUTE		0x7f
110322473Sian#define	DS13xx_M_12HOUR		0x1f
111322473Sian#define	DS13xx_M_24HOUR		0x3f
112322473Sian#define	DS13xx_M_DAY		0x3f
113322473Sian#define	DS13xx_M_MONTH		0x1f
114322473Sian#define	DS13xx_M_YEAR		0xff
115322473Sian
116322473Sian/*
117322473Sian * The chip types we support.
118322473Sian */
119322473Sianenum {
120322473Sian	TYPE_NONE,
121322473Sian	TYPE_DS1307,
122322473Sian	TYPE_DS1308,
123322473Sian	TYPE_DS1337,
124322473Sian	TYPE_DS1338,
125322473Sian	TYPE_DS1339,
126322473Sian	TYPE_DS1340,
127322473Sian	TYPE_DS1341,
128322473Sian	TYPE_DS1342,
129322473Sian	TYPE_DS1371,
130322473Sian	TYPE_DS1372,
131322473Sian	TYPE_DS1374,
132322473Sian	TYPE_DS1375,
133322473Sian	TYPE_DS1388,
134322473Sian
135322473Sian	TYPE_COUNT
136322473Sian};
137322473Sianstatic const char *desc_strings[] = {
138322473Sian	"",
139322473Sian	"Dallas/Maxim DS1307 RTC",
140322473Sian	"Dallas/Maxim DS1308 RTC",
141322473Sian	"Dallas/Maxim DS1337 RTC",
142322473Sian	"Dallas/Maxim DS1338 RTC",
143322473Sian	"Dallas/Maxim DS1339 RTC",
144322473Sian	"Dallas/Maxim DS1340 RTC",
145322473Sian	"Dallas/Maxim DS1341 RTC",
146322473Sian	"Dallas/Maxim DS1342 RTC",
147322473Sian	"Dallas/Maxim DS1371 RTC",
148322473Sian	"Dallas/Maxim DS1372 RTC",
149322473Sian	"Dallas/Maxim DS1374 RTC",
150322473Sian	"Dallas/Maxim DS1375 RTC",
151322473Sian	"Dallas/Maxim DS1388 RTC",
152322473Sian};
153322473SianCTASSERT(nitems(desc_strings) == TYPE_COUNT);
154322473Sian
155322473Sian/*
156322473Sian * The time registers in the order they are laid out in hardware.
157322473Sian */
158322473Sianstruct time_regs {
159322473Sian	uint8_t sec, min, hour, wday, day, month, year;
160322473Sian};
161322473Sian
162322473Sianstruct ds13rtc_softc {
163322473Sian	device_t	dev;
164322473Sian	device_t	busdev;
165322473Sian	u_int		flags;		/* SC_F_* flags */
166322473Sian	u_int		chiptype;	/* Type of DS13xx chip */
167322473Sian	uint8_t		secaddr;	/* Address of seconds register */
168322473Sian	uint8_t		osfaddr;	/* Address of register with OSF */
169322473Sian};
170322473Sian
171322473Sian#define	SC_F_BINARY	(1u << 0)	/* Time is 32-bit binary counter */
172322473Sian#define	SC_F_AMPM	(1u << 1)	/* Use PM flag in hours reg */
173322473Sian#define	SC_F_CENTURY	(1u << 2)	/* Use century bit */
174322473Sian
175322473Sian/*
176322473Sian * We use the compat_data table to look up hint strings in the non-FDT case, so
177322473Sian * define the struct locally when we don't get it from ofw_bus_subr.h.
178322473Sian */
179322473Sian#ifdef FDT
180322473Siantypedef struct ofw_compat_data ds13_compat_data;
181322473Sian#else
182322473Siantypedef struct {
183322473Sian	const char *ocd_str;
184322473Sian	uintptr_t  ocd_data;
185322473Sian} ds13_compat_data;
186322473Sian#endif
187322473Sian
188322473Sianstatic ds13_compat_data compat_data[] = {
189322473Sian	{"dallas,ds1307",   TYPE_DS1307},
190322473Sian	{"dallas,ds1308",   TYPE_DS1308},
191322473Sian	{"dallas,ds1337",   TYPE_DS1337},
192322473Sian	{"dallas,ds1338",   TYPE_DS1338},
193322473Sian	{"dallas,ds1339",   TYPE_DS1339},
194322473Sian	{"dallas,ds1340",   TYPE_DS1340},
195322473Sian	{"dallas,ds1341",   TYPE_DS1341},
196322473Sian	{"dallas,ds1342",   TYPE_DS1342},
197322473Sian	{"dallas,ds1371",   TYPE_DS1371},
198322473Sian	{"dallas,ds1372",   TYPE_DS1372},
199322473Sian	{"dallas,ds1374",   TYPE_DS1374},
200322473Sian	{"dallas,ds1375",   TYPE_DS1375},
201322473Sian	{"dallas,ds1388",   TYPE_DS1388},
202322473Sian
203322473Sian	{NULL,              TYPE_NONE},
204322473Sian};
205322473Sian
206322473Sianstatic int
207322473Sianread_reg(struct ds13rtc_softc *sc, uint8_t reg, uint8_t *val)
208322473Sian{
209322473Sian
210322473Sian	return (iicdev_readfrom(sc->dev, reg, val, sizeof(*val), IIC_WAIT));
211322473Sian}
212322473Sian
213322473Sianstatic int
214322473Sianwrite_reg(struct ds13rtc_softc *sc, uint8_t reg, uint8_t val)
215322473Sian{
216322473Sian
217322473Sian	return (iicdev_writeto(sc->dev, reg, &val, sizeof(val), IIC_WAIT));
218322473Sian}
219322473Sian
220322473Sianstatic int
221322473Sianread_timeregs(struct ds13rtc_softc *sc, struct time_regs *tregs)
222322473Sian{
223322473Sian	int err;
224322473Sian
225322473Sian	if ((err = iicdev_readfrom(sc->dev, sc->secaddr, tregs,
226322473Sian	    sizeof(*tregs), IIC_WAIT)) != 0)
227322473Sian		return (err);
228322473Sian
229322473Sian	return (err);
230322473Sian}
231322473Sian
232322473Sianstatic int
233322473Sianwrite_timeregs(struct ds13rtc_softc *sc, struct time_regs *tregs)
234322473Sian{
235322473Sian
236322473Sian	return (iicdev_writeto(sc->dev, sc->secaddr, tregs,
237322473Sian	    sizeof(*tregs), IIC_WAIT));
238322473Sian}
239322473Sian
240322473Sianstatic int
241322473Sianread_timeword(struct ds13rtc_softc *sc, time_t *secs)
242322473Sian{
243322473Sian	int err;
244322473Sian	uint8_t buf[4];
245322473Sian
246322473Sian	if ((err = iicdev_readfrom(sc->dev, sc->secaddr, buf, sizeof(buf),
247322473Sian	    IIC_WAIT)) == 0)
248322473Sian		*secs = le32dec(buf);
249322473Sian
250322473Sian	return (err);
251322473Sian}
252322473Sian
253322473Sianstatic int
254322473Sianwrite_timeword(struct ds13rtc_softc *sc, time_t secs)
255322473Sian{
256322473Sian	uint8_t buf[4];
257322473Sian
258322473Sian	le32enc(buf, (uint32_t)secs);
259322473Sian	return (iicdev_writeto(sc->dev, sc->secaddr, buf, sizeof(buf),
260322473Sian	    IIC_WAIT));
261322473Sian}
262322473Sian
263322473Sianstatic void
264322473Siands13rtc_start(void *arg)
265322473Sian{
266322473Sian	struct ds13rtc_softc *sc;
267322473Sian	uint8_t ctlreg, statreg;
268322473Sian
269322473Sian	sc = arg;
270322473Sian
271322473Sian	/*
272322473Sian	 * Every chip in this family can be usefully initialized by writing 0 to
273322473Sian	 * the control register, except DS1375 which has an external oscillator
274322473Sian	 * controlled by values in the ctlreg that we know nothing about, so
275322473Sian	 * we'd best leave them alone.  For all other chips, writing 0 enables
276322473Sian	 * the oscillator, disables signals/outputs in battery-backed mode
277322473Sian	 * (saves power) and disables features like watchdog timers and alarms.
278322473Sian	 */
279322473Sian	switch (sc->chiptype) {
280322473Sian	case TYPE_DS1307:
281322473Sian	case TYPE_DS1308:
282322473Sian	case TYPE_DS1338:
283322473Sian	case TYPE_DS1340:
284322473Sian	case TYPE_DS1371:
285322473Sian	case TYPE_DS1372:
286322473Sian	case TYPE_DS1374:
287322473Sian		ctlreg = DS130x_R_CONTROL;
288322473Sian		break;
289322473Sian	case TYPE_DS1337:
290322473Sian	case TYPE_DS1339:
291322473Sian		ctlreg = DS133x_R_CONTROL;
292322473Sian		break;
293322473Sian	case TYPE_DS1341:
294322473Sian	case TYPE_DS1342:
295322473Sian		ctlreg = DS1341_R_CONTROL;
296322473Sian		break;
297322473Sian	case TYPE_DS1375:
298322473Sian		ctlreg = DS13xx_R_NONE;
299322473Sian		break;
300322473Sian	case TYPE_DS1388:
301322473Sian		ctlreg = DS1388_R_CONTROL;
302322473Sian		break;
303322473Sian	default:
304322473Sian		device_printf(sc->dev, "missing init code for this chiptype\n");
305322473Sian		return;
306322473Sian	}
307322473Sian	if (ctlreg != DS13xx_R_NONE)
308322473Sian		write_reg(sc, ctlreg, 0);
309322473Sian
310322473Sian	/*
311322473Sian	 * Common init.  Read the OSF/CH status bit and report stopped clocks to
312322473Sian	 * the user.  The status bit will be cleared the first time we write
313322473Sian	 * valid time to the chip (and must not be cleared before that).
314322473Sian	 */
315322473Sian	if (read_reg(sc, sc->osfaddr, &statreg) != 0) {
316322473Sian		device_printf(sc->dev, "cannot read RTC clock status bit\n");
317322473Sian		return;
318322473Sian	}
319322473Sian	if (statreg & DS13xx_B_STATUS_OSF) {
320322473Sian		device_printf(sc->dev,
321322473Sian		    "WARNING: RTC battery failed; time is invalid\n");
322322473Sian	}
323322473Sian
324322473Sian	/*
325322473Sian	 * Figure out whether the chip is configured for AM/PM mode.  On all
326322473Sian	 * chips that do AM/PM mode, the flag bit is in the hours register,
327322473Sian	 * which is secaddr+2.
328322473Sian	 */
329322473Sian	if ((sc->chiptype != TYPE_DS1340) && !(sc->flags & SC_F_BINARY)) {
330322473Sian		if (read_reg(sc, sc->secaddr + 2, &statreg) != 0) {
331322473Sian			device_printf(sc->dev,
332322473Sian			    "cannot read RTC clock AM/PM bit\n");
333322473Sian			return;
334322473Sian		}
335322473Sian		if (statreg & DS13xx_B_HOUR_AMPM)
336322473Sian			sc->flags |= SC_F_AMPM;
337322473Sian	}
338322473Sian
339322473Sian	/*
340322473Sian	 * Everything looks good if we make it to here; register as an RTC.
341322473Sian	 * Schedule RTC updates to happen just after top-of-second.
342322473Sian	 */
343322473Sian	clock_register_flags(sc->dev, 1000000, CLOCKF_SETTIME_NO_ADJ);
344322473Sian	clock_schedule(sc->dev, 1);
345322473Sian}
346322473Sian
347322473Sianstatic int
348322473Siands13rtc_gettime(device_t dev, struct timespec *ts)
349322473Sian{
350322473Sian	struct clocktime ct;
351322473Sian	struct time_regs tregs;
352322473Sian	struct ds13rtc_softc *sc;
353322473Sian	int err;
354322473Sian	uint8_t statreg, hourmask;
355322473Sian
356322473Sian	sc = device_get_softc(dev);
357322473Sian
358322473Sian	/* Read the OSF/CH bit; if the clock stopped we can't provide time. */
359322473Sian	if ((err = read_reg(sc, sc->osfaddr, &statreg)) != 0) {
360322473Sian		return (err);
361322473Sian	}
362322473Sian	if (statreg & DS13xx_B_STATUS_OSF)
363322473Sian		return (EINVAL); /* hardware is good, time is not. */
364322473Sian
365322473Sian	/* If the chip counts time in binary, we just read and return it. */
366322473Sian	if (sc->flags & SC_F_BINARY) {
367322473Sian		if ((err = read_timeword(sc, &ts->tv_sec)) != 0)
368322473Sian			return (err);
369322473Sian		ts->tv_nsec = 0;
370322473Sian	}
371322473Sian
372322473Sian	/*
373322473Sian	 * Chip counts in BCD, read and decode it...
374322473Sian	 */
375322473Sian	if ((err = read_timeregs(sc, &tregs)) != 0) {
376322473Sian		device_printf(dev, "cannot read RTC time\n");
377322473Sian		return (err);
378322473Sian	}
379322473Sian
380322473Sian	if (sc->flags & SC_F_AMPM)
381322473Sian		hourmask = DS13xx_M_12HOUR;
382322473Sian	else
383322473Sian		hourmask = DS13xx_M_24HOUR;
384322473Sian
385322473Sian	ct.sec  = FROMBCD(tregs.sec   & DS13xx_M_SECOND);
386322473Sian	ct.min  = FROMBCD(tregs.min   & DS13xx_M_MINUTE);
387322473Sian	ct.hour = FROMBCD(tregs.hour  & hourmask);
388322473Sian	ct.day  = FROMBCD(tregs.day   & DS13xx_M_DAY);
389322473Sian	ct.mon  = FROMBCD(tregs.month & DS13xx_M_MONTH);
390322473Sian	ct.year = FROMBCD(tregs.year  & DS13xx_M_YEAR);
391322473Sian	ct.nsec = 0;
392322473Sian
393322473Sian	if (sc->flags & SC_F_AMPM) {
394322473Sian		if (ct.hour == 12)
395322473Sian			ct.hour = 0;
396322473Sian		if (tregs.hour & DS13xx_B_HOUR_PM)
397322473Sian			ct.hour += 12;
398322473Sian	}
399322473Sian
400322473Sian	/*
401322473Sian	 * If this chip has a century bit, honor it.  Otherwise let
402322473Sian	 * clock_ct_to_ts() infer the century from the 2-digit year.
403322473Sian	 */
404322473Sian	if (sc->flags & SC_F_CENTURY)
405322473Sian		ct.year += (tregs.month & DS13xx_B_MONTH_CENTURY) ? 2000 : 1900;
406322473Sian
407322473Sian	err = clock_ct_to_ts(&ct, ts);
408322473Sian
409322473Sian	return (err);
410322473Sian}
411322473Sian
412322473Sianstatic int
413322473Siands13rtc_settime(device_t dev, struct timespec *ts)
414322473Sian{
415322473Sian	struct clocktime ct;
416322473Sian	struct time_regs tregs;
417322473Sian	struct ds13rtc_softc *sc;
418322473Sian	int err;
419322473Sian	uint8_t cflag, statreg, pmflag;
420322473Sian
421322473Sian	sc = device_get_softc(dev);
422322473Sian
423322473Sian	/*
424322473Sian	 * We request a timespec with no resolution-adjustment.  That also
425322473Sian	 * disables utc adjustment, so apply that ourselves.
426322473Sian	 */
427322473Sian	ts->tv_sec -= utc_offset();
428322473Sian
429322473Sian	/* If the chip counts time in binary, store tv_sec and we're done. */
430322473Sian	if (sc->flags & SC_F_BINARY)
431322473Sian		return (write_timeword(sc, ts->tv_sec));
432322473Sian
433322473Sian	clock_ts_to_ct(ts, &ct);
434322473Sian
435322473Sian	/* If the chip is in AMPM mode deal with the PM flag. */
436322473Sian	pmflag = 0;
437322473Sian	if (sc->flags & SC_F_AMPM) {
438322473Sian		if (ct.hour >= 12) {
439322473Sian			ct.hour -= 12;
440322473Sian			pmflag = DS13xx_B_HOUR_PM;
441322473Sian		}
442322473Sian		if (ct.hour == 0)
443322473Sian			ct.hour = 12;
444322473Sian	}
445322473Sian
446322473Sian	/* If the chip has a century bit, set it as needed. */
447322473Sian	cflag = 0;
448322473Sian	if (sc->flags & SC_F_CENTURY) {
449322473Sian		if (ct.year >= 2000)
450322473Sian			cflag |= DS13xx_B_MONTH_CENTURY;
451322473Sian	}
452322473Sian
453322473Sian	tregs.sec   = TOBCD(ct.sec);
454322473Sian	tregs.min   = TOBCD(ct.min);
455322473Sian	tregs.hour  = TOBCD(ct.hour) | pmflag;
456322473Sian	tregs.day   = TOBCD(ct.day);
457322473Sian	tregs.month = TOBCD(ct.mon) | cflag;
458322473Sian	tregs.year  = TOBCD(ct.year % 100);
459322473Sian	tregs.wday  = ct.dow;
460322473Sian
461322473Sian	/*
462322473Sian	 * Set the time.  Reset the OSF bit if it is on and it is not part of
463322473Sian	 * the time registers (in which case writing time resets it).
464322473Sian	 */
465322473Sian	if ((err = write_timeregs(sc, &tregs)) != 0)
466322473Sian		goto errout;
467322473Sian	if (sc->osfaddr != sc->secaddr) {
468322473Sian		if ((err = read_reg(sc, sc->osfaddr, &statreg)) != 0)
469322473Sian			goto errout;
470322473Sian		if (statreg & DS13xx_B_STATUS_OSF) {
471322473Sian			statreg &= ~DS13xx_B_STATUS_OSF;
472322473Sian			err = write_reg(sc, sc->osfaddr, statreg);
473322473Sian		}
474322473Sian	}
475322473Sian
476322473Sianerrout:
477322473Sian
478322473Sian	if (err != 0)
479322473Sian		device_printf(dev, "cannot update RTC time\n");
480322473Sian
481322473Sian	return (err);
482322473Sian}
483322473Sian
484322473Sianstatic int
485322473Siands13rtc_get_chiptype(device_t dev)
486322473Sian{
487322473Sian#ifdef FDT
488322473Sian
489322473Sian	return (ofw_bus_search_compatible(dev, compat_data)->ocd_data);
490322473Sian#else
491322473Sian	ds13_compat_data *cdata;
492322473Sian	const char *htype;
493322473Sian
494322473Sian	/*
495322473Sian	 * We can only attach if provided a chiptype hint string.
496322473Sian	 */
497322473Sian	if (resource_string_value(device_get_name(dev),
498322473Sian	    device_get_unit(dev), "chiptype", &htype) != 0)
499322473Sian		return (TYPE_NONE);
500322473Sian
501322473Sian	/*
502322473Sian	 * Loop through the ofw compat data comparing the hinted chip type to
503322473Sian	 * the compat strings.
504322473Sian	 */
505322473Sian	for (cdata = compat_data; cdata->ocd_str != NULL; ++cdata) {
506322473Sian		if (strcmp(htype, cdata->ocd_str) == 0)
507322473Sian			break;
508322473Sian	}
509322473Sian	return (cdata->ocd_data);
510322473Sian#endif
511322473Sian}
512322473Sian
513322473Sianstatic int
514322473Siands13rtc_probe(device_t dev)
515322473Sian{
516322473Sian	int chiptype, goodrv;
517322473Sian
518322473Sian#ifdef FDT
519322473Sian	if (!ofw_bus_status_okay(dev))
520322473Sian		return (ENXIO);
521322473Sian	goodrv = BUS_PROBE_GENERIC;
522322473Sian#else
523322473Sian	goodrv = BUS_PROBE_NOWILDCARD;
524322473Sian#endif
525322473Sian
526322473Sian	chiptype = ds13rtc_get_chiptype(dev);
527322473Sian	if (chiptype == TYPE_NONE)
528322473Sian		return (ENXIO);
529322473Sian
530322473Sian	device_set_desc(dev, desc_strings[chiptype]);
531322473Sian	return (goodrv);
532322473Sian}
533322473Sian
534322473Sianstatic int
535322473Siands13rtc_attach(device_t dev)
536322473Sian{
537322473Sian	struct ds13rtc_softc *sc;
538322473Sian
539322473Sian	sc = device_get_softc(dev);
540322473Sian	sc->dev = dev;
541322473Sian	sc->busdev = device_get_parent(dev);
542322473Sian
543322473Sian	/*
544322473Sian	 * We need to know what kind of chip we're driving.
545322473Sian	 */
546322473Sian	if ((sc->chiptype = ds13rtc_get_chiptype(dev)) == TYPE_NONE) {
547322473Sian		device_printf(dev, "impossible: cannot determine chip type\n");
548322473Sian		return (ENXIO);
549322473Sian	}
550322473Sian
551322473Sian	/* The seconds register is in the same place on all except DS1388. */
552322473Sian	if (sc->chiptype == TYPE_DS1388)
553322473Sian		sc->secaddr = DS1388_R_SECOND;
554322473Sian	else
555322473Sian		sc->secaddr = DS13xx_R_SECOND;
556322473Sian
557322473Sian	/*
558322473Sian	 * The OSF/CH (osc failed/clock-halted) bit appears in different
559322473Sian	 * registers for different chip types.  The DS1375 has no OSF indicator
560322473Sian	 * because it has no internal oscillator; we just point to an always-
561322473Sian	 * zero bit in the status register for that chip.
562322473Sian	 */
563322473Sian	switch (sc->chiptype) {
564322473Sian	case TYPE_DS1307:
565322473Sian	case TYPE_DS1308:
566322473Sian	case TYPE_DS1338:
567322473Sian		sc->osfaddr = DS13xx_R_SECOND;
568322473Sian		break;
569322473Sian	case TYPE_DS1337:
570322473Sian	case TYPE_DS1339:
571322473Sian	case TYPE_DS1341:
572322473Sian	case TYPE_DS1342:
573322473Sian	case TYPE_DS1375:
574322473Sian		sc->osfaddr = DS133x_R_STATUS;
575322473Sian		sc->flags  |= SC_F_CENTURY;
576322473Sian		break;
577322473Sian	case TYPE_DS1340:
578322473Sian		sc->osfaddr = DS1340_R_STATUS;
579322473Sian		break;
580322473Sian	case TYPE_DS1371:
581322473Sian	case TYPE_DS1372:
582322473Sian	case TYPE_DS1374:
583322473Sian		sc->osfaddr = DS137x_R_STATUS;
584322473Sian		sc->flags  |= SC_F_BINARY;
585322473Sian		break;
586322473Sian	case TYPE_DS1388:
587322473Sian		sc->osfaddr = DS1388_R_STATUS;
588322473Sian		break;
589322473Sian	}
590322473Sian
591322473Sian	/*
592322473Sian	 * We have to wait until interrupts are enabled.  Sometimes I2C read
593322473Sian	 * and write only works when the interrupts are available.
594322473Sian	 */
595322473Sian	config_intrhook_oneshot(ds13rtc_start, sc);
596322473Sian
597322473Sian	return (0);
598322473Sian}
599322473Sian
600322473Sianstatic int
601322473Siands13rtc_detach(device_t dev)
602322473Sian{
603322473Sian
604322473Sian	clock_unregister(dev);
605322473Sian	return (0);
606322473Sian}
607322473Sian
608322473Sianstatic device_method_t ds13rtc_methods[] = {
609322473Sian	DEVMETHOD(device_probe,		ds13rtc_probe),
610322473Sian	DEVMETHOD(device_attach,	ds13rtc_attach),
611322473Sian	DEVMETHOD(device_detach,	ds13rtc_detach),
612322473Sian
613322473Sian	DEVMETHOD(clock_gettime,	ds13rtc_gettime),
614322473Sian	DEVMETHOD(clock_settime,	ds13rtc_settime),
615322473Sian
616322473Sian	DEVMETHOD_END
617322473Sian};
618322473Sian
619322473Sianstatic driver_t ds13rtc_driver = {
620322473Sian	"ds13rtc",
621322473Sian	ds13rtc_methods,
622322473Sian	sizeof(struct ds13rtc_softc),
623322473Sian};
624322473Sian
625322473Sianstatic devclass_t ds13rtc_devclass;
626322473Sian
627322473SianDRIVER_MODULE(ds13rtc, iicbus, ds13rtc_driver, ds13rtc_devclass, NULL, NULL);
628322473SianMODULE_VERSION(ds13rtc, 1);
629322473SianMODULE_DEPEND(ds13rtc, iicbus, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
630