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. */
65 static void ds1307_start(void *);
68 ds1307_read(device_t dev, uint16_t addr, uint8_t reg, uint8_t *data, size_t len)
70 struct iic_msg msg[2] = {
71 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
72 { addr, IIC_M_RD, len, data },
75 return (iicbus_transfer(dev, msg, nitems(msg)));
79 ds1307_write(device_t dev, uint16_t addr, uint8_t *data, size_t len)
81 struct iic_msg msg[1] = {
82 { addr, IIC_M_WR, len, data },
85 return (iicbus_transfer(dev, msg, nitems(msg)));
89 ds1307_ctrl_read(struct ds1307_softc *sc)
94 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_CONTROL,
95 &sc->sc_ctrl, sizeof(sc->sc_ctrl));
97 device_printf(sc->sc_dev, "cannot read from RTC.\n");
105 ds1307_ctrl_write(struct ds1307_softc *sc)
110 data[0] = DS1307_CONTROL;
111 data[1] = sc->sc_ctrl & DS1307_CTRL_MASK;
112 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
114 device_printf(sc->sc_dev, "cannot write to RTC.\n");
120 ds1307_osc_enable(struct ds1307_softc *sc)
123 uint8_t data[2], secs;
126 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_SECS,
127 &secs, sizeof(secs));
129 device_printf(sc->sc_dev, "cannot read from RTC.\n");
132 /* Check if the oscillator is disabled. */
133 if ((secs & DS1307_SECS_CH) == 0)
135 device_printf(sc->sc_dev, "clock was halted, check the battery.\n");
136 data[0] = DS1307_SECS;
137 data[1] = secs & DS1307_SECS_MASK;
138 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
140 device_printf(sc->sc_dev, "cannot write to RTC.\n");
146 ds1307_set_24hrs_mode(struct ds1307_softc *sc)
149 uint8_t data[2], hour;
152 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_HOUR,
153 &hour, sizeof(hour));
155 device_printf(sc->sc_dev, "cannot read from RTC.\n");
158 data[0] = DS1307_HOUR;
159 data[1] = hour & DS1307_HOUR_MASK;
160 error = ds1307_write(sc->sc_dev, sc->sc_addr, data, sizeof(data));
162 device_printf(sc->sc_dev, "cannot write to RTC.\n");
168 ds1307_sqwe_sysctl(SYSCTL_HANDLER_ARGS)
170 int sqwe, error, newv;
171 struct ds1307_softc *sc;
173 sc = (struct ds1307_softc *)arg1;
174 error = ds1307_ctrl_read(sc);
177 sqwe = newv = (sc->sc_ctrl & DS1307_CTRL_SQWE) ? 1 : 0;
178 error = sysctl_handle_int(oidp, &newv, 0, req);
179 if (error != 0 || req->newptr == NULL)
182 sc->sc_ctrl &= ~DS1307_CTRL_SQWE;
184 sc->sc_ctrl |= DS1307_CTRL_SQWE;
185 error = ds1307_ctrl_write(sc);
194 ds1307_sqw_freq_sysctl(SYSCTL_HANDLER_ARGS)
196 int ds1307_sqw_freq[] = { 1, 4096, 8192, 32768 };
197 int error, freq, i, newf, tmp;
198 struct ds1307_softc *sc;
200 sc = (struct ds1307_softc *)arg1;
201 error = ds1307_ctrl_read(sc);
204 tmp = (sc->sc_ctrl & DS1307_CTRL_RS_MASK);
205 if (tmp >= nitems(ds1307_sqw_freq))
206 tmp = nitems(ds1307_sqw_freq) - 1;
207 freq = ds1307_sqw_freq[tmp];
208 error = sysctl_handle_int(oidp, &freq, 0, req);
209 if (error != 0 || req->newptr == NULL)
211 if (freq != ds1307_sqw_freq[tmp]) {
213 for (i = 0; i < nitems(ds1307_sqw_freq); i++)
214 if (freq >= ds1307_sqw_freq[i])
216 sc->sc_ctrl &= ~DS1307_CTRL_RS_MASK;
218 error = ds1307_ctrl_write(sc);
227 ds1307_sqw_out_sysctl(SYSCTL_HANDLER_ARGS)
229 int sqwe, error, newv;
230 struct ds1307_softc *sc;
232 sc = (struct ds1307_softc *)arg1;
233 error = ds1307_ctrl_read(sc);
236 sqwe = newv = (sc->sc_ctrl & DS1307_CTRL_OUT) ? 1 : 0;
237 error = sysctl_handle_int(oidp, &newv, 0, req);
238 if (error != 0 || req->newptr == NULL)
241 sc->sc_ctrl &= ~DS1307_CTRL_OUT;
243 sc->sc_ctrl |= DS1307_CTRL_OUT;
244 error = ds1307_ctrl_write(sc);
253 ds1307_probe(device_t dev)
257 if (!ofw_bus_status_okay(dev))
259 if (!ofw_bus_is_compatible(dev, "dallas,ds1307") &&
260 !ofw_bus_is_compatible(dev, "maxim,ds1307"))
263 device_set_desc(dev, "Maxim DS1307 RTC");
265 return (BUS_PROBE_DEFAULT);
269 ds1307_attach(device_t dev)
271 struct ds1307_softc *sc;
273 sc = device_get_softc(dev);
275 sc->sc_addr = iicbus_get_addr(dev);
277 sc->enum_hook.ich_func = ds1307_start;
278 sc->enum_hook.ich_arg = dev;
281 * We have to wait until interrupts are enabled. Usually I2C read
282 * and write only works when the interrupts are available.
284 if (config_intrhook_establish(&sc->enum_hook) != 0)
291 ds1307_start(void *xdev)
294 struct ds1307_softc *sc;
295 struct sysctl_ctx_list *ctx;
296 struct sysctl_oid *tree_node;
297 struct sysctl_oid_list *tree;
299 dev = (device_t)xdev;
300 sc = device_get_softc(dev);
301 ctx = device_get_sysctl_ctx(dev);
302 tree_node = device_get_sysctl_tree(dev);
303 tree = SYSCTL_CHILDREN(tree_node);
305 config_intrhook_disestablish(&sc->enum_hook);
306 /* Set the 24 hours mode. */
307 if (ds1307_set_24hrs_mode(sc) != 0)
309 /* Enable the oscillator if halted. */
310 if (ds1307_osc_enable(sc) != 0)
313 /* Configuration parameters. */
314 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqwe",
315 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
316 ds1307_sqwe_sysctl, "IU", "DS1307 square-wave enable");
317 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_freq",
318 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
319 ds1307_sqw_freq_sysctl, "IU",
320 "DS1307 square-wave output frequency");
321 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_out",
322 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
323 ds1307_sqw_out_sysctl, "IU", "DS1307 square-wave output state");
325 /* 1 second resolution. */
326 clock_register(dev, 1000000);
330 ds1307_gettime(device_t dev, struct timespec *ts)
334 struct ds1307_softc *sc;
337 sc = device_get_softc(dev);
338 memset(data, 0, sizeof(data));
339 error = ds1307_read(sc->sc_dev, sc->sc_addr, DS1307_SECS,
342 device_printf(dev, "cannot read from RTC.\n");
346 ct.sec = FROMBCD(data[DS1307_SECS] & DS1307_SECS_MASK);
347 ct.min = FROMBCD(data[DS1307_MINS] & DS1307_MINS_MASK);
348 ct.hour = FROMBCD(data[DS1307_HOUR] & DS1307_HOUR_MASK);
349 ct.day = FROMBCD(data[DS1307_DATE] & DS1307_DATE_MASK);
350 ct.dow = data[DS1307_WEEKDAY] & DS1307_WEEKDAY_MASK;
351 ct.mon = FROMBCD(data[DS1307_MONTH] & DS1307_MONTH_MASK);
352 ct.year = FROMBCD(data[DS1307_YEAR] & DS1307_YEAR_MASK);
353 ct.year += sc->sc_year0;
354 if (ct.year < POSIX_BASE_YEAR)
355 ct.year += 100; /* assume [1970, 2069] */
357 return (clock_ct_to_ts(&ct, ts));
361 ds1307_settime(device_t dev, struct timespec *ts)
365 struct ds1307_softc *sc;
368 sc = device_get_softc(dev);
369 /* Accuracy is only one second. */
370 if (ts->tv_nsec >= 500000000)
373 clock_ts_to_ct(ts, &ct);
374 memset(data, 0, sizeof(data));
375 data[0] = DS1307_SECS;
376 data[DS1307_SECS + 1] = TOBCD(ct.sec);
377 data[DS1307_MINS + 1] = TOBCD(ct.min);
378 data[DS1307_HOUR + 1] = TOBCD(ct.hour);
379 data[DS1307_DATE + 1] = TOBCD(ct.day);
380 data[DS1307_WEEKDAY + 1] = ct.dow;
381 data[DS1307_MONTH + 1] = TOBCD(ct.mon);
382 data[DS1307_YEAR + 1] = TOBCD(ct.year % 100);
383 /* Write the time back to RTC. */
384 error = ds1307_write(dev, sc->sc_addr, data, sizeof(data));
386 device_printf(dev, "cannot write to RTC.\n");
391 static device_method_t ds1307_methods[] = {
392 DEVMETHOD(device_probe, ds1307_probe),
393 DEVMETHOD(device_attach, ds1307_attach),
395 DEVMETHOD(clock_gettime, ds1307_gettime),
396 DEVMETHOD(clock_settime, ds1307_settime),
401 static driver_t ds1307_driver = {
404 sizeof(struct ds1307_softc),
407 static devclass_t ds1307_devclass;
409 DRIVER_MODULE(ds1307, iicbus, ds1307_driver, ds1307_devclass, NULL, NULL);
410 MODULE_VERSION(ds1307, 1);
411 MODULE_DEPEND(ds1307, iicbus, 1, 1, 1);