diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 88f20e6..e3255b7 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2518,10 +2518,10 @@ device iicsmb # smb over i2c bridge # I2C peripheral devices # -# ds133x Dallas Semiconductor DS1337, DS1338 and DS1339 RTC +# ds13xx Dallas Semiconductor DS1337, DS1338, DS1339 and DS1388 RTC # ds1672 Dallas Semiconductor DS1672 RTC # -device ds133x +device ds13xx device ds1672 # Parallel-Port Bus diff --git a/sys/conf/files b/sys/conf/files index ff2335f..4deb3c6 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1128,7 +1128,7 @@ dev/ieee488/pcii.c optional pcii dev/ieee488/tnt4882.c optional tnt4882 dev/ieee488/upd7210.c optional pcii | tnt4882 dev/iicbus/ad7418.c optional ad7418 -dev/iicbus/ds133x.c optional ds133x +dev/iicbus/ds13xx.c optional ds13xx dev/iicbus/ds1672.c optional ds1672 dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic diff --git a/sys/dev/iicbus/ds133x.c b/sys/dev/iicbus/ds133x.c deleted file mode 100644 index 0808405..0000000 --- a/sys/dev/iicbus/ds133x.c +++ /dev/null @@ -1,363 +0,0 @@ -/*- - * Copyright (c) 2008 Stanislav Sedov , - * Rafal Jaworowski , - * Piotr Ziecik . - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD: src/sys/dev/iicbus/ds133x.c,v 1.5 2009/04/21 22:48:12 stas Exp $"); -/* - * Dallas Semiconductor DS133X RTC sitting on the I2C bus. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "iicbus_if.h" -#include "clock_if.h" - -#define DS133X_DEVNAME "ds133x_rtc" - -#define DS133X_ADDR 0xd0 /* slave address */ -#define DS133X_DATE_REG 0x0 -#define DS133X_CTRL_REG 0x0e -#define DS133X_OSCD_FLAG 0x80 -#define DS133X_OSF_FLAG 0x80 - -#define DS133X_24H_FLAG 0x40 /* 24 hours mode. */ -#define DS133X_PM_FLAG 0x20 /* AM/PM bit. */ -#define DS133X_CENT_FLAG 0x80 /* Century selector. */ -#define DS133X_CENT_SHIFT 7 - -#define DS1338_REG_CLOCK_HALT 0x00 -#define DS1338_REG_CONTROL 0x07 -#define DS1338_CLOCK_HALT (1 << 7) -#define DS1338_OSC_STOP (1 << 5) - -#define DS1339_REG_CONTROL 0x0E -#define DS1339_REG_STATUS 0x0F -#define DS1339_OSC_STOP (1 << 7) -#define DS1339_ENABLE_OSC (1 << 7) -#define DS1339_BBSQI (1 << 5) - -#define HALFSEC 500000000 /* 1/2 of second. */ - -#define MAX_IIC_DATA_SIZE 7 - -enum { - DS1337, - DS1338, - DS1339, -}; - -struct ds133x_softc { - int sc_type; - device_t sc_dev; -}; - -static int -ds133x_read(device_t dev, uint8_t address, uint8_t *data, uint8_t size) -{ - struct iic_msg msg[] = { - { DS133X_ADDR, IIC_M_WR, 1, &address }, - { DS133X_ADDR, IIC_M_RD, size, data }, - }; - - return (iicbus_transfer(dev, msg, 2)); -} - -static int -ds133x_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size) -{ - uint8_t buffer[MAX_IIC_DATA_SIZE + 1]; - struct iic_msg msg[] = { - { DS133X_ADDR, IIC_M_WR, size + 1, buffer }, - }; - - if (size > MAX_IIC_DATA_SIZE) - return (ENOMEM); - - buffer[0] = address; - memcpy(buffer + 1, data, size); - - return (iicbus_transfer(dev, msg, 1)); -} - -static int -ds133x_detect(device_t dev, int *sc_type) -{ - int error; - uint8_t reg, orig; - - /* - * Check for DS1338. At address 0x0F this chip has RAM, however - * DS1337 and DS1339 have status register. Bits 6-2 in status - * register will be always read as 0. - */ - - if ((error = ds133x_read(dev, DS1339_REG_STATUS, ®, 1))) - return (error); - - orig = reg; - reg |= 0x7C; - - if ((error = ds133x_write(dev, DS1339_REG_STATUS, ®, 1))) - return (error); - - if ((error = ds133x_read(dev, DS1339_REG_STATUS, ®, 1))) - return (error); - - if ((reg & 0x7C) != 0) { - /* This is DS1338 */ - - if ((error = ds133x_write(dev, DS1339_REG_STATUS, &orig, 1))) - return (error); - - *sc_type = DS1338; - - return (0); - } - - /* - * Now Check for DS1337. Bit 5 in control register of this chip will be - * allways read as 0. In DS1339 changing of this bit is safe until - * chip is powered up. - */ - - if ((error = ds133x_read(dev, DS1339_REG_CONTROL, ®, 1))) - return (error); - - orig = reg; - reg |= DS1339_BBSQI; - - if ((error = ds133x_write(dev, DS1339_REG_CONTROL, ®, 1))) - return (error); - - if ((error = ds133x_read(dev, DS1339_REG_CONTROL, ®, 1))) - return (error); - - if ((reg & DS1339_BBSQI) != 0) { - /* This is DS1339 */ - - if ((error = ds133x_write(dev, DS1339_REG_CONTROL, &orig, 1))) - return (error); - - *sc_type = DS1339; - return (0); - } - - /* This is DS1337 */ - *sc_type = DS1337; - - return (0); -} - -static int -ds133x_init(device_t dev, uint8_t cs_reg, uint8_t cs_bit, uint8_t osf_reg, - uint8_t osf_bit) -{ - int error; - uint8_t reg; - - if ((error = ds133x_read(dev, cs_reg, ®, 1))) - return (error); - - if (reg & cs_bit) { /* If clock is stopped - start it */ - reg &= ~cs_bit; - if ((error = ds133x_write(dev, cs_reg, ®, 1))) - return (error); - } - - if ((error = ds133x_read(dev, osf_reg, ®, 1))) - return (error); - - if (reg & osf_bit) { /* Clear oscillator stop flag */ - device_printf(dev, "RTC oscillator was stopped. Check system" - " time and RTC battery.\n"); - reg &= ~osf_bit; - if ((error = ds133x_write(dev, osf_reg, ®, 1))) - return (error); - } - - return (0); -} - - -static void -ds133x_identify(driver_t *driver, device_t parent) -{ - - if (device_find_child(parent, DS133X_DEVNAME, -1) == NULL) - BUS_ADD_CHILD(parent, 0, DS133X_DEVNAME, -1); -} - -static int -ds133x_probe(device_t dev) -{ - struct ds133x_softc *sc; - int error; - - sc = device_get_softc(dev); - - if ((error = ds133x_detect(dev, &sc->sc_type))) - return (error); - - switch (sc->sc_type) { - case DS1337: - device_set_desc(dev, "Dallas Semiconductor DS1337 RTC"); - break; - case DS1338: - device_set_desc(dev, "Dallas Semiconductor DS1338 RTC"); - break; - case DS1339: - device_set_desc(dev, "Dallas Semiconductor DS1339 RTC"); - break; - default: - break; - } - - return (0); -} - -static int -ds133x_attach(device_t dev) -{ - struct ds133x_softc *sc = device_get_softc(dev); - - sc->sc_dev = dev; - - if (sc->sc_type == DS1338) - ds133x_init(dev, DS1338_REG_CLOCK_HALT, DS1338_CLOCK_HALT, - DS1338_REG_CONTROL, DS1338_OSC_STOP); - else - ds133x_init(dev, DS1339_REG_CONTROL, DS1339_ENABLE_OSC, - DS1339_REG_STATUS, DS1339_OSC_STOP); - - clock_register(dev, 1000000); - - return (0); -} - -static uint8_t -ds133x_get_hours(uint8_t val) -{ - uint8_t ret; - - if (!(val & DS133X_24H_FLAG)) - ret = FROMBCD(val & 0x3f); - else if (!(val & DS133X_PM_FLAG)) - ret = FROMBCD(val & 0x1f); - else - ret = FROMBCD(val & 0x1f) + 12; - - return (ret); -} - -static int -ds133x_gettime(device_t dev, struct timespec *ts) -{ - struct ds133x_softc *sc = device_get_softc(dev); - struct clocktime ct; - uint8_t date[7]; - int error; - - error = ds133x_read(dev, DS133X_DATE_REG, date, 7); - if (error == 0) { - ct.nsec = 0; - ct.sec = FROMBCD(date[0] & 0x7f); - ct.min = FROMBCD(date[1] & 0x7f); - ct.hour = ds133x_get_hours(date[2]); - ct.dow = FROMBCD(date[3] & 0x07) - 1; - ct.day = FROMBCD(date[4] & 0x3f); - ct.mon = FROMBCD(date[5] & 0x1f); - - if (sc->sc_type == DS1338) - ct.year = 2000 + FROMBCD(date[6]); - else - ct.year = 1900 + FROMBCD(date[6]) + - ((date[5] & DS133X_CENT_FLAG) >> DS133X_CENT_SHIFT) * 100; - - error = clock_ct_to_ts(&ct, ts); - } - - return (error); -} - -static int -ds133x_settime(device_t dev, struct timespec *ts) -{ - struct ds133x_softc *sc = device_get_softc(dev); - struct clocktime ct; - uint8_t date[7]; - - clock_ts_to_ct(ts, &ct); - - date[0] = TOBCD(ct.nsec >= HALFSEC ? ct.sec + 1 : ct.sec) & 0x7f; - date[1] = TOBCD(ct.min) & 0x7f; - date[2] = TOBCD(ct.hour) & 0x3f; /* We use 24-hours mode. */ - date[3] = TOBCD(ct.dow + 1) & 0x07; - date[4] = TOBCD(ct.day) & 0x3f; - date[5] = TOBCD(ct.mon) & 0x1f; - if (sc->sc_type == DS1338) - date[6] = TOBCD(ct.year - 2000); - else if (ct.year >= 2000) { - date[5] |= DS133X_CENT_FLAG; - date[6] = TOBCD(ct.year - 2000); - } else - date[6] = TOBCD(ct.year - 1900); - - return (ds133x_write(dev, DS133X_DATE_REG, date, 7)); -} - -static device_method_t ds133x_methods[] = { - DEVMETHOD(device_identify, ds133x_identify), - DEVMETHOD(device_probe, ds133x_probe), - DEVMETHOD(device_attach, ds133x_attach), - - DEVMETHOD(clock_gettime, ds133x_gettime), - DEVMETHOD(clock_settime, ds133x_settime), - - {0, 0}, -}; - -static driver_t ds133x_driver = { - DS133X_DEVNAME, - ds133x_methods, - sizeof(struct ds133x_softc), -}; - -static devclass_t ds133x_devclass; - -DRIVER_MODULE(ds133x, iicbus, ds133x_driver, ds133x_devclass, 0, 0); -MODULE_VERSION(ds133x, 1); -MODULE_DEPEND(ds133x, iicbus, 1, 1, 1); diff --git a/sys/dev/iicbus/ds13xx.c b/sys/dev/iicbus/ds13xx.c new file mode 100644 index 0000000..9f0b01f --- /dev/null +++ b/sys/dev/iicbus/ds13xx.c @@ -0,0 +1,422 @@ +/*- + * Copyright (c) 2008 Stanislav Sedov , + * Rafal Jaworowski , + * Piotr Ziecik . + * Copyright (c) 2010 Semihalf, Michal Mazur + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Dallas Semiconductor DS13XX RTC sitting on the I2C bus. + */ +#include +__FBSDID("$FreeBSD: src/sys/dev/iicbus/ds133x.c,v 1.5 2009/04/21 22:48:12 stas Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "iicbus_if.h" +#include "clock_if.h" + +#define DS13XX_DEVNAME "ds13xx_rtc" + +#define DS13XX_ADDR 0xd0 /* slave address */ +#define DS13XX_DATE_REG 0x0 +#define DS13XX_CTRL_REG 0x0e +#define DS13XX_OSCD_FLAG 0x80 +#define DS13XX_OSF_FLAG 0x80 + +#define DS13XX_24H_FLAG 0x40 /* 24 hours mode. */ +#define DS13XX_PM_FLAG 0x20 /* AM/PM bit. */ +#define DS13XX_CENT_FLAG 0x80 /* Century selector. */ +#define DS13XX_CENT_SHIFT 7 + +#define DS1338_REG_CLOCK_HALT 0x00 +#define DS1338_REG_CONTROL 0x07 +#define DS1338_CLOCK_HALT (1 << 7) +#define DS1338_OSC_STOP (1 << 5) + +#define DS1339_REG_CONTROL 0x0E +#define DS1339_REG_STATUS 0x0F +#define DS1339_OSC_STOP (1 << 7) +#define DS1339_ENABLE_OSC (1 << 7) +#define DS1339_BBSQI (1 << 5) + +#define DS1388_REG_CONTROL 0x0C +#define DS1388_REG_FLAG 0x0B +#define DS1388_ENABLE_OSC (1 << 7) +#define DS1388_OSC_STOP (1 << 7) +#define DS1388_DATE_REG 0x1 + +#define DS13XX_DESC "Dallas Semiconductor DS13" + +#define HALFSEC 500000000 /* 1/2 of second. */ + +#define MAX_IIC_DATA_SIZE 7 + +enum { + DS1337, + DS1338, + DS1339, + DS1388, +}; + +struct ds13xx_softc { + int sc_type; + device_t sc_dev; + uint8_t date_reg; +}; + +static int +ds13xx_read(device_t dev, uint8_t address, uint8_t *data, uint8_t size) +{ + struct iic_msg msg[] = { + { DS13XX_ADDR, IIC_M_WR, 1, &address }, + { DS13XX_ADDR, IIC_M_RD, size, data }, + }; + + return (iicbus_transfer(dev, msg, 2)); +} + +static int +ds13xx_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size) +{ + uint8_t buffer[MAX_IIC_DATA_SIZE + 1]; + struct iic_msg msg[] = { + { DS13XX_ADDR, IIC_M_WR, size + 1, buffer }, + }; + + if (size > MAX_IIC_DATA_SIZE) + return (ENOMEM); + + buffer[0] = address; + memcpy(buffer + 1, data, size); + + return (iicbus_transfer(dev, msg, 1)); +} + +static int +ds13xx_detect(device_t dev, int *sc_type) +{ + int error; + uint8_t reg, orig; + + /* + * Try a simple heuristics to identify the DS133x / DS1388 chip type. + * + * The DS1338 has internal RAM at address 0x0F, however DS1337 and + * DS1339 have status register at this offset. Bits 6-2 in status + * register will be always read as 0. + * + * DS1388 does not have any registers at 0x0F so read attempt will + * cause error. + */ + + if (ds13xx_read(dev, DS1339_REG_STATUS, ®, 1)) { + /* + * Check for DS1388. Control register of this chip is at + * address 0x0C and bits 6-2 always reads as 0. + * Status register is at 0x0B and bits 5-0 are always 0. + */ + if ((error = ds13xx_read(dev, DS1388_REG_CONTROL, ®, 1))) + return (error); + if (reg & 0x7C) + return (-1); + + if ((error = ds13xx_read(dev, DS1388_REG_FLAG, ®, 1))) + return (error); + if (reg & 0x3F) + return (-1); + + *sc_type = DS1388; + + return (0); + } + + orig = reg; + reg |= 0x7C; + + if ((error = ds13xx_write(dev, DS1339_REG_STATUS, ®, 1))) + return (error); + + if ((error = ds13xx_read(dev, DS1339_REG_STATUS, ®, 1))) + return (error); + + if ((reg & 0x7C) != 0) { + /* This is DS1338 */ + + if ((error = ds13xx_write(dev, DS1339_REG_STATUS, &orig, 1))) + return (error); + + *sc_type = DS1338; + + return (0); + } + + /* + * Now Check for DS1337. Bit 5 in control register of this chip will be + * allways read as 0. In DS1339 changing of this bit is safe until + * chip is powered up. + */ + + if ((error = ds13xx_read(dev, DS1339_REG_CONTROL, ®, 1))) + return (error); + + orig = reg; + reg |= DS1339_BBSQI; + + if ((error = ds13xx_write(dev, DS1339_REG_CONTROL, ®, 1))) + return (error); + + if ((error = ds13xx_read(dev, DS1339_REG_CONTROL, ®, 1))) + return (error); + + if ((reg & DS1339_BBSQI) != 0) { + /* This is DS1339 */ + + if ((error = ds13xx_write(dev, DS1339_REG_CONTROL, &orig, 1))) + return (error); + + *sc_type = DS1339; + return (0); + } + + /* This is DS1337 */ + *sc_type = DS1337; + + return (0); +} + +static int +ds13xx_init(device_t dev, uint8_t cs_reg, uint8_t cs_bit, uint8_t osf_reg, + uint8_t osf_bit) +{ + int error; + uint8_t reg; + + if ((error = ds13xx_read(dev, cs_reg, ®, 1))) + return (error); + + if (reg & cs_bit) { /* If clock is stopped - start it */ + reg &= ~cs_bit; + if ((error = ds13xx_write(dev, cs_reg, ®, 1))) + return (error); + } + + if ((error = ds13xx_read(dev, osf_reg, ®, 1))) + return (error); + + if (reg & osf_bit) { /* Clear oscillator stop flag */ + device_printf(dev, "RTC oscillator was stopped. Check system" + " time and RTC battery.\n"); + reg &= ~osf_bit; + if ((error = ds13xx_write(dev, osf_reg, ®, 1))) + return (error); + } + + return (0); +} + + +static void +ds13xx_identify(driver_t *driver, device_t parent) +{ + + if (device_find_child(parent, DS13XX_DEVNAME, -1) == NULL) + BUS_ADD_CHILD(parent, 0, DS13XX_DEVNAME, -1); +} + +static int +ds13xx_probe(device_t dev) +{ + struct ds13xx_softc *sc; + int error; + + sc = device_get_softc(dev); + + if ((error = ds13xx_detect(dev, &sc->sc_type))) + return (error); + + switch (sc->sc_type) { + case DS1337: + device_set_desc(dev, DS13XX_DESC "37 RTC"); + break; + case DS1338: + device_set_desc(dev, DS13XX_DESC "38 RTC"); + break; + case DS1339: + device_set_desc(dev, DS13XX_DESC "39 RTC"); + break; + case DS1388: + device_set_desc(dev, DS13XX_DESC "88 RTC"); + break; + default: + break; + } + + return (0); +} + +static int +ds13xx_attach(device_t dev) +{ + struct ds13xx_softc *sc = device_get_softc(dev); + + sc->sc_dev = dev; + sc->date_reg = DS13XX_DATE_REG; + + switch (sc->sc_type) { + case DS1338: + ds13xx_init(dev, DS1338_REG_CLOCK_HALT, DS1338_CLOCK_HALT, + DS1338_REG_CONTROL, DS1338_OSC_STOP); + break; + case DS1388: + sc->date_reg = DS1388_DATE_REG; + ds13xx_init(dev, DS1388_REG_CONTROL, DS1388_ENABLE_OSC, + DS1388_REG_FLAG, DS1388_OSC_STOP); + break; + default: + ds13xx_init(dev, DS1339_REG_CONTROL, DS1339_ENABLE_OSC, + DS1339_REG_STATUS, DS1339_OSC_STOP); + break; + } + + clock_register(dev, 1000000); + + return (0); +} + +static uint8_t +ds13xx_get_hours(uint8_t val) +{ + uint8_t ret; + + if (!(val & DS13XX_24H_FLAG)) + ret = FROMBCD(val & 0x3f); + else if (!(val & DS13XX_PM_FLAG)) + ret = FROMBCD(val & 0x1f); + else + ret = FROMBCD(val & 0x1f) + 12; + + return (ret); +} + +static int +ds13xx_gettime(device_t dev, struct timespec *ts) +{ + struct ds13xx_softc *sc = device_get_softc(dev); + struct clocktime ct; + uint8_t date[7]; + int error; + + error = ds13xx_read(dev, sc->date_reg, date, 7); + if (error == 0) { + ct.nsec = 0; + ct.sec = FROMBCD(date[0] & 0x7f); + ct.min = FROMBCD(date[1] & 0x7f); + ct.hour = ds13xx_get_hours(date[2]); + ct.dow = FROMBCD(date[3] & 0x07) - 1; + ct.day = FROMBCD(date[4] & 0x3f); + ct.mon = FROMBCD(date[5] & 0x1f); + + switch (sc->sc_type) { + case DS1338: + case DS1388: + ct.year = 2000 + FROMBCD(date[6]); + break; + default: + ct.year = 1900 + FROMBCD(date[6]) + + ((date[5] & DS13XX_CENT_FLAG) >> DS13XX_CENT_SHIFT) * 100; + break; + } + + error = clock_ct_to_ts(&ct, ts); + } + + return (error); +} + +static int +ds13xx_settime(device_t dev, struct timespec *ts) +{ + struct ds13xx_softc *sc = device_get_softc(dev); + struct clocktime ct; + uint8_t date[7]; + + clock_ts_to_ct(ts, &ct); + + date[0] = TOBCD(ct.nsec >= HALFSEC ? ct.sec + 1 : ct.sec) & 0x7f; + date[1] = TOBCD(ct.min) & 0x7f; + date[2] = TOBCD(ct.hour) & 0x3f; /* We use 24-hours mode. */ + date[3] = TOBCD(ct.dow + 1) & 0x07; + date[4] = TOBCD(ct.day) & 0x3f; + date[5] = TOBCD(ct.mon) & 0x1f; + switch (sc->sc_type) { + case DS1338: + case DS1388: + date[6] = TOBCD(ct.year - 2000); + break; + default: + if (ct.year >= 2000) { + date[5] |= DS13XX_CENT_FLAG; + date[6] = TOBCD(ct.year - 2000); + } else + date[6] = TOBCD(ct.year - 1900); + break; + } + + return (ds13xx_write(dev, sc->date_reg, date, 7)); +} + +static device_method_t ds13xx_methods[] = { + DEVMETHOD(device_identify, ds13xx_identify), + DEVMETHOD(device_probe, ds13xx_probe), + DEVMETHOD(device_attach, ds13xx_attach), + + DEVMETHOD(clock_gettime, ds13xx_gettime), + DEVMETHOD(clock_settime, ds13xx_settime), + + {0, 0}, +}; + +static driver_t ds13xx_driver = { + DS13XX_DEVNAME, + ds13xx_methods, + sizeof(struct ds13xx_softc), +}; + +static devclass_t ds13xx_devclass; + +DRIVER_MODULE(ds13xx, iicbus, ds13xx_driver, ds13xx_devclass, 0, 0); +MODULE_VERSION(ds13xx, 1); +MODULE_DEPEND(ds13xx, iicbus, 1, 1, 1);