2 * Copyright (c) 2015 Luiz Otavio O Souza <loos@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 * Driver for Maxim DS1307 I2C real-time clock/calendar.
34 #include "opt_platform.h"
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/clock.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/sysctl.h>
44 #include <dev/iicbus/iicbus.h>
45 #include <dev/iicbus/iiconf.h>
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
52 #include <dev/iicbus/ds1307reg.h>
55 #include "iicbus_if.h"
60 struct intr_config_hook enum_hook;
61 uint16_t sc_addr; /* DS1307 slave address. */
66 static void ds1307_start(void *);
69 static const struct ofw_compat_data ds1307_compat_data[] = {
70 {"dallas,ds1307", (uintptr_t)"Maxim DS1307 RTC"},
71 {"maxim,ds1307", (uintptr_t)"Maxim DS1307 RTC"},
72 {"microchip,mcp7941x", (uintptr_t)"Microchip MCP7941x RTC"},
78 ds1307_read(device_t dev, uint16_t addr, uint8_t reg, uint8_t *data, size_t len)
80 struct iic_msg msg[2] = {
81 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
82 { addr, IIC_M_RD, len, data },
85 return (iicbus_transfer(dev, msg, nitems(msg)));
89 ds1307_write(device_t dev, uint16_t addr, uint8_t *data, size_t len)
91 struct iic_msg msg[1] = {
92 { addr, IIC_M_WR, len, data },
95 return (iicbus_transfer(dev, msg, nitems(msg)));
99 ds1307_ctrl_read(struct ds1307_softc *sc)
104 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_CONTROL,
105 &sc->sc_ctrl, sizeof(sc->sc_ctrl));
107 device_printf(sc->sc_dev, "cannot read from RTC.\n");
115 ds1307_ctrl_write(struct ds1307_softc *sc)
120 data[0] = DS1307_CONTROL;
121 data[1] = sc->sc_ctrl & DS1307_CTRL_MASK;
122 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
124 device_printf(sc->sc_dev, "cannot write to RTC.\n");
130 ds1307_osc_enable(struct ds1307_softc *sc)
133 uint8_t data[2], secs;
136 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_SECS,
137 &secs, sizeof(secs));
139 device_printf(sc->sc_dev, "cannot read from RTC.\n");
142 /* Check if the oscillator is disabled. */
143 if ((secs & DS1307_SECS_CH) == 0)
145 device_printf(sc->sc_dev, "clock was halted, check the battery.\n");
146 data[0] = DS1307_SECS;
147 data[1] = secs & DS1307_SECS_MASK;
148 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
150 device_printf(sc->sc_dev, "cannot write to RTC.\n");
156 ds1307_set_24hrs_mode(struct ds1307_softc *sc)
159 uint8_t data[2], hour;
162 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_HOUR,
163 &hour, sizeof(hour));
165 device_printf(sc->sc_dev, "cannot read from RTC.\n");
168 data[0] = DS1307_HOUR;
169 data[1] = hour & DS1307_HOUR_MASK;
170 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
172 device_printf(sc->sc_dev, "cannot write to RTC.\n");
178 ds1307_sqwe_sysctl(SYSCTL_HANDLER_ARGS)
180 int sqwe, error, newv, sqwe_bit;
181 struct ds1307_softc *sc;
183 sc = (struct ds1307_softc *)arg1;
184 error = ds1307_ctrl_read(sc);
188 sqwe_bit = MCP7941X_CTRL_SQWE;
190 sqwe_bit = DS1307_CTRL_SQWE;
191 sqwe = newv = (sc->sc_ctrl & sqwe_bit) ? 1 : 0;
192 error = sysctl_handle_int(oidp, &newv, 0, req);
193 if (error != 0 || req->newptr == NULL)
196 sc->sc_ctrl &= ~sqwe_bit;
198 sc->sc_ctrl |= sqwe_bit;
199 error = ds1307_ctrl_write(sc);
208 ds1307_sqw_freq_sysctl(SYSCTL_HANDLER_ARGS)
210 int ds1307_sqw_freq[] = { 1, 4096, 8192, 32768 };
211 int error, freq, i, newf, tmp;
212 struct ds1307_softc *sc;
214 sc = (struct ds1307_softc *)arg1;
215 error = ds1307_ctrl_read(sc);
218 tmp = (sc->sc_ctrl & DS1307_CTRL_RS_MASK);
219 if (tmp >= nitems(ds1307_sqw_freq))
220 tmp = nitems(ds1307_sqw_freq) - 1;
221 freq = ds1307_sqw_freq[tmp];
222 error = sysctl_handle_int(oidp, &freq, 0, req);
223 if (error != 0 || req->newptr == NULL)
225 if (freq != ds1307_sqw_freq[tmp]) {
227 for (i = 0; i < nitems(ds1307_sqw_freq); i++)
228 if (freq >= ds1307_sqw_freq[i])
230 sc->sc_ctrl &= ~DS1307_CTRL_RS_MASK;
232 error = ds1307_ctrl_write(sc);
241 ds1307_sqw_out_sysctl(SYSCTL_HANDLER_ARGS)
243 int sqwe, error, newv;
244 struct ds1307_softc *sc;
246 sc = (struct ds1307_softc *)arg1;
247 error = ds1307_ctrl_read(sc);
250 sqwe = newv = (sc->sc_ctrl & DS1307_CTRL_OUT) ? 1 : 0;
251 error = sysctl_handle_int(oidp, &newv, 0, req);
252 if (error != 0 || req->newptr == NULL)
255 sc->sc_ctrl &= ~DS1307_CTRL_OUT;
257 sc->sc_ctrl |= DS1307_CTRL_OUT;
258 error = ds1307_ctrl_write(sc);
267 ds1307_probe(device_t dev)
270 const struct ofw_compat_data *compat;
272 if (!ofw_bus_status_okay(dev))
275 compat = ofw_bus_search_compatible(dev, ds1307_compat_data);
277 if (compat->ocd_str == NULL)
280 device_set_desc(dev, (const char *)compat->ocd_data);
282 return (BUS_PROBE_DEFAULT);
284 device_set_desc(dev, "Maxim DS1307 RTC");
286 return (BUS_PROBE_DEFAULT);
291 ds1307_attach(device_t dev)
293 struct ds1307_softc *sc;
295 sc = device_get_softc(dev);
297 sc->sc_addr = iicbus_get_addr(dev);
299 sc->enum_hook.ich_func = ds1307_start;
300 sc->enum_hook.ich_arg = dev;
302 if (ofw_bus_is_compatible(dev, "microchip,mcp7941x"))
306 * We have to wait until interrupts are enabled. Usually I2C read
307 * and write only works when the interrupts are available.
309 if (config_intrhook_establish(&sc->enum_hook) != 0)
316 ds1307_start(void *xdev)
319 struct ds1307_softc *sc;
320 struct sysctl_ctx_list *ctx;
321 struct sysctl_oid *tree_node;
322 struct sysctl_oid_list *tree;
324 dev = (device_t)xdev;
325 sc = device_get_softc(dev);
326 ctx = device_get_sysctl_ctx(dev);
327 tree_node = device_get_sysctl_tree(dev);
328 tree = SYSCTL_CHILDREN(tree_node);
330 config_intrhook_disestablish(&sc->enum_hook);
331 /* Set the 24 hours mode. */
332 if (ds1307_set_24hrs_mode(sc) != 0)
334 /* Enable the oscillator if halted. */
335 if (ds1307_osc_enable(sc) != 0)
338 /* Configuration parameters. */
339 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqwe",
340 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
341 ds1307_sqwe_sysctl, "IU", "DS1307 square-wave enable");
342 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_freq",
343 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
344 ds1307_sqw_freq_sysctl, "IU",
345 "DS1307 square-wave output frequency");
346 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_out",
347 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
348 ds1307_sqw_out_sysctl, "IU", "DS1307 square-wave output state");
350 /* 1 second resolution. */
351 clock_register(dev, 1000000);
355 ds1307_gettime(device_t dev, struct timespec *ts)
359 struct ds1307_softc *sc;
362 sc = device_get_softc(dev);
363 memset(data, 0, sizeof(data));
364 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_SECS,
367 device_printf(dev, "cannot read from RTC.\n");
371 ct.sec = FROMBCD(data[DS1307_SECS] & DS1307_SECS_MASK);
372 ct.min = FROMBCD(data[DS1307_MINS] & DS1307_MINS_MASK);
373 ct.hour = FROMBCD(data[DS1307_HOUR] & DS1307_HOUR_MASK);
374 ct.day = FROMBCD(data[DS1307_DATE] & DS1307_DATE_MASK);
375 ct.dow = data[DS1307_WEEKDAY] & DS1307_WEEKDAY_MASK;
376 ct.mon = FROMBCD(data[DS1307_MONTH] & DS1307_MONTH_MASK);
377 ct.year = FROMBCD(data[DS1307_YEAR] & DS1307_YEAR_MASK);
378 ct.year += sc->sc_year0;
379 if (ct.year < POSIX_BASE_YEAR)
380 ct.year += 100; /* assume [1970, 2069] */
382 return (clock_ct_to_ts(&ct, ts));
386 ds1307_settime(device_t dev, struct timespec *ts)
390 struct ds1307_softc *sc;
393 sc = device_get_softc(dev);
394 /* Accuracy is only one second. */
395 if (ts->tv_nsec >= 500000000)
398 clock_ts_to_ct(ts, &ct);
399 memset(data, 0, sizeof(data));
400 data[0] = DS1307_SECS;
401 data[DS1307_SECS + 1] = TOBCD(ct.sec);
402 data[DS1307_MINS + 1] = TOBCD(ct.min);
403 data[DS1307_HOUR + 1] = TOBCD(ct.hour);
404 data[DS1307_DATE + 1] = TOBCD(ct.day);
405 data[DS1307_WEEKDAY + 1] = ct.dow;
406 data[DS1307_MONTH + 1] = TOBCD(ct.mon);
407 data[DS1307_YEAR + 1] = TOBCD(ct.year % 100);
408 /* Write the time back to RTC. */
409 error = ds1307_write(dev, sc->sc_addr, data, sizeof(data));
411 device_printf(dev, "cannot write to RTC.\n");
416 static device_method_t ds1307_methods[] = {
417 DEVMETHOD(device_probe, ds1307_probe),
418 DEVMETHOD(device_attach, ds1307_attach),
420 DEVMETHOD(clock_gettime, ds1307_gettime),
421 DEVMETHOD(clock_settime, ds1307_settime),
426 static driver_t ds1307_driver = {
429 sizeof(struct ds1307_softc),
432 static devclass_t ds1307_devclass;
434 DRIVER_MODULE(ds1307, iicbus, ds1307_driver, ds1307_devclass, NULL, NULL);
435 MODULE_VERSION(ds1307, 1);
436 MODULE_DEPEND(ds1307, iicbus, 1, 1, 1);