1 /* $OpenBSD: ds3231.c,v 1.1 2020/04/25 15:10:52 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 extern todr_chip_handle_t todr_handle; 27 28 #define DS3231_SC 0x00 29 #define DS3231_MN 0x01 30 #define DS3231_HR 0x02 31 #define DS3231_HR_PM (1 << 5) 32 #define DS3231_HR_12 (1 << 6) 33 #define DS3231_HR_12_MASK ~(DS3231_HR_12 | DS3231_HR_PM) 34 #define DS3231_DW 0x03 35 #define DS3231_DT 0x04 36 #define DS3231_MO 0x05 37 #define DS3231_MO_MASK 0x3f 38 #define DS3231_YR 0x06 39 #define DS3231_SR 0x07 40 #define DS3231_SR_OSF (1 << 7) 41 42 #define DS3231_NRTC_REGS 7 43 44 struct dsxrtc_softc { 45 struct device sc_dev; 46 i2c_tag_t sc_tag; 47 i2c_addr_t sc_addr; 48 49 struct todr_chip_handle sc_todr; 50 }; 51 52 int dsxrtc_match(struct device *, void *, void *); 53 void dsxrtc_attach(struct device *, struct device *, void *); 54 55 struct cfattach dsxrtc_ca = { 56 sizeof(struct dsxrtc_softc), dsxrtc_match, dsxrtc_attach 57 }; 58 59 struct cfdriver dsxrtc_cd = { 60 NULL, "dsxrtc", DV_DULL 61 }; 62 63 uint8_t dsxrtc_reg_read(struct dsxrtc_softc *, int); 64 void dsxrtc_reg_write(struct dsxrtc_softc *, int, uint8_t); 65 int dsxrtc_clock_read(struct dsxrtc_softc *, struct clock_ymdhms *); 66 int dsxrtc_clock_write(struct dsxrtc_softc *, struct clock_ymdhms *); 67 int dsxrtc_gettime(struct todr_chip_handle *, struct timeval *); 68 int dsxrtc_settime(struct todr_chip_handle *, struct timeval *); 69 70 int 71 dsxrtc_match(struct device *parent, void *match, void *aux) 72 { 73 struct i2c_attach_args *ia = aux; 74 75 if (strcmp(ia->ia_name, "maxim,ds3231") == 0 || 76 strcmp(ia->ia_name, "maxim,ds3232") == 0) 77 return 1; 78 79 return 0; 80 } 81 82 void 83 dsxrtc_attach(struct device *parent, struct device *self, void *aux) 84 { 85 struct dsxrtc_softc *sc = (struct dsxrtc_softc *)self; 86 struct i2c_attach_args *ia = aux; 87 88 sc->sc_tag = ia->ia_tag; 89 sc->sc_addr = ia->ia_addr; 90 91 sc->sc_todr.cookie = sc; 92 sc->sc_todr.todr_gettime = dsxrtc_gettime; 93 sc->sc_todr.todr_settime = dsxrtc_settime; 94 todr_handle = &sc->sc_todr; 95 96 printf("\n"); 97 } 98 99 int 100 dsxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 101 { 102 struct dsxrtc_softc *sc = handle->cookie; 103 struct clock_ymdhms dt; 104 int error; 105 106 error = dsxrtc_clock_read(sc, &dt); 107 if (error) 108 return error; 109 110 if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || 111 dt.dt_day > 31 || dt.dt_day == 0 || 112 dt.dt_mon > 12 || dt.dt_mon == 0 || 113 dt.dt_year < POSIX_BASE_YEAR) 114 return EINVAL; 115 116 tv->tv_sec = clock_ymdhms_to_secs(&dt); 117 tv->tv_usec = 0; 118 return 0; 119 } 120 121 int 122 dsxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 123 { 124 struct dsxrtc_softc *sc = handle->cookie; 125 struct clock_ymdhms dt; 126 127 clock_secs_to_ymdhms(tv->tv_sec, &dt); 128 129 return dsxrtc_clock_write(sc, &dt); 130 131 } 132 133 uint8_t 134 dsxrtc_reg_read(struct dsxrtc_softc *sc, int reg) 135 { 136 uint8_t cmd = reg; 137 uint8_t val; 138 int error; 139 140 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 141 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 142 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 143 iic_release_bus(sc->sc_tag, I2C_F_POLL); 144 145 if (error) { 146 printf("%s: can't read register 0x%02x\n", 147 sc->sc_dev.dv_xname, reg); 148 val = 0xff; 149 } 150 151 return val; 152 } 153 154 void 155 dsxrtc_reg_write(struct dsxrtc_softc *sc, int reg, uint8_t val) 156 { 157 uint8_t cmd = reg; 158 int error; 159 160 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 161 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 162 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 163 iic_release_bus(sc->sc_tag, I2C_F_POLL); 164 165 if (error) { 166 printf("%s: can't write register 0x%02x\n", 167 sc->sc_dev.dv_xname, reg); 168 } 169 } 170 171 int 172 dsxrtc_clock_read(struct dsxrtc_softc *sc, struct clock_ymdhms *dt) 173 { 174 uint8_t regs[DS3231_NRTC_REGS]; 175 uint8_t cmd = DS3231_SC; 176 uint8_t status; 177 int error; 178 179 /* Consider the time to be invalid if the OSF bit is set. */ 180 status = dsxrtc_reg_read(sc, DS3231_SR); 181 if (status & DS3231_SR_OSF) 182 return EINVAL; 183 184 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 185 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 186 &cmd, sizeof(cmd), regs, DS3231_NRTC_REGS, I2C_F_POLL); 187 iic_release_bus(sc->sc_tag, I2C_F_POLL); 188 189 if (error) { 190 printf("%s: can't read RTC\n", sc->sc_dev.dv_xname); 191 return error; 192 } 193 194 /* 195 * Convert the DS3231's register values into something useable. 196 */ 197 dt->dt_sec = FROMBCD(regs[0]); 198 dt->dt_min = FROMBCD(regs[1]); 199 if (regs[2] & DS3231_HR_12) { 200 dt->dt_hour = FROMBCD(regs[2] & DS3231_HR_12_MASK); 201 if (regs[2] & DS3231_HR_PM) 202 dt->dt_hour += 12; 203 } else { 204 dt->dt_hour = FROMBCD(regs[2]); 205 } 206 dt->dt_day = FROMBCD(regs[4]); 207 dt->dt_mon = FROMBCD(regs[5] & DS3231_MO_MASK); 208 dt->dt_year = FROMBCD(regs[6]) + 2000; 209 210 return 0; 211 } 212 213 int 214 dsxrtc_clock_write(struct dsxrtc_softc *sc, struct clock_ymdhms *dt) 215 { 216 uint8_t regs[DS3231_NRTC_REGS]; 217 uint8_t cmd = DS3231_SC; 218 uint8_t status; 219 int error; 220 221 /* 222 * Convert our time representation into something the DS3231 223 * can understand. 224 */ 225 regs[0] = TOBCD(dt->dt_sec); 226 regs[1] = TOBCD(dt->dt_min); 227 regs[2] = TOBCD(dt->dt_hour); 228 regs[3] = TOBCD(dt->dt_wday + 1); 229 regs[4] = TOBCD(dt->dt_day); 230 regs[5] = TOBCD(dt->dt_mon); 231 regs[6] = TOBCD(dt->dt_year - 2000); 232 233 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 234 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 235 &cmd, sizeof(cmd), regs, DS3231_NRTC_REGS, I2C_F_POLL); 236 iic_release_bus(sc->sc_tag, I2C_F_POLL); 237 238 if (error) { 239 printf("%s: can't write RTC\n", sc->sc_dev.dv_xname); 240 return error; 241 } 242 243 /* Clear OSF flag. */ 244 status = dsxrtc_reg_read(sc, DS3231_SR); 245 dsxrtc_reg_write(sc, DS3231_SR, status & ~DS3231_SR_OSF); 246 247 return 0; 248 } 249