12f16049cSEmmanuel Vadot /*- 22f16049cSEmmanuel Vadot * Copyright (c) 2014-2015 Luiz Otavio O Souza <loos@FreeBSD.org> 32f16049cSEmmanuel Vadot * All rights reserved. 42f16049cSEmmanuel Vadot * 52f16049cSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 62f16049cSEmmanuel Vadot * modification, are permitted provided that the following conditions 72f16049cSEmmanuel Vadot * are met: 82f16049cSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 92f16049cSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 102f16049cSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 112f16049cSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 122f16049cSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 132f16049cSEmmanuel Vadot * 142f16049cSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152f16049cSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162f16049cSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172f16049cSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182f16049cSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192f16049cSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202f16049cSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212f16049cSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222f16049cSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232f16049cSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242f16049cSEmmanuel Vadot * SUCH DAMAGE. 252f16049cSEmmanuel Vadot */ 262f16049cSEmmanuel Vadot 272f16049cSEmmanuel Vadot #include <sys/cdefs.h> 282f16049cSEmmanuel Vadot /* 292f16049cSEmmanuel Vadot * Driver for Maxim DS3231[N] real-time clock/calendar. 302f16049cSEmmanuel Vadot */ 312f16049cSEmmanuel Vadot 322f16049cSEmmanuel Vadot #include "opt_platform.h" 332f16049cSEmmanuel Vadot 342f16049cSEmmanuel Vadot #include <sys/param.h> 352f16049cSEmmanuel Vadot #include <sys/systm.h> 362f16049cSEmmanuel Vadot #include <sys/bus.h> 372f16049cSEmmanuel Vadot #include <sys/clock.h> 382f16049cSEmmanuel Vadot #include <sys/kernel.h> 392f16049cSEmmanuel Vadot #include <sys/module.h> 402f16049cSEmmanuel Vadot #include <sys/sysctl.h> 412f16049cSEmmanuel Vadot 422f16049cSEmmanuel Vadot #include <dev/iicbus/iicbus.h> 432f16049cSEmmanuel Vadot #include <dev/iicbus/iiconf.h> 442f16049cSEmmanuel Vadot #ifdef FDT 452f16049cSEmmanuel Vadot #include <dev/ofw/openfirm.h> 462f16049cSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 472f16049cSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 482f16049cSEmmanuel Vadot #endif 492f16049cSEmmanuel Vadot 502f16049cSEmmanuel Vadot #include <dev/iicbus/rtc/ds3231reg.h> 512f16049cSEmmanuel Vadot 522f16049cSEmmanuel Vadot #include "clock_if.h" 532f16049cSEmmanuel Vadot #include "iicbus_if.h" 542f16049cSEmmanuel Vadot 552f16049cSEmmanuel Vadot struct ds3231_softc { 562f16049cSEmmanuel Vadot device_t sc_dev; 572f16049cSEmmanuel Vadot int sc_last_c; 582f16049cSEmmanuel Vadot int sc_year0; 592f16049cSEmmanuel Vadot struct intr_config_hook enum_hook; 602f16049cSEmmanuel Vadot uint16_t sc_addr; /* DS3231 slave address. */ 612f16049cSEmmanuel Vadot uint8_t sc_ctrl; 622f16049cSEmmanuel Vadot uint8_t sc_status; 632f16049cSEmmanuel Vadot bool sc_use_ampm; 642f16049cSEmmanuel Vadot }; 652f16049cSEmmanuel Vadot 662f16049cSEmmanuel Vadot static void ds3231_start(void *); 672f16049cSEmmanuel Vadot 682f16049cSEmmanuel Vadot static int 692f16049cSEmmanuel Vadot ds3231_read1(device_t dev, uint8_t reg, uint8_t *data) 702f16049cSEmmanuel Vadot { 712f16049cSEmmanuel Vadot 722f16049cSEmmanuel Vadot return (iicdev_readfrom(dev, reg, data, 1, IIC_INTRWAIT)); 732f16049cSEmmanuel Vadot } 742f16049cSEmmanuel Vadot 752f16049cSEmmanuel Vadot static int 762f16049cSEmmanuel Vadot ds3231_write1(device_t dev, uint8_t reg, uint8_t data) 772f16049cSEmmanuel Vadot { 782f16049cSEmmanuel Vadot 792f16049cSEmmanuel Vadot return (iicdev_writeto(dev, reg, &data, 1, IIC_INTRWAIT)); 802f16049cSEmmanuel Vadot } 812f16049cSEmmanuel Vadot 822f16049cSEmmanuel Vadot static int 832f16049cSEmmanuel Vadot ds3231_ctrl_read(struct ds3231_softc *sc) 842f16049cSEmmanuel Vadot { 852f16049cSEmmanuel Vadot int error; 862f16049cSEmmanuel Vadot 872f16049cSEmmanuel Vadot error = ds3231_read1(sc->sc_dev, DS3231_CONTROL, &sc->sc_ctrl); 882f16049cSEmmanuel Vadot if (error) { 892f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "cannot read from RTC.\n"); 902f16049cSEmmanuel Vadot return (error); 912f16049cSEmmanuel Vadot } 922f16049cSEmmanuel Vadot return (0); 932f16049cSEmmanuel Vadot } 942f16049cSEmmanuel Vadot 952f16049cSEmmanuel Vadot static int 962f16049cSEmmanuel Vadot ds3231_ctrl_write(struct ds3231_softc *sc) 972f16049cSEmmanuel Vadot { 982f16049cSEmmanuel Vadot int error; 992f16049cSEmmanuel Vadot uint8_t data; 1002f16049cSEmmanuel Vadot 1012f16049cSEmmanuel Vadot /* Always enable the oscillator. Always disable both alarms. */ 1022f16049cSEmmanuel Vadot data = sc->sc_ctrl & ~DS3231_CTRL_MASK; 1032f16049cSEmmanuel Vadot error = ds3231_write1(sc->sc_dev, DS3231_CONTROL, data); 1042f16049cSEmmanuel Vadot if (error != 0) 1052f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "cannot write to RTC.\n"); 1062f16049cSEmmanuel Vadot 1072f16049cSEmmanuel Vadot return (error); 1082f16049cSEmmanuel Vadot } 1092f16049cSEmmanuel Vadot 1102f16049cSEmmanuel Vadot static int 1112f16049cSEmmanuel Vadot ds3231_status_read(struct ds3231_softc *sc) 1122f16049cSEmmanuel Vadot { 1132f16049cSEmmanuel Vadot int error; 1142f16049cSEmmanuel Vadot 1152f16049cSEmmanuel Vadot error = ds3231_read1(sc->sc_dev, DS3231_STATUS, &sc->sc_status); 1162f16049cSEmmanuel Vadot if (error) { 1172f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "cannot read from RTC.\n"); 1182f16049cSEmmanuel Vadot return (error); 1192f16049cSEmmanuel Vadot } 1202f16049cSEmmanuel Vadot 1212f16049cSEmmanuel Vadot return (0); 1222f16049cSEmmanuel Vadot } 1232f16049cSEmmanuel Vadot 1242f16049cSEmmanuel Vadot static int 1252f16049cSEmmanuel Vadot ds3231_status_write(struct ds3231_softc *sc, int clear_a1, int clear_a2) 1262f16049cSEmmanuel Vadot { 1272f16049cSEmmanuel Vadot int error; 1282f16049cSEmmanuel Vadot uint8_t data; 1292f16049cSEmmanuel Vadot 1302f16049cSEmmanuel Vadot data = sc->sc_status; 1312f16049cSEmmanuel Vadot if (clear_a1 == 0) 1322f16049cSEmmanuel Vadot data |= DS3231_STATUS_A1F; 1332f16049cSEmmanuel Vadot if (clear_a2 == 0) 1342f16049cSEmmanuel Vadot data |= DS3231_STATUS_A2F; 1352f16049cSEmmanuel Vadot error = ds3231_write1(sc->sc_dev, DS3231_STATUS, data); 1362f16049cSEmmanuel Vadot if (error != 0) 1372f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "cannot write to RTC.\n"); 1382f16049cSEmmanuel Vadot 1392f16049cSEmmanuel Vadot return (error); 1402f16049cSEmmanuel Vadot } 1412f16049cSEmmanuel Vadot 1422f16049cSEmmanuel Vadot static int 1432f16049cSEmmanuel Vadot ds3231_temp_read(struct ds3231_softc *sc, int *temp) 1442f16049cSEmmanuel Vadot { 1452f16049cSEmmanuel Vadot int error, neg, t; 1462f16049cSEmmanuel Vadot uint8_t buf8[2]; 1472f16049cSEmmanuel Vadot uint16_t buf; 1482f16049cSEmmanuel Vadot 1492f16049cSEmmanuel Vadot error = iicdev_readfrom(sc->sc_dev, DS3231_TEMP, buf8, sizeof(buf8), 1502f16049cSEmmanuel Vadot IIC_INTRWAIT); 1512f16049cSEmmanuel Vadot if (error != 0) 1522f16049cSEmmanuel Vadot return (error); 1532f16049cSEmmanuel Vadot buf = (buf8[0] << 8) | (buf8[1] & 0xff); 1542f16049cSEmmanuel Vadot neg = 0; 1552f16049cSEmmanuel Vadot if (buf & DS3231_NEG_BIT) { 1562f16049cSEmmanuel Vadot buf = ~(buf & DS3231_TEMP_MASK) + 1; 1572f16049cSEmmanuel Vadot neg = 1; 1582f16049cSEmmanuel Vadot } 1592f16049cSEmmanuel Vadot *temp = ((int16_t)buf >> 8) * 10; 1602f16049cSEmmanuel Vadot t = 0; 1612f16049cSEmmanuel Vadot if (buf & DS3231_0250C) 1622f16049cSEmmanuel Vadot t += 250; 1632f16049cSEmmanuel Vadot if (buf & DS3231_0500C) 1642f16049cSEmmanuel Vadot t += 500; 1652f16049cSEmmanuel Vadot t /= 100; 1662f16049cSEmmanuel Vadot *temp += t; 1672f16049cSEmmanuel Vadot if (neg) 1682f16049cSEmmanuel Vadot *temp = -(*temp); 1692f16049cSEmmanuel Vadot *temp += TZ_ZEROC; 1702f16049cSEmmanuel Vadot 1712f16049cSEmmanuel Vadot return (0); 1722f16049cSEmmanuel Vadot } 1732f16049cSEmmanuel Vadot 1742f16049cSEmmanuel Vadot static int 1752f16049cSEmmanuel Vadot ds3231_temp_sysctl(SYSCTL_HANDLER_ARGS) 1762f16049cSEmmanuel Vadot { 1772f16049cSEmmanuel Vadot int error, temp; 1782f16049cSEmmanuel Vadot struct ds3231_softc *sc; 1792f16049cSEmmanuel Vadot 1802f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 1812f16049cSEmmanuel Vadot if (ds3231_temp_read(sc, &temp) != 0) 1822f16049cSEmmanuel Vadot return (EIO); 1832f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &temp, 0, req); 1842f16049cSEmmanuel Vadot 1852f16049cSEmmanuel Vadot return (error); 1862f16049cSEmmanuel Vadot } 1872f16049cSEmmanuel Vadot 1882f16049cSEmmanuel Vadot static int 1892f16049cSEmmanuel Vadot ds3231_conv_sysctl(SYSCTL_HANDLER_ARGS) 1902f16049cSEmmanuel Vadot { 1912f16049cSEmmanuel Vadot int error, conv, newc; 1922f16049cSEmmanuel Vadot struct ds3231_softc *sc; 1932f16049cSEmmanuel Vadot 1942f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 1952f16049cSEmmanuel Vadot error = ds3231_ctrl_read(sc); 1962f16049cSEmmanuel Vadot if (error != 0) 1972f16049cSEmmanuel Vadot return (error); 1982f16049cSEmmanuel Vadot newc = conv = (sc->sc_ctrl & DS3231_CTRL_CONV) ? 1 : 0; 1992f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &newc, 0, req); 2002f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 2012f16049cSEmmanuel Vadot return (error); 2022f16049cSEmmanuel Vadot if (conv == 0 && newc != 0) { 2032f16049cSEmmanuel Vadot error = ds3231_status_read(sc); 2042f16049cSEmmanuel Vadot if (error != 0) 2052f16049cSEmmanuel Vadot return (error); 2062f16049cSEmmanuel Vadot if (sc->sc_status & DS3231_STATUS_BUSY) 2072f16049cSEmmanuel Vadot return (0); 2082f16049cSEmmanuel Vadot sc->sc_ctrl |= DS3231_CTRL_CONV; 2092f16049cSEmmanuel Vadot error = ds3231_ctrl_write(sc); 2102f16049cSEmmanuel Vadot if (error != 0) 2112f16049cSEmmanuel Vadot return (error); 2122f16049cSEmmanuel Vadot } 2132f16049cSEmmanuel Vadot 2142f16049cSEmmanuel Vadot return (error); 2152f16049cSEmmanuel Vadot } 2162f16049cSEmmanuel Vadot 2172f16049cSEmmanuel Vadot static int 2182f16049cSEmmanuel Vadot ds3231_bbsqw_sysctl(SYSCTL_HANDLER_ARGS) 2192f16049cSEmmanuel Vadot { 2202f16049cSEmmanuel Vadot int bbsqw, error, newb; 2212f16049cSEmmanuel Vadot struct ds3231_softc *sc; 2222f16049cSEmmanuel Vadot 2232f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 2242f16049cSEmmanuel Vadot error = ds3231_ctrl_read(sc); 2252f16049cSEmmanuel Vadot if (error != 0) 2262f16049cSEmmanuel Vadot return (error); 2272f16049cSEmmanuel Vadot bbsqw = newb = (sc->sc_ctrl & DS3231_CTRL_BBSQW) ? 1 : 0; 2282f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &newb, 0, req); 2292f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 2302f16049cSEmmanuel Vadot return (error); 2312f16049cSEmmanuel Vadot if (bbsqw != newb) { 2322f16049cSEmmanuel Vadot sc->sc_ctrl &= ~DS3231_CTRL_BBSQW; 2332f16049cSEmmanuel Vadot if (newb) 2342f16049cSEmmanuel Vadot sc->sc_ctrl |= DS3231_CTRL_BBSQW; 2352f16049cSEmmanuel Vadot error = ds3231_ctrl_write(sc); 2362f16049cSEmmanuel Vadot if (error != 0) 2372f16049cSEmmanuel Vadot return (error); 2382f16049cSEmmanuel Vadot } 2392f16049cSEmmanuel Vadot 2402f16049cSEmmanuel Vadot return (error); 2412f16049cSEmmanuel Vadot } 2422f16049cSEmmanuel Vadot 2432f16049cSEmmanuel Vadot static int 2442f16049cSEmmanuel Vadot ds3231_sqw_freq_sysctl(SYSCTL_HANDLER_ARGS) 2452f16049cSEmmanuel Vadot { 2462f16049cSEmmanuel Vadot int ds3231_sqw_freq[] = { 1, 1024, 4096, 8192 }; 2472f16049cSEmmanuel Vadot int error, freq, i, newf, tmp; 2482f16049cSEmmanuel Vadot struct ds3231_softc *sc; 2492f16049cSEmmanuel Vadot 2502f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 2512f16049cSEmmanuel Vadot error = ds3231_ctrl_read(sc); 2522f16049cSEmmanuel Vadot if (error != 0) 2532f16049cSEmmanuel Vadot return (error); 2542f16049cSEmmanuel Vadot tmp = (sc->sc_ctrl & DS3231_CTRL_RS_MASK) >> DS3231_CTRL_RS_SHIFT; 2552f16049cSEmmanuel Vadot if (tmp >= nitems(ds3231_sqw_freq)) 2562f16049cSEmmanuel Vadot tmp = nitems(ds3231_sqw_freq) - 1; 2572f16049cSEmmanuel Vadot freq = ds3231_sqw_freq[tmp]; 2582f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &freq, 0, req); 2592f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 2602f16049cSEmmanuel Vadot return (error); 2612f16049cSEmmanuel Vadot if (freq != ds3231_sqw_freq[tmp]) { 2622f16049cSEmmanuel Vadot newf = 0; 2632f16049cSEmmanuel Vadot for (i = 0; i < nitems(ds3231_sqw_freq); i++) 2642f16049cSEmmanuel Vadot if (freq >= ds3231_sqw_freq[i]) 2652f16049cSEmmanuel Vadot newf = i; 2662f16049cSEmmanuel Vadot sc->sc_ctrl &= ~DS3231_CTRL_RS_MASK; 2672f16049cSEmmanuel Vadot sc->sc_ctrl |= newf << DS3231_CTRL_RS_SHIFT; 2682f16049cSEmmanuel Vadot error = ds3231_ctrl_write(sc); 2692f16049cSEmmanuel Vadot if (error != 0) 2702f16049cSEmmanuel Vadot return (error); 2712f16049cSEmmanuel Vadot } 2722f16049cSEmmanuel Vadot 2732f16049cSEmmanuel Vadot return (error); 2742f16049cSEmmanuel Vadot } 2752f16049cSEmmanuel Vadot 2762f16049cSEmmanuel Vadot static int 2772f16049cSEmmanuel Vadot ds3231_str_sqw_mode(char *buf) 2782f16049cSEmmanuel Vadot { 2792f16049cSEmmanuel Vadot int len, rtrn; 2802f16049cSEmmanuel Vadot 2812f16049cSEmmanuel Vadot rtrn = -1; 2822f16049cSEmmanuel Vadot len = strlen(buf); 2832f16049cSEmmanuel Vadot if ((len > 2 && strncasecmp("interrupt", buf, len) == 0) || 2842f16049cSEmmanuel Vadot (len > 2 && strncasecmp("int", buf, len) == 0)) { 2852f16049cSEmmanuel Vadot rtrn = 1; 2862f16049cSEmmanuel Vadot } else if ((len > 2 && strncasecmp("square-wave", buf, len) == 0) || 2872f16049cSEmmanuel Vadot (len > 2 && strncasecmp("sqw", buf, len) == 0)) { 2882f16049cSEmmanuel Vadot rtrn = 0; 2892f16049cSEmmanuel Vadot } 2902f16049cSEmmanuel Vadot 2912f16049cSEmmanuel Vadot return (rtrn); 2922f16049cSEmmanuel Vadot } 2932f16049cSEmmanuel Vadot 2942f16049cSEmmanuel Vadot static int 2952f16049cSEmmanuel Vadot ds3231_sqw_mode_sysctl(SYSCTL_HANDLER_ARGS) 2962f16049cSEmmanuel Vadot { 2972f16049cSEmmanuel Vadot char buf[16]; 2982f16049cSEmmanuel Vadot int error, mode, newm; 2992f16049cSEmmanuel Vadot struct ds3231_softc *sc; 3002f16049cSEmmanuel Vadot 3012f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 3022f16049cSEmmanuel Vadot error = ds3231_ctrl_read(sc); 3032f16049cSEmmanuel Vadot if (error != 0) 3042f16049cSEmmanuel Vadot return (error); 3052f16049cSEmmanuel Vadot if (sc->sc_ctrl & DS3231_CTRL_INTCN) { 3062f16049cSEmmanuel Vadot mode = 1; 3072f16049cSEmmanuel Vadot strlcpy(buf, "interrupt", sizeof(buf)); 3082f16049cSEmmanuel Vadot } else { 3092f16049cSEmmanuel Vadot mode = 0; 3102f16049cSEmmanuel Vadot strlcpy(buf, "square-wave", sizeof(buf)); 3112f16049cSEmmanuel Vadot } 3122f16049cSEmmanuel Vadot error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 3132f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 3142f16049cSEmmanuel Vadot return (error); 3152f16049cSEmmanuel Vadot newm = ds3231_str_sqw_mode(buf); 3162f16049cSEmmanuel Vadot if (newm != -1 && mode != newm) { 3172f16049cSEmmanuel Vadot sc->sc_ctrl &= ~DS3231_CTRL_INTCN; 3182f16049cSEmmanuel Vadot if (newm == 1) 3192f16049cSEmmanuel Vadot sc->sc_ctrl |= DS3231_CTRL_INTCN; 3202f16049cSEmmanuel Vadot error = ds3231_ctrl_write(sc); 3212f16049cSEmmanuel Vadot if (error != 0) 3222f16049cSEmmanuel Vadot return (error); 3232f16049cSEmmanuel Vadot } 3242f16049cSEmmanuel Vadot 3252f16049cSEmmanuel Vadot return (error); 3262f16049cSEmmanuel Vadot } 3272f16049cSEmmanuel Vadot 3282f16049cSEmmanuel Vadot static int 3292f16049cSEmmanuel Vadot ds3231_en32khz_sysctl(SYSCTL_HANDLER_ARGS) 3302f16049cSEmmanuel Vadot { 3312f16049cSEmmanuel Vadot int error, en32khz, tmp; 3322f16049cSEmmanuel Vadot struct ds3231_softc *sc; 3332f16049cSEmmanuel Vadot 3342f16049cSEmmanuel Vadot sc = (struct ds3231_softc *)arg1; 3352f16049cSEmmanuel Vadot error = ds3231_status_read(sc); 3362f16049cSEmmanuel Vadot if (error != 0) 3372f16049cSEmmanuel Vadot return (error); 3382f16049cSEmmanuel Vadot tmp = en32khz = (sc->sc_status & DS3231_STATUS_EN32KHZ) ? 1 : 0; 3392f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &en32khz, 0, req); 3402f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 3412f16049cSEmmanuel Vadot return (error); 3422f16049cSEmmanuel Vadot if (en32khz != tmp) { 3432f16049cSEmmanuel Vadot sc->sc_status &= ~DS3231_STATUS_EN32KHZ; 3442f16049cSEmmanuel Vadot if (en32khz) 3452f16049cSEmmanuel Vadot sc->sc_status |= DS3231_STATUS_EN32KHZ; 3462f16049cSEmmanuel Vadot error = ds3231_status_write(sc, 0, 0); 3472f16049cSEmmanuel Vadot if (error != 0) 3482f16049cSEmmanuel Vadot return (error); 3492f16049cSEmmanuel Vadot } 3502f16049cSEmmanuel Vadot 3512f16049cSEmmanuel Vadot return (error); 3522f16049cSEmmanuel Vadot } 3532f16049cSEmmanuel Vadot 3542f16049cSEmmanuel Vadot static int 3552f16049cSEmmanuel Vadot ds3231_probe(device_t dev) 3562f16049cSEmmanuel Vadot { 3572f16049cSEmmanuel Vadot int rc; 3582f16049cSEmmanuel Vadot 3592f16049cSEmmanuel Vadot #ifdef FDT 3602f16049cSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 3612f16049cSEmmanuel Vadot return (ENXIO); 3622f16049cSEmmanuel Vadot if (ofw_bus_is_compatible(dev, "maxim,ds3231")) 3632f16049cSEmmanuel Vadot rc = BUS_PROBE_DEFAULT; 3642f16049cSEmmanuel Vadot else 3652f16049cSEmmanuel Vadot #endif 3662f16049cSEmmanuel Vadot rc = BUS_PROBE_NOWILDCARD; 3672f16049cSEmmanuel Vadot 3682f16049cSEmmanuel Vadot device_set_desc(dev, "Maxim DS3231 RTC"); 3692f16049cSEmmanuel Vadot 3702f16049cSEmmanuel Vadot return (rc); 3712f16049cSEmmanuel Vadot } 3722f16049cSEmmanuel Vadot 3732f16049cSEmmanuel Vadot static int 3742f16049cSEmmanuel Vadot ds3231_attach(device_t dev) 3752f16049cSEmmanuel Vadot { 3762f16049cSEmmanuel Vadot struct ds3231_softc *sc; 3772f16049cSEmmanuel Vadot 3782f16049cSEmmanuel Vadot sc = device_get_softc(dev); 3792f16049cSEmmanuel Vadot sc->sc_dev = dev; 3802f16049cSEmmanuel Vadot sc->sc_addr = iicbus_get_addr(dev); 3812f16049cSEmmanuel Vadot sc->sc_last_c = -1; 3822f16049cSEmmanuel Vadot sc->sc_year0 = 0; 3832f16049cSEmmanuel Vadot sc->enum_hook.ich_func = ds3231_start; 3842f16049cSEmmanuel Vadot sc->enum_hook.ich_arg = dev; 3852f16049cSEmmanuel Vadot 3862f16049cSEmmanuel Vadot /* 3872f16049cSEmmanuel Vadot * We have to wait until interrupts are enabled. Usually I2C read 3882f16049cSEmmanuel Vadot * and write only works when the interrupts are available. 3892f16049cSEmmanuel Vadot */ 3902f16049cSEmmanuel Vadot if (config_intrhook_establish(&sc->enum_hook) != 0) 3912f16049cSEmmanuel Vadot return (ENOMEM); 3922f16049cSEmmanuel Vadot 3932f16049cSEmmanuel Vadot return (0); 3942f16049cSEmmanuel Vadot } 3952f16049cSEmmanuel Vadot 3962f16049cSEmmanuel Vadot static int 3972f16049cSEmmanuel Vadot ds3231_detach(device_t dev) 3982f16049cSEmmanuel Vadot { 3992f16049cSEmmanuel Vadot 4002f16049cSEmmanuel Vadot clock_unregister(dev); 4012f16049cSEmmanuel Vadot return (0); 4022f16049cSEmmanuel Vadot } 4032f16049cSEmmanuel Vadot 4042f16049cSEmmanuel Vadot static void 4052f16049cSEmmanuel Vadot ds3231_start(void *xdev) 4062f16049cSEmmanuel Vadot { 4072f16049cSEmmanuel Vadot device_t dev; 4082f16049cSEmmanuel Vadot struct ds3231_softc *sc; 4092f16049cSEmmanuel Vadot struct sysctl_ctx_list *ctx; 4102f16049cSEmmanuel Vadot struct sysctl_oid *tree_node; 4112f16049cSEmmanuel Vadot struct sysctl_oid_list *tree; 4122f16049cSEmmanuel Vadot 4132f16049cSEmmanuel Vadot dev = (device_t)xdev; 4142f16049cSEmmanuel Vadot sc = device_get_softc(dev); 4152f16049cSEmmanuel Vadot ctx = device_get_sysctl_ctx(dev); 4162f16049cSEmmanuel Vadot tree_node = device_get_sysctl_tree(dev); 4172f16049cSEmmanuel Vadot tree = SYSCTL_CHILDREN(tree_node); 4182f16049cSEmmanuel Vadot 4192f16049cSEmmanuel Vadot config_intrhook_disestablish(&sc->enum_hook); 4202f16049cSEmmanuel Vadot if (ds3231_ctrl_read(sc) != 0) 4212f16049cSEmmanuel Vadot return; 4222f16049cSEmmanuel Vadot if (ds3231_status_read(sc) != 0) 4232f16049cSEmmanuel Vadot return; 4242f16049cSEmmanuel Vadot /* 4252f16049cSEmmanuel Vadot * Warn if the clock stopped, but don't restart it until the first 4262f16049cSEmmanuel Vadot * clock_settime() call. 4272f16049cSEmmanuel Vadot */ 4282f16049cSEmmanuel Vadot if (sc->sc_status & DS3231_STATUS_OSF) { 4292f16049cSEmmanuel Vadot device_printf(sc->sc_dev, 4302f16049cSEmmanuel Vadot "WARNING: RTC clock stopped, check the battery.\n"); 4312f16049cSEmmanuel Vadot } 4322f16049cSEmmanuel Vadot 4332f16049cSEmmanuel Vadot /* 4342f16049cSEmmanuel Vadot * Ack any pending alarm interrupts and clear the EOSC bit to ensure the 4352f16049cSEmmanuel Vadot * clock runs even when on battery power. Do not give up if these 4362f16049cSEmmanuel Vadot * writes fail, because a factory-fresh chip is in a special mode that 4372f16049cSEmmanuel Vadot * disables much of the chip to save battery power, and the only thing 4382f16049cSEmmanuel Vadot * that gets it out of that mode is writing to the time registers. In 4392f16049cSEmmanuel Vadot * these pristine chips, the EOSC and alarm bits are zero already, so 4402f16049cSEmmanuel Vadot * the first valid write of time will get everything running properly. 4412f16049cSEmmanuel Vadot */ 4422f16049cSEmmanuel Vadot ds3231_status_write(sc, 1, 1); 4432f16049cSEmmanuel Vadot ds3231_ctrl_write(sc); 4442f16049cSEmmanuel Vadot 4452f16049cSEmmanuel Vadot /* Temperature. */ 4462f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature", 4472f16049cSEmmanuel Vadot CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 4482f16049cSEmmanuel Vadot ds3231_temp_sysctl, "IK", "Current temperature"); 4492f16049cSEmmanuel Vadot /* Configuration parameters. */ 4502f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temp_conv", 4512f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4522f16049cSEmmanuel Vadot ds3231_conv_sysctl, "IU", 453*3dd490e8SBrooks Davis "DS3231 start a new temperature conversion"); 4542f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "bbsqw", 4552f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4562f16049cSEmmanuel Vadot ds3231_bbsqw_sysctl, "IU", 4572f16049cSEmmanuel Vadot "DS3231 battery-backed square-wave output enable"); 4582f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_freq", 4592f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4602f16049cSEmmanuel Vadot ds3231_sqw_freq_sysctl, "IU", 4612f16049cSEmmanuel Vadot "DS3231 square-wave output frequency"); 4622f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_mode", 4632f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0, 4642f16049cSEmmanuel Vadot ds3231_sqw_mode_sysctl, "A", "DS3231 SQW output mode control"); 4652f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "32khz_enable", 4662f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4672f16049cSEmmanuel Vadot ds3231_en32khz_sysctl, "IU", "DS3231 enable the 32kHz output"); 4682f16049cSEmmanuel Vadot 4692f16049cSEmmanuel Vadot /* 4702f16049cSEmmanuel Vadot * Register as a clock with 1 second resolution. Schedule the 4712f16049cSEmmanuel Vadot * clock_settime() method to be called just after top-of-second; 4722f16049cSEmmanuel Vadot * resetting the time resets top-of-second in the hardware. 4732f16049cSEmmanuel Vadot */ 4742f16049cSEmmanuel Vadot clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_ADJ); 4752f16049cSEmmanuel Vadot clock_schedule(dev, 1); 4762f16049cSEmmanuel Vadot } 4772f16049cSEmmanuel Vadot 4782f16049cSEmmanuel Vadot static int 4792f16049cSEmmanuel Vadot ds3231_gettime(device_t dev, struct timespec *ts) 4802f16049cSEmmanuel Vadot { 4812f16049cSEmmanuel Vadot int c, error; 4822f16049cSEmmanuel Vadot struct bcd_clocktime bct; 4832f16049cSEmmanuel Vadot struct ds3231_softc *sc; 4842f16049cSEmmanuel Vadot uint8_t data[7], hourmask; 4852f16049cSEmmanuel Vadot 4862f16049cSEmmanuel Vadot sc = device_get_softc(dev); 4872f16049cSEmmanuel Vadot 4882f16049cSEmmanuel Vadot /* If the clock halted, we don't have good data. */ 4892f16049cSEmmanuel Vadot if ((error = ds3231_status_read(sc)) != 0) { 4902f16049cSEmmanuel Vadot device_printf(dev, "cannot read from RTC.\n"); 4912f16049cSEmmanuel Vadot return (error); 4922f16049cSEmmanuel Vadot } 4932f16049cSEmmanuel Vadot if (sc->sc_status & DS3231_STATUS_OSF) 4942f16049cSEmmanuel Vadot return (EINVAL); 4952f16049cSEmmanuel Vadot 4962f16049cSEmmanuel Vadot error = iicdev_readfrom(sc->sc_dev, DS3231_SECS, data, sizeof(data), 4972f16049cSEmmanuel Vadot IIC_INTRWAIT); 4982f16049cSEmmanuel Vadot if (error != 0) { 4992f16049cSEmmanuel Vadot device_printf(dev, "cannot read from RTC.\n"); 5002f16049cSEmmanuel Vadot return (error); 5012f16049cSEmmanuel Vadot } 5022f16049cSEmmanuel Vadot 5032f16049cSEmmanuel Vadot /* If chip is in AM/PM mode remember that. */ 5042f16049cSEmmanuel Vadot if (data[DS3231_HOUR] & DS3231_HOUR_USE_AMPM) { 5052f16049cSEmmanuel Vadot sc->sc_use_ampm = true; 5062f16049cSEmmanuel Vadot hourmask = DS3231_HOUR_MASK_12HR; 5072f16049cSEmmanuel Vadot } else 5082f16049cSEmmanuel Vadot hourmask = DS3231_HOUR_MASK_24HR; 5092f16049cSEmmanuel Vadot 5102f16049cSEmmanuel Vadot bct.nsec = 0; 5112f16049cSEmmanuel Vadot bct.sec = data[DS3231_SECS] & DS3231_SECS_MASK; 5122f16049cSEmmanuel Vadot bct.min = data[DS3231_MINS] & DS3231_MINS_MASK; 5132f16049cSEmmanuel Vadot bct.hour = data[DS3231_HOUR] & hourmask; 5142f16049cSEmmanuel Vadot bct.day = data[DS3231_DATE] & DS3231_DATE_MASK; 5152f16049cSEmmanuel Vadot bct.mon = data[DS3231_MONTH] & DS3231_MONTH_MASK; 5162f16049cSEmmanuel Vadot bct.year = data[DS3231_YEAR] & DS3231_YEAR_MASK; 5172f16049cSEmmanuel Vadot bct.ispm = data[DS3231_HOUR] & DS3231_HOUR_IS_PM; 5182f16049cSEmmanuel Vadot 5192f16049cSEmmanuel Vadot /* 5202f16049cSEmmanuel Vadot * If the century flag has toggled since we last saw it, there has been 5212f16049cSEmmanuel Vadot * a century rollover. If this is the first time we're seeing it, 5222f16049cSEmmanuel Vadot * remember the state so we can preserve its polarity on writes. 5232f16049cSEmmanuel Vadot */ 5242f16049cSEmmanuel Vadot c = (data[DS3231_MONTH] & DS3231_C_MASK) ? 1 : 0; 5252f16049cSEmmanuel Vadot if (sc->sc_last_c == -1) 5262f16049cSEmmanuel Vadot sc->sc_last_c = c; 5272f16049cSEmmanuel Vadot else if (c != sc->sc_last_c) { 5282f16049cSEmmanuel Vadot sc->sc_year0 += 0x100; 5292f16049cSEmmanuel Vadot sc->sc_last_c = c; 5302f16049cSEmmanuel Vadot } 5312f16049cSEmmanuel Vadot bct.year |= sc->sc_year0; 5322f16049cSEmmanuel Vadot 5332f16049cSEmmanuel Vadot clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_READ, &bct); 5342f16049cSEmmanuel Vadot return (clock_bcd_to_ts(&bct, ts, sc->sc_use_ampm)); 5352f16049cSEmmanuel Vadot } 5362f16049cSEmmanuel Vadot 5372f16049cSEmmanuel Vadot static int 5382f16049cSEmmanuel Vadot ds3231_settime(device_t dev, struct timespec *ts) 5392f16049cSEmmanuel Vadot { 5402f16049cSEmmanuel Vadot int error; 5412f16049cSEmmanuel Vadot struct bcd_clocktime bct; 5422f16049cSEmmanuel Vadot struct ds3231_softc *sc; 5432f16049cSEmmanuel Vadot uint8_t data[7]; 5442f16049cSEmmanuel Vadot uint8_t pmflags; 5452f16049cSEmmanuel Vadot 5462f16049cSEmmanuel Vadot sc = device_get_softc(dev); 5472f16049cSEmmanuel Vadot 5482f16049cSEmmanuel Vadot /* 5492f16049cSEmmanuel Vadot * We request a timespec with no resolution-adjustment. That also 5502f16049cSEmmanuel Vadot * disables utc adjustment, so apply that ourselves. 5512f16049cSEmmanuel Vadot */ 5522f16049cSEmmanuel Vadot ts->tv_sec -= utc_offset(); 5532f16049cSEmmanuel Vadot clock_ts_to_bcd(ts, &bct, sc->sc_use_ampm); 5542f16049cSEmmanuel Vadot clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_WRITE, &bct); 5552f16049cSEmmanuel Vadot 5562f16049cSEmmanuel Vadot /* If the chip is in AM/PM mode, adjust hour and set flags as needed. */ 5572f16049cSEmmanuel Vadot if (sc->sc_use_ampm) { 5582f16049cSEmmanuel Vadot pmflags = DS3231_HOUR_USE_AMPM; 5592f16049cSEmmanuel Vadot if (bct.ispm) 5602f16049cSEmmanuel Vadot pmflags |= DS3231_HOUR_IS_PM; 5612f16049cSEmmanuel Vadot } else 5622f16049cSEmmanuel Vadot pmflags = 0; 5632f16049cSEmmanuel Vadot 5642f16049cSEmmanuel Vadot data[DS3231_SECS] = bct.sec; 5652f16049cSEmmanuel Vadot data[DS3231_MINS] = bct.min; 5662f16049cSEmmanuel Vadot data[DS3231_HOUR] = bct.hour | pmflags; 5672f16049cSEmmanuel Vadot data[DS3231_DATE] = bct.day; 5682f16049cSEmmanuel Vadot data[DS3231_WEEKDAY] = bct.dow + 1; 5692f16049cSEmmanuel Vadot data[DS3231_MONTH] = bct.mon; 5702f16049cSEmmanuel Vadot data[DS3231_YEAR] = bct.year & 0xff; 5712f16049cSEmmanuel Vadot if (sc->sc_last_c) 5722f16049cSEmmanuel Vadot data[DS3231_MONTH] |= DS3231_C_MASK; 5732f16049cSEmmanuel Vadot 5742f16049cSEmmanuel Vadot /* Write the time back to RTC. */ 5752f16049cSEmmanuel Vadot error = iicdev_writeto(dev, DS3231_SECS, data, sizeof(data), 5762f16049cSEmmanuel Vadot IIC_INTRWAIT); 5772f16049cSEmmanuel Vadot if (error != 0) { 5782f16049cSEmmanuel Vadot device_printf(dev, "cannot write to RTC.\n"); 5792f16049cSEmmanuel Vadot return (error); 5802f16049cSEmmanuel Vadot } 5812f16049cSEmmanuel Vadot 5822f16049cSEmmanuel Vadot /* 5832f16049cSEmmanuel Vadot * Unlike most hardware, the osc-was-stopped bit does not clear itself 5842f16049cSEmmanuel Vadot * after setting the time, it has to be manually written to zero. 5852f16049cSEmmanuel Vadot */ 5862f16049cSEmmanuel Vadot if (sc->sc_status & DS3231_STATUS_OSF) { 5872f16049cSEmmanuel Vadot if ((error = ds3231_status_read(sc)) != 0) { 5882f16049cSEmmanuel Vadot device_printf(dev, "cannot read from RTC.\n"); 5892f16049cSEmmanuel Vadot return (error); 5902f16049cSEmmanuel Vadot } 5912f16049cSEmmanuel Vadot sc->sc_status &= ~DS3231_STATUS_OSF; 5922f16049cSEmmanuel Vadot if ((error = ds3231_status_write(sc, 0, 0)) != 0) { 5932f16049cSEmmanuel Vadot device_printf(dev, "cannot write to RTC.\n"); 5942f16049cSEmmanuel Vadot return (error); 5952f16049cSEmmanuel Vadot } 5962f16049cSEmmanuel Vadot } 5972f16049cSEmmanuel Vadot 5982f16049cSEmmanuel Vadot return (error); 5992f16049cSEmmanuel Vadot } 6002f16049cSEmmanuel Vadot 6012f16049cSEmmanuel Vadot static device_method_t ds3231_methods[] = { 6022f16049cSEmmanuel Vadot DEVMETHOD(device_probe, ds3231_probe), 6032f16049cSEmmanuel Vadot DEVMETHOD(device_attach, ds3231_attach), 6042f16049cSEmmanuel Vadot DEVMETHOD(device_detach, ds3231_detach), 6052f16049cSEmmanuel Vadot 6062f16049cSEmmanuel Vadot DEVMETHOD(clock_gettime, ds3231_gettime), 6072f16049cSEmmanuel Vadot DEVMETHOD(clock_settime, ds3231_settime), 6082f16049cSEmmanuel Vadot 6092f16049cSEmmanuel Vadot DEVMETHOD_END 6102f16049cSEmmanuel Vadot }; 6112f16049cSEmmanuel Vadot 6122f16049cSEmmanuel Vadot static driver_t ds3231_driver = { 6132f16049cSEmmanuel Vadot "ds3231", 6142f16049cSEmmanuel Vadot ds3231_methods, 6152f16049cSEmmanuel Vadot sizeof(struct ds3231_softc), 6162f16049cSEmmanuel Vadot }; 6172f16049cSEmmanuel Vadot 6182f16049cSEmmanuel Vadot DRIVER_MODULE(ds3231, iicbus, ds3231_driver, NULL, NULL); 6192f16049cSEmmanuel Vadot MODULE_VERSION(ds3231, 1); 6202f16049cSEmmanuel Vadot MODULE_DEPEND(ds3231, iicbus, 1, 1, 1); 621