12f16049cSEmmanuel Vadot /*- 22f16049cSEmmanuel Vadot * Copyright (c) 2015 Luiz Otavio O Souza <loos@FreeBSD.org> 32f16049cSEmmanuel Vadot * Copyright (c) 2022 Mathew McBride <matt@traverse.com.au> 42f16049cSEmmanuel Vadot * All rights reserved. 52f16049cSEmmanuel Vadot * 62f16049cSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 72f16049cSEmmanuel Vadot * modification, are permitted provided that the following conditions 82f16049cSEmmanuel Vadot * are met: 92f16049cSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 102f16049cSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 112f16049cSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 122f16049cSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 132f16049cSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 142f16049cSEmmanuel Vadot * 152f16049cSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 162f16049cSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172f16049cSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 182f16049cSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 192f16049cSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 202f16049cSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212f16049cSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222f16049cSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232f16049cSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 242f16049cSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 252f16049cSEmmanuel Vadot * SUCH DAMAGE. 262f16049cSEmmanuel Vadot */ 272f16049cSEmmanuel Vadot 282f16049cSEmmanuel Vadot #include <sys/cdefs.h> 292f16049cSEmmanuel Vadot /* 302f16049cSEmmanuel Vadot * Driver for Maxim DS1307 I2C real-time clock/calendar. 312f16049cSEmmanuel Vadot */ 322f16049cSEmmanuel Vadot 332f16049cSEmmanuel Vadot #include "opt_platform.h" 342f16049cSEmmanuel Vadot 352f16049cSEmmanuel Vadot #include <sys/param.h> 362f16049cSEmmanuel Vadot #include <sys/systm.h> 372f16049cSEmmanuel Vadot #include <sys/bus.h> 382f16049cSEmmanuel Vadot #include <sys/clock.h> 392f16049cSEmmanuel Vadot #include <sys/kernel.h> 402f16049cSEmmanuel Vadot #include <sys/module.h> 412f16049cSEmmanuel Vadot #include <sys/sysctl.h> 422f16049cSEmmanuel Vadot 432f16049cSEmmanuel Vadot #include <dev/iicbus/iicbus.h> 442f16049cSEmmanuel Vadot #include <dev/iicbus/iiconf.h> 452f16049cSEmmanuel Vadot #ifdef FDT 462f16049cSEmmanuel Vadot #include <dev/ofw/openfirm.h> 472f16049cSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 482f16049cSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 492f16049cSEmmanuel Vadot #endif 502f16049cSEmmanuel Vadot 512f16049cSEmmanuel Vadot #include <dev/iicbus/rtc/ds1307reg.h> 522f16049cSEmmanuel Vadot 532f16049cSEmmanuel Vadot #include "clock_if.h" 542f16049cSEmmanuel Vadot #include "iicbus_if.h" 552f16049cSEmmanuel Vadot 562f16049cSEmmanuel Vadot enum { 572f16049cSEmmanuel Vadot TYPE_DS1307, 582f16049cSEmmanuel Vadot TYPE_MAXIM1307, 59b724c829SJosef 'Jeff' Sipek TYPE_MICROCHIP_MCP7941X, 602f16049cSEmmanuel Vadot TYPE_EPSON_RX8035, 612f16049cSEmmanuel Vadot TYPE_COUNT 622f16049cSEmmanuel Vadot }; 632f16049cSEmmanuel Vadot 642f16049cSEmmanuel Vadot struct ds1307_softc { 652f16049cSEmmanuel Vadot device_t sc_dev; 662f16049cSEmmanuel Vadot struct intr_config_hook enum_hook; 672f16049cSEmmanuel Vadot uint32_t chiptype; 682f16049cSEmmanuel Vadot uint8_t sc_ctrl; 692f16049cSEmmanuel Vadot bool sc_use_ampm; 702f16049cSEmmanuel Vadot }; 712f16049cSEmmanuel Vadot 722f16049cSEmmanuel Vadot static void ds1307_start(void *); 732f16049cSEmmanuel Vadot 742f16049cSEmmanuel Vadot #ifdef FDT 752f16049cSEmmanuel Vadot static const struct ofw_compat_data ds1307_compat_data[] = { 762f16049cSEmmanuel Vadot {"dallas,ds1307", TYPE_DS1307}, 772f16049cSEmmanuel Vadot {"maxim,ds1307", TYPE_MAXIM1307}, 78b724c829SJosef 'Jeff' Sipek {"microchip,mcp7941x", TYPE_MICROCHIP_MCP7941X}, 792f16049cSEmmanuel Vadot {"epson,rx8035", TYPE_EPSON_RX8035}, 802f16049cSEmmanuel Vadot { NULL, 0 } 812f16049cSEmmanuel Vadot }; 822f16049cSEmmanuel Vadot #endif 832f16049cSEmmanuel Vadot 842f16049cSEmmanuel Vadot static int 852f16049cSEmmanuel Vadot ds1307_read1(device_t dev, uint8_t reg, uint8_t *data) 862f16049cSEmmanuel Vadot { 872f16049cSEmmanuel Vadot 882f16049cSEmmanuel Vadot return (iicdev_readfrom(dev, reg, data, 1, IIC_INTRWAIT)); 892f16049cSEmmanuel Vadot } 902f16049cSEmmanuel Vadot 912f16049cSEmmanuel Vadot static int 922f16049cSEmmanuel Vadot ds1307_write1(device_t dev, uint8_t reg, uint8_t data) 932f16049cSEmmanuel Vadot { 942f16049cSEmmanuel Vadot 952f16049cSEmmanuel Vadot return (iicdev_writeto(dev, reg, &data, 1, IIC_INTRWAIT)); 962f16049cSEmmanuel Vadot } 972f16049cSEmmanuel Vadot 982f16049cSEmmanuel Vadot static int 992f16049cSEmmanuel Vadot ds1307_ctrl_read(struct ds1307_softc *sc) 1002f16049cSEmmanuel Vadot { 1012f16049cSEmmanuel Vadot int error; 1022f16049cSEmmanuel Vadot 1032f16049cSEmmanuel Vadot sc->sc_ctrl = 0; 1042f16049cSEmmanuel Vadot error = ds1307_read1(sc->sc_dev, DS1307_CONTROL, &sc->sc_ctrl); 1052f16049cSEmmanuel Vadot if (error) { 1062f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "%s: cannot read from RTC: %d\n", 1072f16049cSEmmanuel Vadot __func__, error); 1082f16049cSEmmanuel Vadot return (error); 1092f16049cSEmmanuel Vadot } 1102f16049cSEmmanuel Vadot 1112f16049cSEmmanuel Vadot return (0); 1122f16049cSEmmanuel Vadot } 1132f16049cSEmmanuel Vadot 1142f16049cSEmmanuel Vadot static int 1152f16049cSEmmanuel Vadot ds1307_ctrl_write(struct ds1307_softc *sc) 1162f16049cSEmmanuel Vadot { 1172f16049cSEmmanuel Vadot int error; 1182f16049cSEmmanuel Vadot uint8_t ctrl; 1192f16049cSEmmanuel Vadot 1202f16049cSEmmanuel Vadot ctrl = sc->sc_ctrl & DS1307_CTRL_MASK; 1212f16049cSEmmanuel Vadot error = ds1307_write1(sc->sc_dev, DS1307_CONTROL, ctrl); 1222f16049cSEmmanuel Vadot if (error != 0) 1232f16049cSEmmanuel Vadot device_printf(sc->sc_dev, "%s: cannot write to RTC: %d\n", 1242f16049cSEmmanuel Vadot __func__, error); 1252f16049cSEmmanuel Vadot 1262f16049cSEmmanuel Vadot return (error); 1272f16049cSEmmanuel Vadot } 1282f16049cSEmmanuel Vadot 1292f16049cSEmmanuel Vadot static int 1302f16049cSEmmanuel Vadot ds1307_sqwe_sysctl(SYSCTL_HANDLER_ARGS) 1312f16049cSEmmanuel Vadot { 1322f16049cSEmmanuel Vadot int sqwe, error, newv, sqwe_bit; 1332f16049cSEmmanuel Vadot struct ds1307_softc *sc; 1342f16049cSEmmanuel Vadot 1352f16049cSEmmanuel Vadot sc = (struct ds1307_softc *)arg1; 1362f16049cSEmmanuel Vadot error = ds1307_ctrl_read(sc); 1372f16049cSEmmanuel Vadot if (error != 0) 1382f16049cSEmmanuel Vadot return (error); 139b724c829SJosef 'Jeff' Sipek if (sc->chiptype == TYPE_MICROCHIP_MCP7941X) 1402f16049cSEmmanuel Vadot sqwe_bit = MCP7941X_CTRL_SQWE; 1412f16049cSEmmanuel Vadot else 1422f16049cSEmmanuel Vadot sqwe_bit = DS1307_CTRL_SQWE; 1432f16049cSEmmanuel Vadot sqwe = newv = (sc->sc_ctrl & sqwe_bit) ? 1 : 0; 1442f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &newv, 0, req); 1452f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 1462f16049cSEmmanuel Vadot return (error); 1472f16049cSEmmanuel Vadot if (sqwe != newv) { 1482f16049cSEmmanuel Vadot sc->sc_ctrl &= ~sqwe_bit; 1492f16049cSEmmanuel Vadot if (newv) 1502f16049cSEmmanuel Vadot sc->sc_ctrl |= sqwe_bit; 1512f16049cSEmmanuel Vadot error = ds1307_ctrl_write(sc); 1522f16049cSEmmanuel Vadot if (error != 0) 1532f16049cSEmmanuel Vadot return (error); 1542f16049cSEmmanuel Vadot } 1552f16049cSEmmanuel Vadot 1562f16049cSEmmanuel Vadot return (error); 1572f16049cSEmmanuel Vadot } 1582f16049cSEmmanuel Vadot 1592f16049cSEmmanuel Vadot static int 1602f16049cSEmmanuel Vadot ds1307_sqw_freq_sysctl(SYSCTL_HANDLER_ARGS) 1612f16049cSEmmanuel Vadot { 1622f16049cSEmmanuel Vadot int ds1307_sqw_freq[] = { 1, 4096, 8192, 32768 }; 1632f16049cSEmmanuel Vadot int error, freq, i, newf, tmp; 1642f16049cSEmmanuel Vadot struct ds1307_softc *sc; 1652f16049cSEmmanuel Vadot 1662f16049cSEmmanuel Vadot sc = (struct ds1307_softc *)arg1; 1672f16049cSEmmanuel Vadot error = ds1307_ctrl_read(sc); 1682f16049cSEmmanuel Vadot if (error != 0) 1692f16049cSEmmanuel Vadot return (error); 1702f16049cSEmmanuel Vadot tmp = (sc->sc_ctrl & DS1307_CTRL_RS_MASK); 1712f16049cSEmmanuel Vadot if (tmp >= nitems(ds1307_sqw_freq)) 1722f16049cSEmmanuel Vadot tmp = nitems(ds1307_sqw_freq) - 1; 1732f16049cSEmmanuel Vadot freq = ds1307_sqw_freq[tmp]; 1742f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &freq, 0, req); 1752f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 1762f16049cSEmmanuel Vadot return (error); 1772f16049cSEmmanuel Vadot if (freq != ds1307_sqw_freq[tmp]) { 1782f16049cSEmmanuel Vadot newf = 0; 1792f16049cSEmmanuel Vadot for (i = 0; i < nitems(ds1307_sqw_freq); i++) 1802f16049cSEmmanuel Vadot if (freq >= ds1307_sqw_freq[i]) 1812f16049cSEmmanuel Vadot newf = i; 1822f16049cSEmmanuel Vadot sc->sc_ctrl &= ~DS1307_CTRL_RS_MASK; 1832f16049cSEmmanuel Vadot sc->sc_ctrl |= newf; 1842f16049cSEmmanuel Vadot error = ds1307_ctrl_write(sc); 1852f16049cSEmmanuel Vadot if (error != 0) 1862f16049cSEmmanuel Vadot return (error); 1872f16049cSEmmanuel Vadot } 1882f16049cSEmmanuel Vadot 1892f16049cSEmmanuel Vadot return (error); 1902f16049cSEmmanuel Vadot } 1912f16049cSEmmanuel Vadot 1922f16049cSEmmanuel Vadot static int 1932f16049cSEmmanuel Vadot ds1307_sqw_out_sysctl(SYSCTL_HANDLER_ARGS) 1942f16049cSEmmanuel Vadot { 1952f16049cSEmmanuel Vadot int sqwe, error, newv; 1962f16049cSEmmanuel Vadot struct ds1307_softc *sc; 1972f16049cSEmmanuel Vadot 1982f16049cSEmmanuel Vadot sc = (struct ds1307_softc *)arg1; 1992f16049cSEmmanuel Vadot error = ds1307_ctrl_read(sc); 2002f16049cSEmmanuel Vadot if (error != 0) 2012f16049cSEmmanuel Vadot return (error); 2022f16049cSEmmanuel Vadot sqwe = newv = (sc->sc_ctrl & DS1307_CTRL_OUT) ? 1 : 0; 2032f16049cSEmmanuel Vadot error = sysctl_handle_int(oidp, &newv, 0, req); 2042f16049cSEmmanuel Vadot if (error != 0 || req->newptr == NULL) 2052f16049cSEmmanuel Vadot return (error); 2062f16049cSEmmanuel Vadot if (sqwe != newv) { 2072f16049cSEmmanuel Vadot sc->sc_ctrl &= ~DS1307_CTRL_OUT; 2082f16049cSEmmanuel Vadot if (newv) 2092f16049cSEmmanuel Vadot sc->sc_ctrl |= DS1307_CTRL_OUT; 2102f16049cSEmmanuel Vadot error = ds1307_ctrl_write(sc); 2112f16049cSEmmanuel Vadot if (error != 0) 2122f16049cSEmmanuel Vadot return (error); 2132f16049cSEmmanuel Vadot } 2142f16049cSEmmanuel Vadot 2152f16049cSEmmanuel Vadot return (error); 2162f16049cSEmmanuel Vadot } 2172f16049cSEmmanuel Vadot 2182f16049cSEmmanuel Vadot static int 2192f16049cSEmmanuel Vadot ds1307_probe(device_t dev) 2202f16049cSEmmanuel Vadot { 2212f16049cSEmmanuel Vadot #ifdef FDT 2222f16049cSEmmanuel Vadot const struct ofw_compat_data *compat; 2232f16049cSEmmanuel Vadot 2242f16049cSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 2252f16049cSEmmanuel Vadot return (ENXIO); 2262f16049cSEmmanuel Vadot 2272f16049cSEmmanuel Vadot compat = ofw_bus_search_compatible(dev, ds1307_compat_data); 22834694f3dSAndriy Gapon if (compat->ocd_str != NULL) { 2292f16049cSEmmanuel Vadot switch(compat->ocd_data) { 2302f16049cSEmmanuel Vadot case TYPE_DS1307: 2312f16049cSEmmanuel Vadot device_set_desc(dev, "Dallas DS1307"); 2322f16049cSEmmanuel Vadot break; 2332f16049cSEmmanuel Vadot case TYPE_MAXIM1307: 2342f16049cSEmmanuel Vadot device_set_desc(dev, "Maxim DS1307"); 2352f16049cSEmmanuel Vadot break; 236b724c829SJosef 'Jeff' Sipek case TYPE_MICROCHIP_MCP7941X: 237b724c829SJosef 'Jeff' Sipek device_set_desc(dev, "Microchip MCP7941X"); 2382f16049cSEmmanuel Vadot break; 2392f16049cSEmmanuel Vadot case TYPE_EPSON_RX8035: 2402f16049cSEmmanuel Vadot device_set_desc(dev, "Epson RX-8035"); 2412f16049cSEmmanuel Vadot break; 2422f16049cSEmmanuel Vadot default: 2432f16049cSEmmanuel Vadot device_set_desc(dev, "Unknown DS1307-like device"); 2442f16049cSEmmanuel Vadot break; 2452f16049cSEmmanuel Vadot } 2462f16049cSEmmanuel Vadot return (BUS_PROBE_DEFAULT); 24734694f3dSAndriy Gapon } 2482f16049cSEmmanuel Vadot #endif 2492f16049cSEmmanuel Vadot 25034694f3dSAndriy Gapon device_set_desc(dev, "Maxim DS1307"); 2512f16049cSEmmanuel Vadot return (BUS_PROBE_NOWILDCARD); 2522f16049cSEmmanuel Vadot } 2532f16049cSEmmanuel Vadot 2542f16049cSEmmanuel Vadot static int 2552f16049cSEmmanuel Vadot ds1307_attach(device_t dev) 2562f16049cSEmmanuel Vadot { 2572f16049cSEmmanuel Vadot #ifdef FDT 2582f16049cSEmmanuel Vadot const struct ofw_compat_data *compat; 2592f16049cSEmmanuel Vadot #endif 2602f16049cSEmmanuel Vadot struct ds1307_softc *sc; 2612f16049cSEmmanuel Vadot 2622f16049cSEmmanuel Vadot sc = device_get_softc(dev); 2632f16049cSEmmanuel Vadot sc->sc_dev = dev; 2642f16049cSEmmanuel Vadot sc->enum_hook.ich_func = ds1307_start; 2652f16049cSEmmanuel Vadot sc->enum_hook.ich_arg = dev; 2662f16049cSEmmanuel Vadot #ifdef FDT 2672f16049cSEmmanuel Vadot compat = ofw_bus_search_compatible(dev, ds1307_compat_data); 2682f16049cSEmmanuel Vadot sc->chiptype = compat->ocd_data; 2692f16049cSEmmanuel Vadot /* Unify the chiptypes to DS1307 where possible. */ 2702f16049cSEmmanuel Vadot if (sc->chiptype == TYPE_MAXIM1307) 2712f16049cSEmmanuel Vadot sc->chiptype = TYPE_DS1307; 2722f16049cSEmmanuel Vadot #else 2732f16049cSEmmanuel Vadot sc->chiptype = TYPE_DS1307; 2742f16049cSEmmanuel Vadot #endif 2752f16049cSEmmanuel Vadot 2762f16049cSEmmanuel Vadot /* 2772f16049cSEmmanuel Vadot * We have to wait until interrupts are enabled. Usually I2C read 2782f16049cSEmmanuel Vadot * and write only works when the interrupts are available. 2792f16049cSEmmanuel Vadot */ 2802f16049cSEmmanuel Vadot if (config_intrhook_establish(&sc->enum_hook) != 0) 2812f16049cSEmmanuel Vadot return (ENOMEM); 2822f16049cSEmmanuel Vadot 2832f16049cSEmmanuel Vadot return (0); 2842f16049cSEmmanuel Vadot } 2852f16049cSEmmanuel Vadot 2862f16049cSEmmanuel Vadot static int 2872f16049cSEmmanuel Vadot ds1307_detach(device_t dev) 2882f16049cSEmmanuel Vadot { 2892f16049cSEmmanuel Vadot 2902f16049cSEmmanuel Vadot clock_unregister(dev); 2912f16049cSEmmanuel Vadot return (0); 2922f16049cSEmmanuel Vadot } 2932f16049cSEmmanuel Vadot 2942f16049cSEmmanuel Vadot static bool 2952f16049cSEmmanuel Vadot is_epson_time_valid(struct ds1307_softc *sc) 2962f16049cSEmmanuel Vadot { 2972f16049cSEmmanuel Vadot device_t dev; 2982f16049cSEmmanuel Vadot int error; 2992f16049cSEmmanuel Vadot uint8_t ctrl2; 3002f16049cSEmmanuel Vadot 3012f16049cSEmmanuel Vadot dev = sc->sc_dev; 3022f16049cSEmmanuel Vadot 3032f16049cSEmmanuel Vadot /* 3042f16049cSEmmanuel Vadot * The RX-8035 single register read is non-standard 3052f16049cSEmmanuel Vadot * Refer to section 8.9.5 of the RX-8035 application manual: 3062f16049cSEmmanuel Vadot * "I2C bus basic transfer format", under "Standard Read Method". 3072f16049cSEmmanuel Vadot * Basically, register to read goes into the top 4 bits. 3082f16049cSEmmanuel Vadot */ 3092f16049cSEmmanuel Vadot error = ds1307_read1(dev, (RX8035_CTRL_2 << 4), &ctrl2); 3102f16049cSEmmanuel Vadot if (error) { 3112f16049cSEmmanuel Vadot device_printf(dev, "%s cannot read Control 2 register: %d\n", 3122f16049cSEmmanuel Vadot __func__, error); 3132f16049cSEmmanuel Vadot return (false); 3142f16049cSEmmanuel Vadot } 3152f16049cSEmmanuel Vadot 3162f16049cSEmmanuel Vadot if (ctrl2 & RX8035_CTRL_2_XSTP) { 3172f16049cSEmmanuel Vadot device_printf(dev, "Oscillation stop detected (ctrl2=%#02x)\n", 3182f16049cSEmmanuel Vadot ctrl2); 3192f16049cSEmmanuel Vadot return (false); 3202f16049cSEmmanuel Vadot } 3212f16049cSEmmanuel Vadot 3222f16049cSEmmanuel Vadot /* 3232f16049cSEmmanuel Vadot * Power on reset (PON) generally implies oscillation stop, 3242f16049cSEmmanuel Vadot * but catch it as well to be sure. 3252f16049cSEmmanuel Vadot */ 3262f16049cSEmmanuel Vadot if (ctrl2 & RX8035_CTRL_2_PON) { 3272f16049cSEmmanuel Vadot device_printf(dev, "Power-on reset detected (ctrl2=%#02x)\n", 3282f16049cSEmmanuel Vadot ctrl2); 3292f16049cSEmmanuel Vadot return (false); 3302f16049cSEmmanuel Vadot } 3312f16049cSEmmanuel Vadot 3322f16049cSEmmanuel Vadot return (true); 3332f16049cSEmmanuel Vadot } 3342f16049cSEmmanuel Vadot 3352f16049cSEmmanuel Vadot static int 3362f16049cSEmmanuel Vadot mark_epson_time_valid(struct ds1307_softc *sc) 3372f16049cSEmmanuel Vadot { 3382f16049cSEmmanuel Vadot device_t dev; 3392f16049cSEmmanuel Vadot int error; 3402f16049cSEmmanuel Vadot uint8_t ctrl2; 3412f16049cSEmmanuel Vadot uint8_t control_mask; 3422f16049cSEmmanuel Vadot 3432f16049cSEmmanuel Vadot dev = sc->sc_dev; 3442f16049cSEmmanuel Vadot 3452f16049cSEmmanuel Vadot error = ds1307_read1(dev, (RX8035_CTRL_2 << 4), &ctrl2); 3462f16049cSEmmanuel Vadot if (error) { 3472f16049cSEmmanuel Vadot device_printf(dev, "%s cannot read Control 2 register: %d\n", 3482f16049cSEmmanuel Vadot __func__, error); 349*645a2284SDmitry Salychev return (error); 3502f16049cSEmmanuel Vadot } 3512f16049cSEmmanuel Vadot 3522f16049cSEmmanuel Vadot control_mask = (RX8035_CTRL_2_PON | RX8035_CTRL_2_XSTP | RX8035_CTRL_2_VDET); 3532f16049cSEmmanuel Vadot ctrl2 = ctrl2 & ~(control_mask); 3542f16049cSEmmanuel Vadot 3552f16049cSEmmanuel Vadot error = ds1307_write1(dev, (RX8035_CTRL_2 << 4), ctrl2); 3562f16049cSEmmanuel Vadot if (error) { 3572f16049cSEmmanuel Vadot device_printf(dev, "%s cannot write to Control 2 register: %d\n", 3582f16049cSEmmanuel Vadot __func__, error); 359*645a2284SDmitry Salychev return (error); 3602f16049cSEmmanuel Vadot } 361*645a2284SDmitry Salychev return (0); 3622f16049cSEmmanuel Vadot } 3632f16049cSEmmanuel Vadot 3642f16049cSEmmanuel Vadot static bool is_dev_time_valid(struct ds1307_softc *sc) 3652f16049cSEmmanuel Vadot { 3662f16049cSEmmanuel Vadot device_t dev; 3672f16049cSEmmanuel Vadot int error; 3682f16049cSEmmanuel Vadot uint8_t osc_en; 3692f16049cSEmmanuel Vadot uint8_t secs; 3702f16049cSEmmanuel Vadot 3712f16049cSEmmanuel Vadot /* Epson RTCs have different control/status registers. */ 3722f16049cSEmmanuel Vadot if (sc->chiptype == TYPE_EPSON_RX8035) 3732f16049cSEmmanuel Vadot return (is_epson_time_valid(sc)); 3742f16049cSEmmanuel Vadot 3752f16049cSEmmanuel Vadot dev = sc->sc_dev; 3762f16049cSEmmanuel Vadot /* Check if the oscillator is disabled. */ 3772f16049cSEmmanuel Vadot error = ds1307_read1(dev, DS1307_SECS, &secs); 3782f16049cSEmmanuel Vadot if (error) { 3792f16049cSEmmanuel Vadot device_printf(dev, "%s: cannot read from RTC: %d\n", 3802f16049cSEmmanuel Vadot __func__, error); 3812f16049cSEmmanuel Vadot return (false); 3822f16049cSEmmanuel Vadot } 3832f16049cSEmmanuel Vadot 3842f16049cSEmmanuel Vadot switch (sc->chiptype) { 385b724c829SJosef 'Jeff' Sipek case TYPE_MICROCHIP_MCP7941X: 3862f16049cSEmmanuel Vadot osc_en = 0x80; 3872f16049cSEmmanuel Vadot break; 3882f16049cSEmmanuel Vadot default: 3892f16049cSEmmanuel Vadot osc_en = 0x00; 3902f16049cSEmmanuel Vadot break; 3912f16049cSEmmanuel Vadot } 3922f16049cSEmmanuel Vadot if (((secs & DS1307_SECS_CH) ^ osc_en) != 0) 3932f16049cSEmmanuel Vadot return (false); 3942f16049cSEmmanuel Vadot 3952f16049cSEmmanuel Vadot return (true); 3962f16049cSEmmanuel Vadot } 3972f16049cSEmmanuel Vadot 3982f16049cSEmmanuel Vadot static void 3992f16049cSEmmanuel Vadot ds1307_start(void *xdev) 4002f16049cSEmmanuel Vadot { 4012f16049cSEmmanuel Vadot device_t dev; 4022f16049cSEmmanuel Vadot struct ds1307_softc *sc; 4032f16049cSEmmanuel Vadot struct sysctl_ctx_list *ctx; 4042f16049cSEmmanuel Vadot struct sysctl_oid *tree_node; 4052f16049cSEmmanuel Vadot struct sysctl_oid_list *tree; 4062f16049cSEmmanuel Vadot 4072f16049cSEmmanuel Vadot dev = (device_t)xdev; 4082f16049cSEmmanuel Vadot sc = device_get_softc(dev); 4092f16049cSEmmanuel Vadot 4102f16049cSEmmanuel Vadot config_intrhook_disestablish(&sc->enum_hook); 4112f16049cSEmmanuel Vadot 4122f16049cSEmmanuel Vadot if (!is_dev_time_valid(sc)) 4132f16049cSEmmanuel Vadot device_printf(dev, 4142f16049cSEmmanuel Vadot "WARNING: RTC clock stopped, check the battery.\n"); 4152f16049cSEmmanuel Vadot 4162f16049cSEmmanuel Vadot /* 4172f16049cSEmmanuel Vadot * Configuration parameters: 4182f16049cSEmmanuel Vadot * square wave output cannot be changed or inhibited on the RX-8035, 4192f16049cSEmmanuel Vadot * so don't present the sysctls there. 4202f16049cSEmmanuel Vadot */ 4212f16049cSEmmanuel Vadot if (sc->chiptype == TYPE_EPSON_RX8035) 4222f16049cSEmmanuel Vadot goto skip_sysctl; 4232f16049cSEmmanuel Vadot 4242f16049cSEmmanuel Vadot ctx = device_get_sysctl_ctx(dev); 4252f16049cSEmmanuel Vadot tree_node = device_get_sysctl_tree(dev); 4262f16049cSEmmanuel Vadot tree = SYSCTL_CHILDREN(tree_node); 4272f16049cSEmmanuel Vadot 4282f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqwe", 4292f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4302f16049cSEmmanuel Vadot ds1307_sqwe_sysctl, "IU", "DS1307 square-wave enable"); 4312f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_freq", 4322f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4332f16049cSEmmanuel Vadot ds1307_sqw_freq_sysctl, "IU", 4342f16049cSEmmanuel Vadot "DS1307 square-wave output frequency"); 4352f16049cSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_out", 4362f16049cSEmmanuel Vadot CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 4372f16049cSEmmanuel Vadot ds1307_sqw_out_sysctl, "IU", "DS1307 square-wave output state"); 4382f16049cSEmmanuel Vadot skip_sysctl: 4392f16049cSEmmanuel Vadot 4402f16049cSEmmanuel Vadot /* 4412f16049cSEmmanuel Vadot * Register as a clock with 1 second resolution. Schedule the 4422f16049cSEmmanuel Vadot * clock_settime() method to be called just after top-of-second; 4432f16049cSEmmanuel Vadot * resetting the time resets top-of-second in the hardware. 4442f16049cSEmmanuel Vadot */ 4452f16049cSEmmanuel Vadot clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_ADJ); 4462f16049cSEmmanuel Vadot clock_schedule(dev, 1); 4472f16049cSEmmanuel Vadot } 4482f16049cSEmmanuel Vadot 4492f16049cSEmmanuel Vadot static int 4502f16049cSEmmanuel Vadot ds1307_gettime(device_t dev, struct timespec *ts) 4512f16049cSEmmanuel Vadot { 4522f16049cSEmmanuel Vadot struct bcd_clocktime bct; 4532f16049cSEmmanuel Vadot struct ds1307_softc *sc; 4542f16049cSEmmanuel Vadot int error; 4552f16049cSEmmanuel Vadot uint8_t data[7], hourmask, ampm_mode; 4562f16049cSEmmanuel Vadot 4572f16049cSEmmanuel Vadot sc = device_get_softc(dev); 4582f16049cSEmmanuel Vadot error = iicdev_readfrom(sc->sc_dev, DS1307_SECS, data, sizeof(data), 4592f16049cSEmmanuel Vadot IIC_INTRWAIT); 4602f16049cSEmmanuel Vadot if (error != 0) { 4612f16049cSEmmanuel Vadot device_printf(dev, "%s: cannot read from RTC: %d\n", 4622f16049cSEmmanuel Vadot __func__, error); 4632f16049cSEmmanuel Vadot return (error); 4642f16049cSEmmanuel Vadot } 4652f16049cSEmmanuel Vadot 4662f16049cSEmmanuel Vadot if (!is_dev_time_valid(sc)) { 4672f16049cSEmmanuel Vadot device_printf(dev, "Device time not valid.\n"); 4682f16049cSEmmanuel Vadot return (EINVAL); 4692f16049cSEmmanuel Vadot } 4702f16049cSEmmanuel Vadot 4712f16049cSEmmanuel Vadot /* 4722f16049cSEmmanuel Vadot * If the chip is in AM/PM mode remember that. 4732f16049cSEmmanuel Vadot * The EPSON uses a 1 to signify 24 hour mode, while the DS uses a 0, 474fa3b3206SGordon Bergling * in slightly different positions. 4752f16049cSEmmanuel Vadot */ 4762f16049cSEmmanuel Vadot if (sc->chiptype == TYPE_EPSON_RX8035) 4772f16049cSEmmanuel Vadot ampm_mode = !(data[DS1307_HOUR] & RX8035_HOUR_USE_24); 4782f16049cSEmmanuel Vadot else 4792f16049cSEmmanuel Vadot ampm_mode = data[DS1307_HOUR] & DS1307_HOUR_USE_AMPM; 4802f16049cSEmmanuel Vadot 4812f16049cSEmmanuel Vadot if (ampm_mode) { 4822f16049cSEmmanuel Vadot sc->sc_use_ampm = true; 4832f16049cSEmmanuel Vadot hourmask = DS1307_HOUR_MASK_12HR; 4842f16049cSEmmanuel Vadot } else 4852f16049cSEmmanuel Vadot hourmask = DS1307_HOUR_MASK_24HR; 4862f16049cSEmmanuel Vadot 4872f16049cSEmmanuel Vadot bct.nsec = 0; 4882f16049cSEmmanuel Vadot bct.ispm = (data[DS1307_HOUR] & DS1307_HOUR_IS_PM) != 0; 4892f16049cSEmmanuel Vadot bct.sec = data[DS1307_SECS] & DS1307_SECS_MASK; 4902f16049cSEmmanuel Vadot bct.min = data[DS1307_MINS] & DS1307_MINS_MASK; 4912f16049cSEmmanuel Vadot bct.hour = data[DS1307_HOUR] & hourmask; 4922f16049cSEmmanuel Vadot bct.day = data[DS1307_DATE] & DS1307_DATE_MASK; 4932f16049cSEmmanuel Vadot bct.mon = data[DS1307_MONTH] & DS1307_MONTH_MASK; 4942f16049cSEmmanuel Vadot bct.year = data[DS1307_YEAR] & DS1307_YEAR_MASK; 4952f16049cSEmmanuel Vadot 4962f16049cSEmmanuel Vadot clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_READ, &bct); 4972f16049cSEmmanuel Vadot return (clock_bcd_to_ts(&bct, ts, sc->sc_use_ampm)); 4982f16049cSEmmanuel Vadot } 4992f16049cSEmmanuel Vadot 5002f16049cSEmmanuel Vadot static int 5012f16049cSEmmanuel Vadot ds1307_settime(device_t dev, struct timespec *ts) 5022f16049cSEmmanuel Vadot { 5032f16049cSEmmanuel Vadot struct bcd_clocktime bct; 5042f16049cSEmmanuel Vadot struct ds1307_softc *sc; 5052f16049cSEmmanuel Vadot int error, year; 5062f16049cSEmmanuel Vadot uint8_t data[7]; 5072f16049cSEmmanuel Vadot uint8_t pmflags; 5082f16049cSEmmanuel Vadot 5092f16049cSEmmanuel Vadot sc = device_get_softc(dev); 5102f16049cSEmmanuel Vadot 5112f16049cSEmmanuel Vadot /* 5122f16049cSEmmanuel Vadot * We request a timespec with no resolution-adjustment. That also 5132f16049cSEmmanuel Vadot * disables utc adjustment, so apply that ourselves. 5142f16049cSEmmanuel Vadot */ 5152f16049cSEmmanuel Vadot ts->tv_sec -= utc_offset(); 5162f16049cSEmmanuel Vadot clock_ts_to_bcd(ts, &bct, sc->sc_use_ampm); 5172f16049cSEmmanuel Vadot clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_WRITE, &bct); 5182f16049cSEmmanuel Vadot 5192f16049cSEmmanuel Vadot /* 5202f16049cSEmmanuel Vadot * If the chip is in AM/PM mode, adjust hour and set flags as needed. 5212f16049cSEmmanuel Vadot * The AM/PM bit polarity and position is different on the EPSON. 5222f16049cSEmmanuel Vadot */ 5232f16049cSEmmanuel Vadot if (sc->sc_use_ampm) { 5242f16049cSEmmanuel Vadot pmflags = (sc->chiptype != TYPE_EPSON_RX8035) ? 5252f16049cSEmmanuel Vadot DS1307_HOUR_USE_AMPM : 0; 5262f16049cSEmmanuel Vadot if (bct.ispm) 5272f16049cSEmmanuel Vadot pmflags |= DS1307_HOUR_IS_PM; 5282f16049cSEmmanuel Vadot 5292f16049cSEmmanuel Vadot } else if (sc->chiptype == TYPE_EPSON_RX8035) 5302f16049cSEmmanuel Vadot pmflags = RX8035_HOUR_USE_24; 5312f16049cSEmmanuel Vadot else 5322f16049cSEmmanuel Vadot pmflags = 0; 5332f16049cSEmmanuel Vadot 5342f16049cSEmmanuel Vadot data[DS1307_SECS] = bct.sec; 5352f16049cSEmmanuel Vadot data[DS1307_MINS] = bct.min; 5362f16049cSEmmanuel Vadot data[DS1307_HOUR] = bct.hour | pmflags; 5372f16049cSEmmanuel Vadot data[DS1307_DATE] = bct.day; 5382f16049cSEmmanuel Vadot data[DS1307_WEEKDAY] = bct.dow; 5392f16049cSEmmanuel Vadot data[DS1307_MONTH] = bct.mon; 5402f16049cSEmmanuel Vadot data[DS1307_YEAR] = bct.year & 0xff; 541b724c829SJosef 'Jeff' Sipek if (sc->chiptype == TYPE_MICROCHIP_MCP7941X) { 5422f16049cSEmmanuel Vadot data[DS1307_SECS] |= MCP7941X_SECS_ST; 5432f16049cSEmmanuel Vadot data[DS1307_WEEKDAY] |= MCP7941X_WEEKDAY_VBATEN; 5442f16049cSEmmanuel Vadot year = bcd2bin(bct.year >> 8) * 100 + bcd2bin(bct.year & 0xff); 5452f16049cSEmmanuel Vadot if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) 5462f16049cSEmmanuel Vadot data[DS1307_MONTH] |= MCP7941X_MONTH_LPYR; 5472f16049cSEmmanuel Vadot } 5482f16049cSEmmanuel Vadot 5492f16049cSEmmanuel Vadot /* Write the time back to RTC. */ 5502f16049cSEmmanuel Vadot error = iicdev_writeto(sc->sc_dev, DS1307_SECS, data, sizeof(data), 5512f16049cSEmmanuel Vadot IIC_INTRWAIT); 5522f16049cSEmmanuel Vadot if (error != 0) 5532f16049cSEmmanuel Vadot device_printf(dev, "%s: cannot write to RTC: %d\n", 5542f16049cSEmmanuel Vadot __func__, error); 5552f16049cSEmmanuel Vadot 5562f16049cSEmmanuel Vadot if (sc->chiptype == TYPE_EPSON_RX8035) 5572f16049cSEmmanuel Vadot error = mark_epson_time_valid(sc); 5582f16049cSEmmanuel Vadot 5592f16049cSEmmanuel Vadot return (error); 5602f16049cSEmmanuel Vadot } 5612f16049cSEmmanuel Vadot 5622f16049cSEmmanuel Vadot static device_method_t ds1307_methods[] = { 5632f16049cSEmmanuel Vadot DEVMETHOD(device_probe, ds1307_probe), 5642f16049cSEmmanuel Vadot DEVMETHOD(device_attach, ds1307_attach), 5652f16049cSEmmanuel Vadot DEVMETHOD(device_detach, ds1307_detach), 5662f16049cSEmmanuel Vadot 5672f16049cSEmmanuel Vadot DEVMETHOD(clock_gettime, ds1307_gettime), 5682f16049cSEmmanuel Vadot DEVMETHOD(clock_settime, ds1307_settime), 5692f16049cSEmmanuel Vadot 5702f16049cSEmmanuel Vadot DEVMETHOD_END 5712f16049cSEmmanuel Vadot }; 5722f16049cSEmmanuel Vadot 5732f16049cSEmmanuel Vadot static driver_t ds1307_driver = { 5742f16049cSEmmanuel Vadot "ds1307", 5752f16049cSEmmanuel Vadot ds1307_methods, 5762f16049cSEmmanuel Vadot sizeof(struct ds1307_softc), 5772f16049cSEmmanuel Vadot }; 5782f16049cSEmmanuel Vadot 5792f16049cSEmmanuel Vadot DRIVER_MODULE(ds1307, iicbus, ds1307_driver, NULL, NULL); 5802f16049cSEmmanuel Vadot MODULE_VERSION(ds1307, 1); 5812f16049cSEmmanuel Vadot MODULE_DEPEND(ds1307, iicbus, 1, 1, 1); 5822f16049cSEmmanuel Vadot IICBUS_FDT_PNP_INFO(ds1307_compat_data); 583