1 /* $OpenBSD: ds3231.c,v 1.3 2022/10/15 18:22:53 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <dev/i2c/i2cvar.h> 23 24 #include <dev/clock_subr.h> 25 26 #define DS3231_SC 0x00 27 #define DS3231_MN 0x01 28 #define DS3231_HR 0x02 29 #define DS3231_HR_PM (1 << 5) 30 #define DS3231_HR_12 (1 << 6) 31 #define DS3231_HR_12_MASK ~(DS3231_HR_12 | DS3231_HR_PM) 32 #define DS3231_DW 0x03 33 #define DS3231_DT 0x04 34 #define DS3231_MO 0x05 35 #define DS3231_MO_MASK 0x3f 36 #define DS3231_YR 0x06 37 #define DS3231_SR 0x07 38 #define DS3231_SR_OSF (1 << 7) 39 40 #define DS3231_NRTC_REGS 7 41 42 struct dsxrtc_softc { 43 struct device sc_dev; 44 i2c_tag_t sc_tag; 45 i2c_addr_t sc_addr; 46 47 struct todr_chip_handle sc_todr; 48 }; 49 50 int dsxrtc_match(struct device *, void *, void *); 51 void dsxrtc_attach(struct device *, struct device *, void *); 52 53 const struct cfattach dsxrtc_ca = { 54 sizeof(struct dsxrtc_softc), dsxrtc_match, dsxrtc_attach 55 }; 56 57 struct cfdriver dsxrtc_cd = { 58 NULL, "dsxrtc", DV_DULL 59 }; 60 61 uint8_t dsxrtc_reg_read(struct dsxrtc_softc *, int); 62 void dsxrtc_reg_write(struct dsxrtc_softc *, int, uint8_t); 63 int dsxrtc_clock_read(struct dsxrtc_softc *, struct clock_ymdhms *); 64 int dsxrtc_clock_write(struct dsxrtc_softc *, struct clock_ymdhms *); 65 int dsxrtc_gettime(struct todr_chip_handle *, struct timeval *); 66 int dsxrtc_settime(struct todr_chip_handle *, struct timeval *); 67 68 int 69 dsxrtc_match(struct device *parent, void *match, void *aux) 70 { 71 struct i2c_attach_args *ia = aux; 72 73 if (strcmp(ia->ia_name, "maxim,ds3231") == 0 || 74 strcmp(ia->ia_name, "maxim,ds3232") == 0) 75 return 1; 76 77 return 0; 78 } 79 80 void 81 dsxrtc_attach(struct device *parent, struct device *self, void *aux) 82 { 83 struct dsxrtc_softc *sc = (struct dsxrtc_softc *)self; 84 struct i2c_attach_args *ia = aux; 85 86 sc->sc_tag = ia->ia_tag; 87 sc->sc_addr = ia->ia_addr; 88 89 sc->sc_todr.cookie = sc; 90 sc->sc_todr.todr_gettime = dsxrtc_gettime; 91 sc->sc_todr.todr_settime = dsxrtc_settime; 92 sc->sc_todr.todr_quality = 1000; 93 todr_attach(&sc->sc_todr); 94 95 printf("\n"); 96 } 97 98 int 99 dsxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 100 { 101 struct dsxrtc_softc *sc = handle->cookie; 102 struct clock_ymdhms dt; 103 int error; 104 105 error = dsxrtc_clock_read(sc, &dt); 106 if (error) 107 return error; 108 109 if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 110 dt.dt_day > 31 || dt.dt_day == 0 || 111 dt.dt_mon > 12 || dt.dt_mon == 0 || 112 dt.dt_year < POSIX_BASE_YEAR) 113 return EINVAL; 114 115 tv->tv_sec = clock_ymdhms_to_secs(&dt); 116 tv->tv_usec = 0; 117 return 0; 118 } 119 120 int 121 dsxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 122 { 123 struct dsxrtc_softc *sc = handle->cookie; 124 struct clock_ymdhms dt; 125 126 clock_secs_to_ymdhms(tv->tv_sec, &dt); 127 128 return dsxrtc_clock_write(sc, &dt); 129 130 } 131 132 uint8_t 133 dsxrtc_reg_read(struct dsxrtc_softc *sc, int reg) 134 { 135 uint8_t cmd = reg; 136 uint8_t val; 137 int error; 138 139 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 140 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 141 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 142 iic_release_bus(sc->sc_tag, I2C_F_POLL); 143 144 if (error) { 145 printf("%s: can't read register 0x%02x\n", 146 sc->sc_dev.dv_xname, reg); 147 val = 0xff; 148 } 149 150 return val; 151 } 152 153 void 154 dsxrtc_reg_write(struct dsxrtc_softc *sc, int reg, uint8_t val) 155 { 156 uint8_t cmd = reg; 157 int error; 158 159 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 160 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 161 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 162 iic_release_bus(sc->sc_tag, I2C_F_POLL); 163 164 if (error) { 165 printf("%s: can't write register 0x%02x\n", 166 sc->sc_dev.dv_xname, reg); 167 } 168 } 169 170 int 171 dsxrtc_clock_read(struct dsxrtc_softc *sc, struct clock_ymdhms *dt) 172 { 173 uint8_t regs[DS3231_NRTC_REGS]; 174 uint8_t cmd = DS3231_SC; 175 uint8_t status; 176 int error; 177 178 /* Consider the time to be invalid if the OSF bit is set. */ 179 status = dsxrtc_reg_read(sc, DS3231_SR); 180 if (status & DS3231_SR_OSF) 181 return EINVAL; 182 183 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 184 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 185 &cmd, sizeof(cmd), regs, DS3231_NRTC_REGS, I2C_F_POLL); 186 iic_release_bus(sc->sc_tag, I2C_F_POLL); 187 188 if (error) { 189 printf("%s: can't read RTC\n", sc->sc_dev.dv_xname); 190 return error; 191 } 192 193 /* 194 * Convert the DS3231's register values into something useable. 195 */ 196 dt->dt_sec = FROMBCD(regs[0]); 197 dt->dt_min = FROMBCD(regs[1]); 198 if (regs[2] & DS3231_HR_12) { 199 dt->dt_hour = FROMBCD(regs[2] & DS3231_HR_12_MASK); 200 if (regs[2] & DS3231_HR_PM) 201 dt->dt_hour += 12; 202 } else { 203 dt->dt_hour = FROMBCD(regs[2]); 204 } 205 dt->dt_day = FROMBCD(regs[4]); 206 dt->dt_mon = FROMBCD(regs[5] & DS3231_MO_MASK); 207 dt->dt_year = FROMBCD(regs[6]) + 2000; 208 209 return 0; 210 } 211 212 int 213 dsxrtc_clock_write(struct dsxrtc_softc *sc, struct clock_ymdhms *dt) 214 { 215 uint8_t regs[DS3231_NRTC_REGS]; 216 uint8_t cmd = DS3231_SC; 217 uint8_t status; 218 int error; 219 220 /* 221 * Convert our time representation into something the DS3231 222 * can understand. 223 */ 224 regs[0] = TOBCD(dt->dt_sec); 225 regs[1] = TOBCD(dt->dt_min); 226 regs[2] = TOBCD(dt->dt_hour); 227 regs[3] = TOBCD(dt->dt_wday + 1); 228 regs[4] = TOBCD(dt->dt_day); 229 regs[5] = TOBCD(dt->dt_mon); 230 regs[6] = TOBCD(dt->dt_year - 2000); 231 232 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 233 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 234 &cmd, sizeof(cmd), regs, DS3231_NRTC_REGS, I2C_F_POLL); 235 iic_release_bus(sc->sc_tag, I2C_F_POLL); 236 237 if (error) { 238 printf("%s: can't write RTC\n", sc->sc_dev.dv_xname); 239 return error; 240 } 241 242 /* Clear OSF flag. */ 243 status = dsxrtc_reg_read(sc, DS3231_SR); 244 dsxrtc_reg_write(sc, DS3231_SR, status & ~DS3231_SR_OSF); 245 246 return 0; 247 } 248