1279399Sloos/*- 2279399Sloos * Copyright (c) 2014-2015 Luiz Otavio O Souza <loos@FreeBSD.org> 3279399Sloos * All rights reserved. 4279399Sloos * 5279399Sloos * Redistribution and use in source and binary forms, with or without 6279399Sloos * modification, are permitted provided that the following conditions 7279399Sloos * are met: 8279399Sloos * 1. Redistributions of source code must retain the above copyright 9279399Sloos * notice, this list of conditions and the following disclaimer. 10279399Sloos * 2. Redistributions in binary form must reproduce the above copyright 11279399Sloos * notice, this list of conditions and the following disclaimer in the 12279399Sloos * documentation and/or other materials provided with the distribution. 13279399Sloos * 14279399Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15279399Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16279399Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17279399Sloos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18279399Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19279399Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20279399Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21279399Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22279399Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23279399Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24279399Sloos * SUCH DAMAGE. 25279399Sloos */ 26279399Sloos 27279399Sloos#include <sys/cdefs.h> 28279399Sloos__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/ds3231.c 331503 2018-03-24 23:01:10Z ian $"); 29279399Sloos 30279399Sloos/* 31279399Sloos * Driver for Maxim DS3231[N] real-time clock/calendar. 32279399Sloos */ 33279399Sloos 34279399Sloos#include "opt_platform.h" 35279399Sloos 36279399Sloos#include <sys/param.h> 37279399Sloos#include <sys/systm.h> 38279399Sloos#include <sys/bus.h> 39279399Sloos#include <sys/clock.h> 40279399Sloos#include <sys/kernel.h> 41279399Sloos#include <sys/module.h> 42279399Sloos#include <sys/sysctl.h> 43279399Sloos 44279399Sloos#include <dev/iicbus/iicbus.h> 45279399Sloos#include <dev/iicbus/iiconf.h> 46279399Sloos#ifdef FDT 47279399Sloos#include <dev/ofw/openfirm.h> 48279399Sloos#include <dev/ofw/ofw_bus.h> 49279399Sloos#include <dev/ofw/ofw_bus_subr.h> 50279399Sloos#endif 51279399Sloos 52279399Sloos#include <dev/iicbus/ds3231reg.h> 53279399Sloos 54279399Sloos#include "clock_if.h" 55279399Sloos#include "iicbus_if.h" 56279399Sloos 57279399Sloosstruct ds3231_softc { 58279399Sloos device_t sc_dev; 59279399Sloos int sc_last_c; 60279399Sloos int sc_year0; 61279399Sloos struct intr_config_hook enum_hook; 62279399Sloos uint16_t sc_addr; /* DS3231 slave address. */ 63279399Sloos uint8_t sc_ctrl; 64279399Sloos uint8_t sc_status; 65323467Sian bool sc_use_ampm; 66279399Sloos}; 67279399Sloos 68279399Sloosstatic void ds3231_start(void *); 69279399Sloos 70279399Sloosstatic int 71323467Siands3231_read1(device_t dev, uint8_t reg, uint8_t *data) 72279399Sloos{ 73279399Sloos 74323467Sian return (iicdev_readfrom(dev, reg, data, 1, IIC_INTRWAIT)); 75279399Sloos} 76279399Sloos 77279399Sloosstatic int 78323467Siands3231_write1(device_t dev, uint8_t reg, uint8_t data) 79279399Sloos{ 80279399Sloos 81323467Sian return (iicdev_writeto(dev, reg, &data, 1, IIC_INTRWAIT)); 82279399Sloos} 83279399Sloos 84279399Sloosstatic int 85279399Sloosds3231_ctrl_read(struct ds3231_softc *sc) 86279399Sloos{ 87279399Sloos int error; 88279399Sloos 89323467Sian error = ds3231_read1(sc->sc_dev, DS3231_CONTROL, &sc->sc_ctrl); 90279399Sloos if (error) { 91279399Sloos device_printf(sc->sc_dev, "cannot read from RTC.\n"); 92279399Sloos return (error); 93279399Sloos } 94279399Sloos return (0); 95279399Sloos} 96279399Sloos 97279399Sloosstatic int 98279399Sloosds3231_ctrl_write(struct ds3231_softc *sc) 99279399Sloos{ 100279399Sloos int error; 101323467Sian uint8_t data; 102279399Sloos 103279399Sloos /* Always enable the oscillator. Always disable both alarms. */ 104323467Sian data = sc->sc_ctrl & ~DS3231_CTRL_MASK; 105323467Sian error = ds3231_write1(sc->sc_dev, DS3231_CONTROL, data); 106279399Sloos if (error != 0) 107279399Sloos device_printf(sc->sc_dev, "cannot write to RTC.\n"); 108279399Sloos 109279399Sloos return (error); 110279399Sloos} 111279399Sloos 112279399Sloosstatic int 113279399Sloosds3231_status_read(struct ds3231_softc *sc) 114279399Sloos{ 115279399Sloos int error; 116279399Sloos 117323467Sian error = ds3231_read1(sc->sc_dev, DS3231_STATUS, &sc->sc_status); 118279399Sloos if (error) { 119279399Sloos device_printf(sc->sc_dev, "cannot read from RTC.\n"); 120279399Sloos return (error); 121279399Sloos } 122279399Sloos 123279399Sloos return (0); 124279399Sloos} 125279399Sloos 126279399Sloosstatic int 127279399Sloosds3231_status_write(struct ds3231_softc *sc, int clear_a1, int clear_a2) 128279399Sloos{ 129279399Sloos int error; 130323467Sian uint8_t data; 131279399Sloos 132323467Sian data = sc->sc_status; 133279399Sloos if (clear_a1 == 0) 134323467Sian data |= DS3231_STATUS_A1F; 135279399Sloos if (clear_a2 == 0) 136323467Sian data |= DS3231_STATUS_A2F; 137323467Sian error = ds3231_write1(sc->sc_dev, DS3231_STATUS, data); 138279399Sloos if (error != 0) 139279399Sloos device_printf(sc->sc_dev, "cannot write to RTC.\n"); 140279399Sloos 141279399Sloos return (error); 142279399Sloos} 143279399Sloos 144279399Sloosstatic int 145279399Sloosds3231_temp_read(struct ds3231_softc *sc, int *temp) 146279399Sloos{ 147279399Sloos int error, neg, t; 148279399Sloos uint8_t buf8[2]; 149279399Sloos uint16_t buf; 150279399Sloos 151323467Sian error = iicdev_readfrom(sc->sc_dev, DS3231_TEMP, buf8, sizeof(buf8), 152323467Sian IIC_INTRWAIT); 153279399Sloos if (error != 0) 154279399Sloos return (error); 155279399Sloos buf = (buf8[0] << 8) | (buf8[1] & 0xff); 156279399Sloos neg = 0; 157279399Sloos if (buf & DS3231_NEG_BIT) { 158279399Sloos buf = ~(buf & DS3231_TEMP_MASK) + 1; 159279399Sloos neg = 1; 160279399Sloos } 161279399Sloos *temp = ((int16_t)buf >> 8) * 10; 162279399Sloos t = 0; 163279399Sloos if (buf & DS3231_0250C) 164279399Sloos t += 250; 165279399Sloos if (buf & DS3231_0500C) 166279399Sloos t += 500; 167279399Sloos t /= 100; 168279399Sloos *temp += t; 169279399Sloos if (neg) 170279399Sloos *temp = -(*temp); 171279399Sloos *temp += TZ_ZEROC; 172279399Sloos 173279399Sloos return (0); 174279399Sloos} 175279399Sloos 176279399Sloosstatic int 177279399Sloosds3231_temp_sysctl(SYSCTL_HANDLER_ARGS) 178279399Sloos{ 179279399Sloos int error, temp; 180279399Sloos struct ds3231_softc *sc; 181279399Sloos 182279399Sloos sc = (struct ds3231_softc *)arg1; 183279399Sloos if (ds3231_temp_read(sc, &temp) != 0) 184279399Sloos return (EIO); 185279399Sloos error = sysctl_handle_int(oidp, &temp, 0, req); 186279399Sloos 187279399Sloos return (error); 188279399Sloos} 189279399Sloos 190279399Sloosstatic int 191279399Sloosds3231_conv_sysctl(SYSCTL_HANDLER_ARGS) 192279399Sloos{ 193279399Sloos int error, conv, newc; 194279399Sloos struct ds3231_softc *sc; 195279399Sloos 196279399Sloos sc = (struct ds3231_softc *)arg1; 197279399Sloos error = ds3231_ctrl_read(sc); 198279399Sloos if (error != 0) 199279399Sloos return (error); 200279399Sloos newc = conv = (sc->sc_ctrl & DS3231_CTRL_CONV) ? 1 : 0; 201279399Sloos error = sysctl_handle_int(oidp, &newc, 0, req); 202279399Sloos if (error != 0 || req->newptr == NULL) 203279399Sloos return (error); 204279399Sloos if (conv == 0 && newc != 0) { 205279399Sloos error = ds3231_status_read(sc); 206279399Sloos if (error != 0) 207279399Sloos return (error); 208279399Sloos if (sc->sc_status & DS3231_STATUS_BUSY) 209279399Sloos return (0); 210279399Sloos sc->sc_ctrl |= DS3231_CTRL_CONV; 211279399Sloos error = ds3231_ctrl_write(sc); 212279399Sloos if (error != 0) 213279399Sloos return (error); 214279399Sloos } 215279399Sloos 216279399Sloos return (error); 217279399Sloos} 218279399Sloos 219279399Sloosstatic int 220279399Sloosds3231_bbsqw_sysctl(SYSCTL_HANDLER_ARGS) 221279399Sloos{ 222279399Sloos int bbsqw, error, newb; 223279399Sloos struct ds3231_softc *sc; 224279399Sloos 225279399Sloos sc = (struct ds3231_softc *)arg1; 226279399Sloos error = ds3231_ctrl_read(sc); 227279399Sloos if (error != 0) 228279399Sloos return (error); 229279399Sloos bbsqw = newb = (sc->sc_ctrl & DS3231_CTRL_BBSQW) ? 1 : 0; 230279399Sloos error = sysctl_handle_int(oidp, &newb, 0, req); 231279399Sloos if (error != 0 || req->newptr == NULL) 232279399Sloos return (error); 233279399Sloos if (bbsqw != newb) { 234279399Sloos sc->sc_ctrl &= ~DS3231_CTRL_BBSQW; 235279399Sloos if (newb) 236279399Sloos sc->sc_ctrl |= DS3231_CTRL_BBSQW; 237279399Sloos error = ds3231_ctrl_write(sc); 238279399Sloos if (error != 0) 239279399Sloos return (error); 240279399Sloos } 241279399Sloos 242279399Sloos return (error); 243279399Sloos} 244279399Sloos 245279399Sloosstatic int 246279399Sloosds3231_sqw_freq_sysctl(SYSCTL_HANDLER_ARGS) 247279399Sloos{ 248279852Sloos int ds3231_sqw_freq[] = { 1, 1024, 4096, 8192 }; 249279399Sloos int error, freq, i, newf, tmp; 250279399Sloos struct ds3231_softc *sc; 251279399Sloos 252279399Sloos sc = (struct ds3231_softc *)arg1; 253279399Sloos error = ds3231_ctrl_read(sc); 254279399Sloos if (error != 0) 255279399Sloos return (error); 256279399Sloos tmp = (sc->sc_ctrl & DS3231_CTRL_RS_MASK) >> DS3231_CTRL_RS_SHIFT; 257279852Sloos if (tmp >= nitems(ds3231_sqw_freq)) 258279852Sloos tmp = nitems(ds3231_sqw_freq) - 1; 259279399Sloos freq = ds3231_sqw_freq[tmp]; 260279399Sloos error = sysctl_handle_int(oidp, &freq, 0, req); 261279399Sloos if (error != 0 || req->newptr == NULL) 262279399Sloos return (error); 263279399Sloos if (freq != ds3231_sqw_freq[tmp]) { 264279399Sloos newf = 0; 265279399Sloos for (i = 0; i < nitems(ds3231_sqw_freq); i++) 266279399Sloos if (freq >= ds3231_sqw_freq[i]) 267279399Sloos newf = i; 268279399Sloos sc->sc_ctrl &= ~DS3231_CTRL_RS_MASK; 269279399Sloos sc->sc_ctrl |= newf << DS3231_CTRL_RS_SHIFT; 270279399Sloos error = ds3231_ctrl_write(sc); 271279399Sloos if (error != 0) 272279399Sloos return (error); 273279399Sloos } 274279399Sloos 275279399Sloos return (error); 276279399Sloos} 277279399Sloos 278279399Sloosstatic int 279279399Sloosds3231_str_sqw_mode(char *buf) 280279399Sloos{ 281279399Sloos int len, rtrn; 282279399Sloos 283279399Sloos rtrn = -1; 284279399Sloos len = strlen(buf); 285279399Sloos if ((len > 2 && strncasecmp("interrupt", buf, len) == 0) || 286279399Sloos (len > 2 && strncasecmp("int", buf, len) == 0)) { 287279399Sloos rtrn = 1; 288279399Sloos } else if ((len > 2 && strncasecmp("square-wave", buf, len) == 0) || 289279399Sloos (len > 2 && strncasecmp("sqw", buf, len) == 0)) { 290279399Sloos rtrn = 0; 291279399Sloos } 292279399Sloos 293279399Sloos return (rtrn); 294279399Sloos} 295279399Sloos 296279399Sloosstatic int 297279399Sloosds3231_sqw_mode_sysctl(SYSCTL_HANDLER_ARGS) 298279399Sloos{ 299279399Sloos char buf[16]; 300279399Sloos int error, mode, newm; 301279399Sloos struct ds3231_softc *sc; 302279399Sloos 303279399Sloos sc = (struct ds3231_softc *)arg1; 304279399Sloos error = ds3231_ctrl_read(sc); 305279399Sloos if (error != 0) 306279399Sloos return (error); 307279399Sloos if (sc->sc_ctrl & DS3231_CTRL_INTCN) { 308279399Sloos mode = 1; 309279399Sloos strlcpy(buf, "interrupt", sizeof(buf)); 310279399Sloos } else { 311279399Sloos mode = 0; 312279399Sloos strlcpy(buf, "square-wave", sizeof(buf)); 313279399Sloos } 314279399Sloos error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 315279399Sloos if (error != 0 || req->newptr == NULL) 316279399Sloos return (error); 317279399Sloos newm = ds3231_str_sqw_mode(buf); 318279399Sloos if (newm != -1 && mode != newm) { 319279399Sloos sc->sc_ctrl &= ~DS3231_CTRL_INTCN; 320279399Sloos if (newm == 1) 321279399Sloos sc->sc_ctrl |= DS3231_CTRL_INTCN; 322279399Sloos error = ds3231_ctrl_write(sc); 323279399Sloos if (error != 0) 324279399Sloos return (error); 325279399Sloos } 326279399Sloos 327279399Sloos return (error); 328279399Sloos} 329279399Sloos 330279399Sloosstatic int 331279399Sloosds3231_en32khz_sysctl(SYSCTL_HANDLER_ARGS) 332279399Sloos{ 333279399Sloos int error, en32khz, tmp; 334279399Sloos struct ds3231_softc *sc; 335279399Sloos 336279399Sloos sc = (struct ds3231_softc *)arg1; 337279399Sloos error = ds3231_status_read(sc); 338279399Sloos if (error != 0) 339279399Sloos return (error); 340279399Sloos tmp = en32khz = (sc->sc_status & DS3231_STATUS_EN32KHZ) ? 1 : 0; 341279399Sloos error = sysctl_handle_int(oidp, &en32khz, 0, req); 342279399Sloos if (error != 0 || req->newptr == NULL) 343279399Sloos return (error); 344279399Sloos if (en32khz != tmp) { 345279399Sloos sc->sc_status &= ~DS3231_STATUS_EN32KHZ; 346279399Sloos if (en32khz) 347279399Sloos sc->sc_status |= DS3231_STATUS_EN32KHZ; 348279399Sloos error = ds3231_status_write(sc, 0, 0); 349279399Sloos if (error != 0) 350279399Sloos return (error); 351279399Sloos } 352279399Sloos 353279399Sloos return (error); 354279399Sloos} 355279399Sloos 356279399Sloosstatic int 357279399Sloosds3231_probe(device_t dev) 358279399Sloos{ 359279399Sloos 360279399Sloos#ifdef FDT 361279399Sloos if (!ofw_bus_status_okay(dev)) 362279399Sloos return (ENXIO); 363279399Sloos if (!ofw_bus_is_compatible(dev, "maxim,ds3231")) 364279399Sloos return (ENXIO); 365279399Sloos#endif 366279399Sloos device_set_desc(dev, "Maxim DS3231 RTC"); 367279399Sloos 368279399Sloos return (BUS_PROBE_DEFAULT); 369279399Sloos} 370279399Sloos 371279399Sloosstatic int 372279399Sloosds3231_attach(device_t dev) 373279399Sloos{ 374279399Sloos struct ds3231_softc *sc; 375279399Sloos 376279399Sloos sc = device_get_softc(dev); 377279399Sloos sc->sc_dev = dev; 378279399Sloos sc->sc_addr = iicbus_get_addr(dev); 379279399Sloos sc->sc_last_c = -1; 380331503Sian sc->sc_year0 = 0; 381279399Sloos sc->enum_hook.ich_func = ds3231_start; 382279399Sloos sc->enum_hook.ich_arg = dev; 383279399Sloos 384279399Sloos /* 385279399Sloos * We have to wait until interrupts are enabled. Usually I2C read 386279399Sloos * and write only works when the interrupts are available. 387279399Sloos */ 388279399Sloos if (config_intrhook_establish(&sc->enum_hook) != 0) 389279399Sloos return (ENOMEM); 390279399Sloos 391279399Sloos return (0); 392279399Sloos} 393279399Sloos 394323467Sianstatic int 395323467Siands3231_detach(device_t dev) 396323467Sian{ 397323467Sian 398323467Sian clock_unregister(dev); 399323467Sian return (0); 400323467Sian} 401323467Sian 402279399Sloosstatic void 403279399Sloosds3231_start(void *xdev) 404279399Sloos{ 405279399Sloos device_t dev; 406279399Sloos struct ds3231_softc *sc; 407279399Sloos struct sysctl_ctx_list *ctx; 408279399Sloos struct sysctl_oid *tree_node; 409279399Sloos struct sysctl_oid_list *tree; 410279399Sloos 411279399Sloos dev = (device_t)xdev; 412279399Sloos sc = device_get_softc(dev); 413279399Sloos ctx = device_get_sysctl_ctx(dev); 414279399Sloos tree_node = device_get_sysctl_tree(dev); 415279399Sloos tree = SYSCTL_CHILDREN(tree_node); 416279399Sloos 417279399Sloos config_intrhook_disestablish(&sc->enum_hook); 418279399Sloos if (ds3231_ctrl_read(sc) != 0) 419279399Sloos return; 420279399Sloos if (ds3231_status_read(sc) != 0) 421279399Sloos return; 422323467Sian /* 423323467Sian * Warn if the clock stopped, but don't restart it until the first 424323467Sian * clock_settime() call. 425323467Sian */ 426279399Sloos if (sc->sc_status & DS3231_STATUS_OSF) { 427279399Sloos device_printf(sc->sc_dev, 428323467Sian "WARNING: RTC clock stopped, check the battery.\n"); 429279399Sloos } 430279399Sloos 431327653Sian /* 432327653Sian * Ack any pending alarm interrupts and clear the EOSC bit to ensure the 433327653Sian * clock runs even when on battery power. Do not give up if these 434327653Sian * writes fail, because a factory-fresh chip is in a special mode that 435327653Sian * disables much of the chip to save battery power, and the only thing 436327653Sian * that gets it out of that mode is writing to the time registers. In 437327653Sian * these pristine chips, the EOSC and alarm bits are zero already, so 438327653Sian * the first valid write of time will get everything running properly. 439327653Sian */ 440327653Sian ds3231_status_write(sc, 1, 1); 441327653Sian ds3231_ctrl_write(sc); 442327653Sian 443279399Sloos /* Temperature. */ 444279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature", 445279399Sloos CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 446279399Sloos ds3231_temp_sysctl, "IK", "Current temperature"); 447279399Sloos /* Configuration parameters. */ 448279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temp_conv", 449279399Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 450279399Sloos ds3231_conv_sysctl, "IU", 451279399Sloos "DS3231 start a new temperature converstion"); 452279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "bbsqw", 453279399Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 454279399Sloos ds3231_bbsqw_sysctl, "IU", 455279399Sloos "DS3231 battery-backed square-wave output enable"); 456279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_freq", 457279399Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 458279399Sloos ds3231_sqw_freq_sysctl, "IU", 459279399Sloos "DS3231 square-wave output frequency"); 460279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqw_mode", 461279399Sloos CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0, 462279399Sloos ds3231_sqw_mode_sysctl, "A", "DS3231 SQW output mode control"); 463279399Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "32khz_enable", 464279399Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, 465279399Sloos ds3231_en32khz_sysctl, "IU", "DS3231 enable the 32kHz output"); 466279399Sloos 467323467Sian /* 468323467Sian * Register as a clock with 1 second resolution. Schedule the 469323467Sian * clock_settime() method to be called just after top-of-second; 470323467Sian * resetting the time resets top-of-second in the hardware. 471323467Sian */ 472323467Sian clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_ADJ); 473323467Sian clock_schedule(dev, 1); 474279399Sloos} 475279399Sloos 476279399Sloosstatic int 477279399Sloosds3231_gettime(device_t dev, struct timespec *ts) 478279399Sloos{ 479279399Sloos int c, error; 480331503Sian struct bcd_clocktime bct; 481279399Sloos struct ds3231_softc *sc; 482323467Sian uint8_t data[7], hourmask; 483279399Sloos 484279399Sloos sc = device_get_softc(dev); 485323467Sian 486323467Sian /* If the clock halted, we don't have good data. */ 487323467Sian if ((error = ds3231_status_read(sc)) != 0) { 488323467Sian device_printf(dev, "cannot read from RTC.\n"); 489323467Sian return (error); 490323467Sian } 491323467Sian if (sc->sc_status & DS3231_STATUS_OSF) 492323467Sian return (EINVAL); 493323467Sian 494323467Sian error = iicdev_readfrom(sc->sc_dev, DS3231_SECS, data, sizeof(data), 495323467Sian IIC_INTRWAIT); 496279399Sloos if (error != 0) { 497279399Sloos device_printf(dev, "cannot read from RTC.\n"); 498279399Sloos return (error); 499279399Sloos } 500323467Sian 501323467Sian /* If chip is in AM/PM mode remember that. */ 502323467Sian if (data[DS3231_HOUR] & DS3231_HOUR_USE_AMPM) { 503323467Sian sc->sc_use_ampm = true; 504323467Sian hourmask = DS3231_HOUR_MASK_12HR; 505323467Sian } else 506323467Sian hourmask = DS3231_HOUR_MASK_24HR; 507323467Sian 508331503Sian bct.nsec = 0; 509331503Sian bct.sec = data[DS3231_SECS] & DS3231_SECS_MASK; 510331503Sian bct.min = data[DS3231_MINS] & DS3231_MINS_MASK; 511331503Sian bct.hour = data[DS3231_HOUR] & hourmask; 512331503Sian bct.day = data[DS3231_DATE] & DS3231_DATE_MASK; 513331503Sian bct.mon = data[DS3231_MONTH] & DS3231_MONTH_MASK; 514331503Sian bct.year = data[DS3231_YEAR] & DS3231_YEAR_MASK; 515331503Sian bct.ispm = data[DS3231_HOUR] & DS3231_HOUR_IS_PM; 516323467Sian 517323467Sian /* 518323467Sian * If the century flag has toggled since we last saw it, there has been 519323467Sian * a century rollover. If this is the first time we're seeing it, 520323467Sian * remember the state so we can preserve its polarity on writes. 521323467Sian */ 522279399Sloos c = (data[DS3231_MONTH] & DS3231_C_MASK) ? 1 : 0; 523279399Sloos if (sc->sc_last_c == -1) 524279399Sloos sc->sc_last_c = c; 525279399Sloos else if (c != sc->sc_last_c) { 526331503Sian sc->sc_year0 += 0x100; 527279399Sloos sc->sc_last_c = c; 528279399Sloos } 529331503Sian bct.year |= sc->sc_year0; 530279399Sloos 531331503Sian clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_READ, &bct); 532331503Sian return (clock_bcd_to_ts(&bct, ts, sc->sc_use_ampm)); 533279399Sloos} 534279399Sloos 535279399Sloosstatic int 536279399Sloosds3231_settime(device_t dev, struct timespec *ts) 537279399Sloos{ 538279399Sloos int error; 539331503Sian struct bcd_clocktime bct; 540279399Sloos struct ds3231_softc *sc; 541323467Sian uint8_t data[7]; 542323467Sian uint8_t pmflags; 543279399Sloos 544279399Sloos sc = device_get_softc(dev); 545323467Sian 546323467Sian /* 547323467Sian * We request a timespec with no resolution-adjustment. That also 548323467Sian * disables utc adjustment, so apply that ourselves. 549323467Sian */ 550323467Sian ts->tv_sec -= utc_offset(); 551331503Sian clock_ts_to_bcd(ts, &bct, sc->sc_use_ampm); 552331503Sian clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_WRITE, &bct); 553323467Sian 554323467Sian /* If the chip is in AM/PM mode, adjust hour and set flags as needed. */ 555323467Sian if (sc->sc_use_ampm) { 556323467Sian pmflags = DS3231_HOUR_USE_AMPM; 557331503Sian if (bct.ispm) 558323467Sian pmflags |= DS3231_HOUR_IS_PM; 559323467Sian } else 560323467Sian pmflags = 0; 561323467Sian 562331503Sian data[DS3231_SECS] = bct.sec; 563331503Sian data[DS3231_MINS] = bct.min; 564331503Sian data[DS3231_HOUR] = bct.hour | pmflags; 565331503Sian data[DS3231_DATE] = bct.day; 566331503Sian data[DS3231_WEEKDAY] = bct.dow + 1; 567331503Sian data[DS3231_MONTH] = bct.mon; 568331503Sian data[DS3231_YEAR] = bct.year & 0xff; 569279399Sloos if (sc->sc_last_c) 570279399Sloos data[DS3231_MONTH] |= DS3231_C_MASK; 571323467Sian 572279399Sloos /* Write the time back to RTC. */ 573323467Sian error = iicdev_writeto(dev, DS3231_SECS, data, sizeof(data), 574323467Sian IIC_INTRWAIT); 575323467Sian if (error != 0) { 576279399Sloos device_printf(dev, "cannot write to RTC.\n"); 577323467Sian return (error); 578323467Sian } 579279399Sloos 580323467Sian /* 581323467Sian * Unlike most hardware, the osc-was-stopped bit does not clear itself 582323467Sian * after setting the time, it has to be manually written to zero. 583323467Sian */ 584323467Sian if (sc->sc_status & DS3231_STATUS_OSF) { 585323467Sian if ((error = ds3231_status_read(sc)) != 0) { 586323467Sian device_printf(dev, "cannot read from RTC.\n"); 587323467Sian return (error); 588323467Sian } 589323467Sian sc->sc_status &= ~DS3231_STATUS_OSF; 590323467Sian if ((error = ds3231_status_write(sc, 0, 0)) != 0) { 591323467Sian device_printf(dev, "cannot write to RTC.\n"); 592323467Sian return (error); 593323467Sian } 594323467Sian } 595323467Sian 596279399Sloos return (error); 597279399Sloos} 598279399Sloos 599279399Sloosstatic device_method_t ds3231_methods[] = { 600279399Sloos DEVMETHOD(device_probe, ds3231_probe), 601279399Sloos DEVMETHOD(device_attach, ds3231_attach), 602323467Sian DEVMETHOD(device_detach, ds3231_detach), 603279399Sloos 604279399Sloos DEVMETHOD(clock_gettime, ds3231_gettime), 605279399Sloos DEVMETHOD(clock_settime, ds3231_settime), 606279399Sloos 607279399Sloos DEVMETHOD_END 608279399Sloos}; 609279399Sloos 610279399Sloosstatic driver_t ds3231_driver = { 611279399Sloos "ds3231", 612279399Sloos ds3231_methods, 613279399Sloos sizeof(struct ds3231_softc), 614279399Sloos}; 615279399Sloos 616279399Sloosstatic devclass_t ds3231_devclass; 617279399Sloos 618279399SloosDRIVER_MODULE(ds3231, iicbus, ds3231_driver, ds3231_devclass, NULL, NULL); 619279399SloosMODULE_VERSION(ds3231, 1); 620279399SloosMODULE_DEPEND(ds3231, iicbus, 1, 1, 1); 621