ds13rtc.c revision 322473
1322473Sian/*- 2322473Sian * Copyright (c) 2017 Ian Lepore <ian@freebsd.org> 3322473Sian * All rights reserved. 4322473Sian * 5322473Sian * Redistribution and use in source and binary forms, with or without 6322473Sian * modification, are permitted provided that the following conditions 7322473Sian * are met: 8322473Sian * 1. Redistributions of source code must retain the above copyright 9322473Sian * notice, this list of conditions and the following disclaimer. 10322473Sian * 2. Redistributions in binary form must reproduce the above copyright 11322473Sian * notice, this list of conditions and the following disclaimer in the 12322473Sian * documentation and/or other materials provided with the distribution. 13322473Sian * 14322473Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15322473Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16322473Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17322473Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18322473Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19322473Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20322473Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21322473Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22322473Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23322473Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24322473Sian * SUCH DAMAGE. 25322473Sian */ 26322473Sian 27322473Sian#include <sys/cdefs.h> 28322473Sian__FBSDID("$FreeBSD: head/sys/dev/iicbus/ds13rtc.c 322473 2017-08-13 21:02:40Z ian $"); 29322473Sian 30322473Sian/* 31322473Sian * Driver for Dallas/Maxim DS13xx real-time clock/calendar chips: 32322473Sian * 33322473Sian * - DS1307 = Original/basic rtc + 56 bytes ram; 5v only. 34322473Sian * - DS1308 = Updated 1307, available in 1.8v-5v variations. 35322473Sian * - DS1337 = Like 1308, integrated xtal, 32khz output on at powerup. 36322473Sian * - DS1338 = Like 1308, integrated xtal. 37322473Sian * - DS1339 = Like 1337, integrated xtal, integrated trickle charger. 38322473Sian * - DS1340 = Like 1338, ST M41T00 compatible. 39322473Sian * - DS1341 = Like 1338, can slave-sync osc to external clock signal. 40322473Sian * - DS1342 = Like 1341 but requires different xtal. 41322473Sian * - DS1371 = 32-bit binary counter, watchdog timer. 42322473Sian * - DS1372 = 32-bit binary counter, 64-bit unique id in rom. 43322473Sian * - DS1374 = 32-bit binary counter, watchdog timer, trickle charger. 44322473Sian * - DS1375 = Like 1308 but only 16 bytes ram. 45322473Sian * - DS1388 = Rtc, watchdog timer, 512 bytes eeprom (not sram). 46322473Sian * 47322473Sian * This driver supports only basic timekeeping functions. It provides no access 48322473Sian * to or control over any other functionality provided by the chips. 49322473Sian */ 50322473Sian 51322473Sian#include "opt_platform.h" 52322473Sian 53322473Sian#include <sys/param.h> 54322473Sian#include <sys/systm.h> 55322473Sian#include <sys/bus.h> 56322473Sian#include <sys/clock.h> 57322473Sian#include <sys/endian.h> 58322473Sian#include <sys/kernel.h> 59322473Sian#include <sys/libkern.h> 60322473Sian#include <sys/module.h> 61322473Sian 62322473Sian#include <dev/iicbus/iicbus.h> 63322473Sian#include <dev/iicbus/iiconf.h> 64322473Sian#ifdef FDT 65322473Sian#include <dev/ofw/openfirm.h> 66322473Sian#include <dev/ofw/ofw_bus.h> 67322473Sian#include <dev/ofw/ofw_bus_subr.h> 68322473Sian#endif 69322473Sian 70322473Sian#include "clock_if.h" 71322473Sian#include "iicbus_if.h" 72322473Sian 73322473Sian/* 74322473Sian * I2C address 1101 000x 75322473Sian */ 76322473Sian#define DS13xx_ADDR 0xd0 77322473Sian 78322473Sian/* 79322473Sian * Registers, bits within them, and masks for the various chip types. 80322473Sian */ 81322473Sian 82322473Sian#define DS13xx_R_NONE 0xff /* Placeholder */ 83322473Sian 84322473Sian#define DS130x_R_CONTROL 0x07 85322473Sian#define DS133x_R_CONTROL 0x0e 86322473Sian#define DS1340_R_CONTROL 0x07 87322473Sian#define DS1341_R_CONTROL 0x0e 88322473Sian#define DS1371_R_CONTROL 0x07 89322473Sian#define DS1372_R_CONTROL 0x07 90322473Sian#define DS1374_R_CONTROL 0x07 91322473Sian#define DS1375_R_CONTROL 0x0e 92322473Sian#define DS1388_R_CONTROL 0x0c 93322473Sian 94322473Sian#define DS13xx_R_SECOND 0x00 95322473Sian#define DS1388_R_SECOND 0x01 96322473Sian 97322473Sian#define DS130x_R_STATUS DS13xx_R_NONE 98322473Sian#define DS133x_R_STATUS 0x0f 99322473Sian#define DS1340_R_STATUS 0x09 100322473Sian#define DS137x_R_STATUS 0x08 101322473Sian#define DS1388_R_STATUS 0x0b 102322473Sian 103322473Sian#define DS13xx_B_STATUS_OSF 0x80 /* OSF is 1<<7 in status and sec regs */ 104322473Sian#define DS13xx_B_HOUR_AMPM 0x40 /* AMPM mode is bit 1<<6 */ 105322473Sian#define DS13xx_B_HOUR_PM 0x20 /* PM hours indicated by 1<<5 */ 106322473Sian#define DS13xx_B_MONTH_CENTURY 0x80 /* 21st century indicated by 1<<7 */ 107322473Sian 108322473Sian#define DS13xx_M_SECOND 0x7f /* Masks for all BCD time regs... */ 109322473Sian#define DS13xx_M_MINUTE 0x7f 110322473Sian#define DS13xx_M_12HOUR 0x1f 111322473Sian#define DS13xx_M_24HOUR 0x3f 112322473Sian#define DS13xx_M_DAY 0x3f 113322473Sian#define DS13xx_M_MONTH 0x1f 114322473Sian#define DS13xx_M_YEAR 0xff 115322473Sian 116322473Sian/* 117322473Sian * The chip types we support. 118322473Sian */ 119322473Sianenum { 120322473Sian TYPE_NONE, 121322473Sian TYPE_DS1307, 122322473Sian TYPE_DS1308, 123322473Sian TYPE_DS1337, 124322473Sian TYPE_DS1338, 125322473Sian TYPE_DS1339, 126322473Sian TYPE_DS1340, 127322473Sian TYPE_DS1341, 128322473Sian TYPE_DS1342, 129322473Sian TYPE_DS1371, 130322473Sian TYPE_DS1372, 131322473Sian TYPE_DS1374, 132322473Sian TYPE_DS1375, 133322473Sian TYPE_DS1388, 134322473Sian 135322473Sian TYPE_COUNT 136322473Sian}; 137322473Sianstatic const char *desc_strings[] = { 138322473Sian "", 139322473Sian "Dallas/Maxim DS1307 RTC", 140322473Sian "Dallas/Maxim DS1308 RTC", 141322473Sian "Dallas/Maxim DS1337 RTC", 142322473Sian "Dallas/Maxim DS1338 RTC", 143322473Sian "Dallas/Maxim DS1339 RTC", 144322473Sian "Dallas/Maxim DS1340 RTC", 145322473Sian "Dallas/Maxim DS1341 RTC", 146322473Sian "Dallas/Maxim DS1342 RTC", 147322473Sian "Dallas/Maxim DS1371 RTC", 148322473Sian "Dallas/Maxim DS1372 RTC", 149322473Sian "Dallas/Maxim DS1374 RTC", 150322473Sian "Dallas/Maxim DS1375 RTC", 151322473Sian "Dallas/Maxim DS1388 RTC", 152322473Sian}; 153322473SianCTASSERT(nitems(desc_strings) == TYPE_COUNT); 154322473Sian 155322473Sian/* 156322473Sian * The time registers in the order they are laid out in hardware. 157322473Sian */ 158322473Sianstruct time_regs { 159322473Sian uint8_t sec, min, hour, wday, day, month, year; 160322473Sian}; 161322473Sian 162322473Sianstruct ds13rtc_softc { 163322473Sian device_t dev; 164322473Sian device_t busdev; 165322473Sian u_int flags; /* SC_F_* flags */ 166322473Sian u_int chiptype; /* Type of DS13xx chip */ 167322473Sian uint8_t secaddr; /* Address of seconds register */ 168322473Sian uint8_t osfaddr; /* Address of register with OSF */ 169322473Sian}; 170322473Sian 171322473Sian#define SC_F_BINARY (1u << 0) /* Time is 32-bit binary counter */ 172322473Sian#define SC_F_AMPM (1u << 1) /* Use PM flag in hours reg */ 173322473Sian#define SC_F_CENTURY (1u << 2) /* Use century bit */ 174322473Sian 175322473Sian/* 176322473Sian * We use the compat_data table to look up hint strings in the non-FDT case, so 177322473Sian * define the struct locally when we don't get it from ofw_bus_subr.h. 178322473Sian */ 179322473Sian#ifdef FDT 180322473Siantypedef struct ofw_compat_data ds13_compat_data; 181322473Sian#else 182322473Siantypedef struct { 183322473Sian const char *ocd_str; 184322473Sian uintptr_t ocd_data; 185322473Sian} ds13_compat_data; 186322473Sian#endif 187322473Sian 188322473Sianstatic ds13_compat_data compat_data[] = { 189322473Sian {"dallas,ds1307", TYPE_DS1307}, 190322473Sian {"dallas,ds1308", TYPE_DS1308}, 191322473Sian {"dallas,ds1337", TYPE_DS1337}, 192322473Sian {"dallas,ds1338", TYPE_DS1338}, 193322473Sian {"dallas,ds1339", TYPE_DS1339}, 194322473Sian {"dallas,ds1340", TYPE_DS1340}, 195322473Sian {"dallas,ds1341", TYPE_DS1341}, 196322473Sian {"dallas,ds1342", TYPE_DS1342}, 197322473Sian {"dallas,ds1371", TYPE_DS1371}, 198322473Sian {"dallas,ds1372", TYPE_DS1372}, 199322473Sian {"dallas,ds1374", TYPE_DS1374}, 200322473Sian {"dallas,ds1375", TYPE_DS1375}, 201322473Sian {"dallas,ds1388", TYPE_DS1388}, 202322473Sian 203322473Sian {NULL, TYPE_NONE}, 204322473Sian}; 205322473Sian 206322473Sianstatic int 207322473Sianread_reg(struct ds13rtc_softc *sc, uint8_t reg, uint8_t *val) 208322473Sian{ 209322473Sian 210322473Sian return (iicdev_readfrom(sc->dev, reg, val, sizeof(*val), IIC_WAIT)); 211322473Sian} 212322473Sian 213322473Sianstatic int 214322473Sianwrite_reg(struct ds13rtc_softc *sc, uint8_t reg, uint8_t val) 215322473Sian{ 216322473Sian 217322473Sian return (iicdev_writeto(sc->dev, reg, &val, sizeof(val), IIC_WAIT)); 218322473Sian} 219322473Sian 220322473Sianstatic int 221322473Sianread_timeregs(struct ds13rtc_softc *sc, struct time_regs *tregs) 222322473Sian{ 223322473Sian int err; 224322473Sian 225322473Sian if ((err = iicdev_readfrom(sc->dev, sc->secaddr, tregs, 226322473Sian sizeof(*tregs), IIC_WAIT)) != 0) 227322473Sian return (err); 228322473Sian 229322473Sian return (err); 230322473Sian} 231322473Sian 232322473Sianstatic int 233322473Sianwrite_timeregs(struct ds13rtc_softc *sc, struct time_regs *tregs) 234322473Sian{ 235322473Sian 236322473Sian return (iicdev_writeto(sc->dev, sc->secaddr, tregs, 237322473Sian sizeof(*tregs), IIC_WAIT)); 238322473Sian} 239322473Sian 240322473Sianstatic int 241322473Sianread_timeword(struct ds13rtc_softc *sc, time_t *secs) 242322473Sian{ 243322473Sian int err; 244322473Sian uint8_t buf[4]; 245322473Sian 246322473Sian if ((err = iicdev_readfrom(sc->dev, sc->secaddr, buf, sizeof(buf), 247322473Sian IIC_WAIT)) == 0) 248322473Sian *secs = le32dec(buf); 249322473Sian 250322473Sian return (err); 251322473Sian} 252322473Sian 253322473Sianstatic int 254322473Sianwrite_timeword(struct ds13rtc_softc *sc, time_t secs) 255322473Sian{ 256322473Sian uint8_t buf[4]; 257322473Sian 258322473Sian le32enc(buf, (uint32_t)secs); 259322473Sian return (iicdev_writeto(sc->dev, sc->secaddr, buf, sizeof(buf), 260322473Sian IIC_WAIT)); 261322473Sian} 262322473Sian 263322473Sianstatic void 264322473Siands13rtc_start(void *arg) 265322473Sian{ 266322473Sian struct ds13rtc_softc *sc; 267322473Sian uint8_t ctlreg, statreg; 268322473Sian 269322473Sian sc = arg; 270322473Sian 271322473Sian /* 272322473Sian * Every chip in this family can be usefully initialized by writing 0 to 273322473Sian * the control register, except DS1375 which has an external oscillator 274322473Sian * controlled by values in the ctlreg that we know nothing about, so 275322473Sian * we'd best leave them alone. For all other chips, writing 0 enables 276322473Sian * the oscillator, disables signals/outputs in battery-backed mode 277322473Sian * (saves power) and disables features like watchdog timers and alarms. 278322473Sian */ 279322473Sian switch (sc->chiptype) { 280322473Sian case TYPE_DS1307: 281322473Sian case TYPE_DS1308: 282322473Sian case TYPE_DS1338: 283322473Sian case TYPE_DS1340: 284322473Sian case TYPE_DS1371: 285322473Sian case TYPE_DS1372: 286322473Sian case TYPE_DS1374: 287322473Sian ctlreg = DS130x_R_CONTROL; 288322473Sian break; 289322473Sian case TYPE_DS1337: 290322473Sian case TYPE_DS1339: 291322473Sian ctlreg = DS133x_R_CONTROL; 292322473Sian break; 293322473Sian case TYPE_DS1341: 294322473Sian case TYPE_DS1342: 295322473Sian ctlreg = DS1341_R_CONTROL; 296322473Sian break; 297322473Sian case TYPE_DS1375: 298322473Sian ctlreg = DS13xx_R_NONE; 299322473Sian break; 300322473Sian case TYPE_DS1388: 301322473Sian ctlreg = DS1388_R_CONTROL; 302322473Sian break; 303322473Sian default: 304322473Sian device_printf(sc->dev, "missing init code for this chiptype\n"); 305322473Sian return; 306322473Sian } 307322473Sian if (ctlreg != DS13xx_R_NONE) 308322473Sian write_reg(sc, ctlreg, 0); 309322473Sian 310322473Sian /* 311322473Sian * Common init. Read the OSF/CH status bit and report stopped clocks to 312322473Sian * the user. The status bit will be cleared the first time we write 313322473Sian * valid time to the chip (and must not be cleared before that). 314322473Sian */ 315322473Sian if (read_reg(sc, sc->osfaddr, &statreg) != 0) { 316322473Sian device_printf(sc->dev, "cannot read RTC clock status bit\n"); 317322473Sian return; 318322473Sian } 319322473Sian if (statreg & DS13xx_B_STATUS_OSF) { 320322473Sian device_printf(sc->dev, 321322473Sian "WARNING: RTC battery failed; time is invalid\n"); 322322473Sian } 323322473Sian 324322473Sian /* 325322473Sian * Figure out whether the chip is configured for AM/PM mode. On all 326322473Sian * chips that do AM/PM mode, the flag bit is in the hours register, 327322473Sian * which is secaddr+2. 328322473Sian */ 329322473Sian if ((sc->chiptype != TYPE_DS1340) && !(sc->flags & SC_F_BINARY)) { 330322473Sian if (read_reg(sc, sc->secaddr + 2, &statreg) != 0) { 331322473Sian device_printf(sc->dev, 332322473Sian "cannot read RTC clock AM/PM bit\n"); 333322473Sian return; 334322473Sian } 335322473Sian if (statreg & DS13xx_B_HOUR_AMPM) 336322473Sian sc->flags |= SC_F_AMPM; 337322473Sian } 338322473Sian 339322473Sian /* 340322473Sian * Everything looks good if we make it to here; register as an RTC. 341322473Sian * Schedule RTC updates to happen just after top-of-second. 342322473Sian */ 343322473Sian clock_register_flags(sc->dev, 1000000, CLOCKF_SETTIME_NO_ADJ); 344322473Sian clock_schedule(sc->dev, 1); 345322473Sian} 346322473Sian 347322473Sianstatic int 348322473Siands13rtc_gettime(device_t dev, struct timespec *ts) 349322473Sian{ 350322473Sian struct clocktime ct; 351322473Sian struct time_regs tregs; 352322473Sian struct ds13rtc_softc *sc; 353322473Sian int err; 354322473Sian uint8_t statreg, hourmask; 355322473Sian 356322473Sian sc = device_get_softc(dev); 357322473Sian 358322473Sian /* Read the OSF/CH bit; if the clock stopped we can't provide time. */ 359322473Sian if ((err = read_reg(sc, sc->osfaddr, &statreg)) != 0) { 360322473Sian return (err); 361322473Sian } 362322473Sian if (statreg & DS13xx_B_STATUS_OSF) 363322473Sian return (EINVAL); /* hardware is good, time is not. */ 364322473Sian 365322473Sian /* If the chip counts time in binary, we just read and return it. */ 366322473Sian if (sc->flags & SC_F_BINARY) { 367322473Sian if ((err = read_timeword(sc, &ts->tv_sec)) != 0) 368322473Sian return (err); 369322473Sian ts->tv_nsec = 0; 370322473Sian } 371322473Sian 372322473Sian /* 373322473Sian * Chip counts in BCD, read and decode it... 374322473Sian */ 375322473Sian if ((err = read_timeregs(sc, &tregs)) != 0) { 376322473Sian device_printf(dev, "cannot read RTC time\n"); 377322473Sian return (err); 378322473Sian } 379322473Sian 380322473Sian if (sc->flags & SC_F_AMPM) 381322473Sian hourmask = DS13xx_M_12HOUR; 382322473Sian else 383322473Sian hourmask = DS13xx_M_24HOUR; 384322473Sian 385322473Sian ct.sec = FROMBCD(tregs.sec & DS13xx_M_SECOND); 386322473Sian ct.min = FROMBCD(tregs.min & DS13xx_M_MINUTE); 387322473Sian ct.hour = FROMBCD(tregs.hour & hourmask); 388322473Sian ct.day = FROMBCD(tregs.day & DS13xx_M_DAY); 389322473Sian ct.mon = FROMBCD(tregs.month & DS13xx_M_MONTH); 390322473Sian ct.year = FROMBCD(tregs.year & DS13xx_M_YEAR); 391322473Sian ct.nsec = 0; 392322473Sian 393322473Sian if (sc->flags & SC_F_AMPM) { 394322473Sian if (ct.hour == 12) 395322473Sian ct.hour = 0; 396322473Sian if (tregs.hour & DS13xx_B_HOUR_PM) 397322473Sian ct.hour += 12; 398322473Sian } 399322473Sian 400322473Sian /* 401322473Sian * If this chip has a century bit, honor it. Otherwise let 402322473Sian * clock_ct_to_ts() infer the century from the 2-digit year. 403322473Sian */ 404322473Sian if (sc->flags & SC_F_CENTURY) 405322473Sian ct.year += (tregs.month & DS13xx_B_MONTH_CENTURY) ? 2000 : 1900; 406322473Sian 407322473Sian err = clock_ct_to_ts(&ct, ts); 408322473Sian 409322473Sian return (err); 410322473Sian} 411322473Sian 412322473Sianstatic int 413322473Siands13rtc_settime(device_t dev, struct timespec *ts) 414322473Sian{ 415322473Sian struct clocktime ct; 416322473Sian struct time_regs tregs; 417322473Sian struct ds13rtc_softc *sc; 418322473Sian int err; 419322473Sian uint8_t cflag, statreg, pmflag; 420322473Sian 421322473Sian sc = device_get_softc(dev); 422322473Sian 423322473Sian /* 424322473Sian * We request a timespec with no resolution-adjustment. That also 425322473Sian * disables utc adjustment, so apply that ourselves. 426322473Sian */ 427322473Sian ts->tv_sec -= utc_offset(); 428322473Sian 429322473Sian /* If the chip counts time in binary, store tv_sec and we're done. */ 430322473Sian if (sc->flags & SC_F_BINARY) 431322473Sian return (write_timeword(sc, ts->tv_sec)); 432322473Sian 433322473Sian clock_ts_to_ct(ts, &ct); 434322473Sian 435322473Sian /* If the chip is in AMPM mode deal with the PM flag. */ 436322473Sian pmflag = 0; 437322473Sian if (sc->flags & SC_F_AMPM) { 438322473Sian if (ct.hour >= 12) { 439322473Sian ct.hour -= 12; 440322473Sian pmflag = DS13xx_B_HOUR_PM; 441322473Sian } 442322473Sian if (ct.hour == 0) 443322473Sian ct.hour = 12; 444322473Sian } 445322473Sian 446322473Sian /* If the chip has a century bit, set it as needed. */ 447322473Sian cflag = 0; 448322473Sian if (sc->flags & SC_F_CENTURY) { 449322473Sian if (ct.year >= 2000) 450322473Sian cflag |= DS13xx_B_MONTH_CENTURY; 451322473Sian } 452322473Sian 453322473Sian tregs.sec = TOBCD(ct.sec); 454322473Sian tregs.min = TOBCD(ct.min); 455322473Sian tregs.hour = TOBCD(ct.hour) | pmflag; 456322473Sian tregs.day = TOBCD(ct.day); 457322473Sian tregs.month = TOBCD(ct.mon) | cflag; 458322473Sian tregs.year = TOBCD(ct.year % 100); 459322473Sian tregs.wday = ct.dow; 460322473Sian 461322473Sian /* 462322473Sian * Set the time. Reset the OSF bit if it is on and it is not part of 463322473Sian * the time registers (in which case writing time resets it). 464322473Sian */ 465322473Sian if ((err = write_timeregs(sc, &tregs)) != 0) 466322473Sian goto errout; 467322473Sian if (sc->osfaddr != sc->secaddr) { 468322473Sian if ((err = read_reg(sc, sc->osfaddr, &statreg)) != 0) 469322473Sian goto errout; 470322473Sian if (statreg & DS13xx_B_STATUS_OSF) { 471322473Sian statreg &= ~DS13xx_B_STATUS_OSF; 472322473Sian err = write_reg(sc, sc->osfaddr, statreg); 473322473Sian } 474322473Sian } 475322473Sian 476322473Sianerrout: 477322473Sian 478322473Sian if (err != 0) 479322473Sian device_printf(dev, "cannot update RTC time\n"); 480322473Sian 481322473Sian return (err); 482322473Sian} 483322473Sian 484322473Sianstatic int 485322473Siands13rtc_get_chiptype(device_t dev) 486322473Sian{ 487322473Sian#ifdef FDT 488322473Sian 489322473Sian return (ofw_bus_search_compatible(dev, compat_data)->ocd_data); 490322473Sian#else 491322473Sian ds13_compat_data *cdata; 492322473Sian const char *htype; 493322473Sian 494322473Sian /* 495322473Sian * We can only attach if provided a chiptype hint string. 496322473Sian */ 497322473Sian if (resource_string_value(device_get_name(dev), 498322473Sian device_get_unit(dev), "chiptype", &htype) != 0) 499322473Sian return (TYPE_NONE); 500322473Sian 501322473Sian /* 502322473Sian * Loop through the ofw compat data comparing the hinted chip type to 503322473Sian * the compat strings. 504322473Sian */ 505322473Sian for (cdata = compat_data; cdata->ocd_str != NULL; ++cdata) { 506322473Sian if (strcmp(htype, cdata->ocd_str) == 0) 507322473Sian break; 508322473Sian } 509322473Sian return (cdata->ocd_data); 510322473Sian#endif 511322473Sian} 512322473Sian 513322473Sianstatic int 514322473Siands13rtc_probe(device_t dev) 515322473Sian{ 516322473Sian int chiptype, goodrv; 517322473Sian 518322473Sian#ifdef FDT 519322473Sian if (!ofw_bus_status_okay(dev)) 520322473Sian return (ENXIO); 521322473Sian goodrv = BUS_PROBE_GENERIC; 522322473Sian#else 523322473Sian goodrv = BUS_PROBE_NOWILDCARD; 524322473Sian#endif 525322473Sian 526322473Sian chiptype = ds13rtc_get_chiptype(dev); 527322473Sian if (chiptype == TYPE_NONE) 528322473Sian return (ENXIO); 529322473Sian 530322473Sian device_set_desc(dev, desc_strings[chiptype]); 531322473Sian return (goodrv); 532322473Sian} 533322473Sian 534322473Sianstatic int 535322473Siands13rtc_attach(device_t dev) 536322473Sian{ 537322473Sian struct ds13rtc_softc *sc; 538322473Sian 539322473Sian sc = device_get_softc(dev); 540322473Sian sc->dev = dev; 541322473Sian sc->busdev = device_get_parent(dev); 542322473Sian 543322473Sian /* 544322473Sian * We need to know what kind of chip we're driving. 545322473Sian */ 546322473Sian if ((sc->chiptype = ds13rtc_get_chiptype(dev)) == TYPE_NONE) { 547322473Sian device_printf(dev, "impossible: cannot determine chip type\n"); 548322473Sian return (ENXIO); 549322473Sian } 550322473Sian 551322473Sian /* The seconds register is in the same place on all except DS1388. */ 552322473Sian if (sc->chiptype == TYPE_DS1388) 553322473Sian sc->secaddr = DS1388_R_SECOND; 554322473Sian else 555322473Sian sc->secaddr = DS13xx_R_SECOND; 556322473Sian 557322473Sian /* 558322473Sian * The OSF/CH (osc failed/clock-halted) bit appears in different 559322473Sian * registers for different chip types. The DS1375 has no OSF indicator 560322473Sian * because it has no internal oscillator; we just point to an always- 561322473Sian * zero bit in the status register for that chip. 562322473Sian */ 563322473Sian switch (sc->chiptype) { 564322473Sian case TYPE_DS1307: 565322473Sian case TYPE_DS1308: 566322473Sian case TYPE_DS1338: 567322473Sian sc->osfaddr = DS13xx_R_SECOND; 568322473Sian break; 569322473Sian case TYPE_DS1337: 570322473Sian case TYPE_DS1339: 571322473Sian case TYPE_DS1341: 572322473Sian case TYPE_DS1342: 573322473Sian case TYPE_DS1375: 574322473Sian sc->osfaddr = DS133x_R_STATUS; 575322473Sian sc->flags |= SC_F_CENTURY; 576322473Sian break; 577322473Sian case TYPE_DS1340: 578322473Sian sc->osfaddr = DS1340_R_STATUS; 579322473Sian break; 580322473Sian case TYPE_DS1371: 581322473Sian case TYPE_DS1372: 582322473Sian case TYPE_DS1374: 583322473Sian sc->osfaddr = DS137x_R_STATUS; 584322473Sian sc->flags |= SC_F_BINARY; 585322473Sian break; 586322473Sian case TYPE_DS1388: 587322473Sian sc->osfaddr = DS1388_R_STATUS; 588322473Sian break; 589322473Sian } 590322473Sian 591322473Sian /* 592322473Sian * We have to wait until interrupts are enabled. Sometimes I2C read 593322473Sian * and write only works when the interrupts are available. 594322473Sian */ 595322473Sian config_intrhook_oneshot(ds13rtc_start, sc); 596322473Sian 597322473Sian return (0); 598322473Sian} 599322473Sian 600322473Sianstatic int 601322473Siands13rtc_detach(device_t dev) 602322473Sian{ 603322473Sian 604322473Sian clock_unregister(dev); 605322473Sian return (0); 606322473Sian} 607322473Sian 608322473Sianstatic device_method_t ds13rtc_methods[] = { 609322473Sian DEVMETHOD(device_probe, ds13rtc_probe), 610322473Sian DEVMETHOD(device_attach, ds13rtc_attach), 611322473Sian DEVMETHOD(device_detach, ds13rtc_detach), 612322473Sian 613322473Sian DEVMETHOD(clock_gettime, ds13rtc_gettime), 614322473Sian DEVMETHOD(clock_settime, ds13rtc_settime), 615322473Sian 616322473Sian DEVMETHOD_END 617322473Sian}; 618322473Sian 619322473Sianstatic driver_t ds13rtc_driver = { 620322473Sian "ds13rtc", 621322473Sian ds13rtc_methods, 622322473Sian sizeof(struct ds13rtc_softc), 623322473Sian}; 624322473Sian 625322473Sianstatic devclass_t ds13rtc_devclass; 626322473Sian 627322473SianDRIVER_MODULE(ds13rtc, iicbus, ds13rtc_driver, ds13rtc_devclass, NULL, NULL); 628322473SianMODULE_VERSION(ds13rtc, 1); 629322473SianMODULE_DEPEND(ds13rtc, iicbus, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 630