1 /* $OpenBSD: ds1307.c,v 1.8 2022/10/20 10:35:35 mglocker Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 23 #include <dev/clock_subr.h> 24 #include <dev/i2c/i2cvar.h> 25 26 /* 27 * Defines. 28 */ 29 /* RTC Registers */ 30 #define DS1307_SEC_REG 0x00 31 #define DS1307_SEC_MASK 0x7f 32 #define DS1307_SEC_MASK_CH 0x80 /* Clock Halt bit */ 33 #define DS1307_SEC_BIT_CH 7 /* 0 = osc enabled, 1 = osc disabled */ 34 #define DS1307_MIN_REG 0x01 35 #define DS1307_MIN_MASK 0x7f 36 #define DS1307_HOUR_REG 0x02 37 #define DS1307_HOUR_MASK 0x3f 38 #define DS1307_HOUR_MASK_MODE 0x40 /* Hour Mode bit */ 39 #define DS1307_HOUR_BIT_MODE 6 /* 0 = 24h mode, 1 = 12h mode */ 40 #define DS1307_WDAY_REG 0x03 41 #define DS1307_WDAY_MASK 0x07 42 #define DS1307_DATE_REG 0x04 43 #define DS1307_DATE_MASK 0x3f 44 #define DS1307_MONTH_REG 0x05 45 #define DS1307_MONTH_MASK 0x1f 46 #define DS1307_YEAR_REG 0x06 47 #define DS1307_YEAR_MASK 0xff 48 #define DS1307_CTRL_REG 0x07 49 50 /* RAM Registers */ 51 #define DS1307_RAM_REG 0x08 /* RAM address space 0x08 - 0x3f */ 52 53 /* 54 * Driver structure. 55 */ 56 struct maxrtc_softc { 57 struct device sc_dev; 58 i2c_tag_t sc_tag; 59 int sc_addr; 60 struct todr_chip_handle sc_todr; 61 }; 62 63 /* 64 * Prototypes. 65 */ 66 int maxrtc_match(struct device *, void *, void *); 67 void maxrtc_attach(struct device *, struct device *, void *); 68 int maxrtc_read(struct maxrtc_softc *, uint8_t *, uint8_t, 69 uint8_t *, uint8_t); 70 int maxrtc_write(struct maxrtc_softc *, uint8_t *, uint8_t); 71 int maxrtc_enable_osc(struct maxrtc_softc *); 72 int maxrtc_set_24h_mode(struct maxrtc_softc *); 73 int maxrtc_gettime(struct todr_chip_handle *, struct timeval *); 74 int maxrtc_settime(struct todr_chip_handle *, struct timeval *); 75 76 /* 77 * Driver glue structures. 78 */ 79 const struct cfattach maxrtc_ca = { 80 sizeof(struct maxrtc_softc), maxrtc_match, maxrtc_attach 81 }; 82 83 struct cfdriver maxrtc_cd = { 84 NULL, "maxrtc", DV_DULL 85 }; 86 87 /* 88 * Functions. 89 */ 90 int 91 maxrtc_match(struct device *parent, void *v, void *arg) 92 { 93 struct i2c_attach_args *ia = arg; 94 95 if (strcmp(ia->ia_name, "dallas,ds1307") == 0 || 96 strcmp(ia->ia_name, "ds1307") == 0 || 97 strcmp(ia->ia_name, "dallas,ds1339") == 0) 98 return (1); 99 100 return (0); 101 } 102 103 void 104 maxrtc_attach(struct device *parent, struct device *self, void *arg) 105 { 106 struct maxrtc_softc *sc = (struct maxrtc_softc *)self; 107 struct i2c_attach_args *ia = arg; 108 109 sc->sc_tag = ia->ia_tag; 110 sc->sc_addr = ia->ia_addr; 111 112 if (maxrtc_enable_osc(sc) == -1) 113 return; 114 115 if (maxrtc_set_24h_mode(sc) == -1) 116 return; 117 118 sc->sc_todr.cookie = sc; 119 sc->sc_todr.todr_gettime = maxrtc_gettime; 120 sc->sc_todr.todr_settime = maxrtc_settime; 121 sc->sc_todr.todr_quality = 1000; 122 todr_attach(&sc->sc_todr); 123 } 124 125 int 126 maxrtc_read(struct maxrtc_softc *sc, uint8_t *cmd, uint8_t cmd_len, 127 uint8_t *data, uint8_t data_len) 128 { 129 int r; 130 131 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 132 if ((r = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 133 cmd, cmd_len, data, data_len, I2C_F_POLL))) 134 printf("%s: maxrtc_read failed\n", sc->sc_dev.dv_xname); 135 iic_release_bus(sc->sc_tag, I2C_F_POLL); 136 137 return (r); 138 } 139 140 int 141 maxrtc_write(struct maxrtc_softc *sc, uint8_t *data, uint8_t data_len) 142 { 143 int r; 144 145 /* 146 * On write operation the DS1307 requires the target address to be 147 * stored in the first byte of the data packet. Therefore we don't 148 * fill up the command packet here. 149 */ 150 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 151 if ((r = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 152 NULL, 0, data, data_len, I2C_F_POLL))) 153 printf("%s: maxrtc_write failed\n", sc->sc_dev.dv_xname); 154 iic_release_bus(sc->sc_tag, I2C_F_POLL); 155 156 return (r); 157 } 158 159 int 160 maxrtc_enable_osc(struct maxrtc_softc *sc) 161 { 162 uint8_t cmd; 163 uint8_t data_r; 164 uint8_t data_w[2]; 165 166 cmd = DS1307_SEC_REG; 167 data_r = 0; 168 if (maxrtc_read(sc, &cmd, sizeof(cmd), &data_r, sizeof(data_r))) { 169 printf("%s: maxrtc_enable_osc failed\n", sc->sc_dev.dv_xname); 170 return (-1); 171 } 172 if ((data_r & DS1307_SEC_MASK_CH) == 0) { 173 /* oscillator is already enabled */ 174 printf(": rtc is ok\n"); 175 return (0); 176 } 177 printf(": rtc was halted, check battery\n"); 178 179 /* enable the oscillator */ 180 data_r |= 0 << DS1307_SEC_BIT_CH; 181 data_w[0] = DS1307_SEC_REG; 182 data_w[1] = data_r; 183 if (maxrtc_write(sc, data_w, sizeof(data_w))) { 184 printf("%s: maxrtc_enable_osc failed\n", sc->sc_dev.dv_xname); 185 return (-1); 186 } 187 188 return (0); 189 } 190 191 int 192 maxrtc_set_24h_mode(struct maxrtc_softc *sc) 193 { 194 uint8_t cmd; 195 uint8_t data_r; 196 uint8_t data_w[2]; 197 198 cmd = DS1307_HOUR_REG; 199 data_r = 0; 200 if (maxrtc_read(sc, &cmd, sizeof(cmd), &data_r, sizeof(data_r))) { 201 printf("%s: maxrtc_set_24h_mode failed\n", sc->sc_dev.dv_xname); 202 return (-1); 203 } 204 if ((data_r & DS1307_HOUR_MASK_MODE) == 0) { 205 /* 24h mode is already set */ 206 return (0); 207 } 208 209 /* set 24h mode */ 210 data_r |= 0 << DS1307_HOUR_BIT_MODE; 211 data_w[0] = DS1307_HOUR_REG; 212 data_w[1] = data_r; 213 if (maxrtc_write(sc, data_w, sizeof(data_w))) { 214 printf("%s: maxrtc_set_24h_mode failed\n", sc->sc_dev.dv_xname); 215 return (-1); 216 } 217 218 return (0); 219 } 220 221 int 222 maxrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 223 { 224 struct maxrtc_softc *sc = ch->cookie; 225 struct clock_ymdhms dt; 226 uint8_t cmd; 227 uint8_t data[7]; 228 229 cmd = DS1307_SEC_REG; 230 memset(data, 0, sizeof(data)); 231 if (maxrtc_read(sc, &cmd, sizeof(cmd), data, sizeof(data))) { 232 printf("%s: maxrtc_gettime failed\n", sc->sc_dev.dv_xname); 233 return (-1); 234 } 235 236 dt.dt_sec = FROMBCD(data[DS1307_SEC_REG] & DS1307_SEC_MASK); 237 dt.dt_min = FROMBCD(data[DS1307_MIN_REG] & DS1307_MIN_MASK); 238 dt.dt_hour = FROMBCD(data[DS1307_HOUR_REG] & DS1307_HOUR_MASK); 239 dt.dt_wday = FROMBCD(data[DS1307_WDAY_REG] & DS1307_WDAY_MASK); 240 dt.dt_day = FROMBCD(data[DS1307_DATE_REG] & DS1307_DATE_MASK); 241 dt.dt_mon = FROMBCD(data[DS1307_MONTH_REG] & DS1307_MONTH_MASK); 242 dt.dt_year = FROMBCD(data[DS1307_YEAR_REG] & DS1307_YEAR_MASK) + 2000; 243 244 tv->tv_sec = clock_ymdhms_to_secs(&dt); 245 tv->tv_usec = 0; 246 247 return (0); 248 } 249 250 int 251 maxrtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 252 { 253 struct maxrtc_softc *sc = ch->cookie; 254 struct clock_ymdhms dt; 255 uint8_t data[8]; 256 257 clock_secs_to_ymdhms(tv->tv_sec, &dt); 258 259 data[0] = DS1307_SEC_REG; 260 data[1] = TOBCD(dt.dt_sec); /* this will also enable the osc */ 261 data[2] = TOBCD(dt.dt_min); 262 data[3] = TOBCD(dt.dt_hour); /* this will also set 24h mode */ 263 data[4] = TOBCD(dt.dt_wday); 264 data[5] = TOBCD(dt.dt_day); 265 data[6] = TOBCD(dt.dt_mon); 266 data[7] = TOBCD(dt.dt_year - 2000); 267 if (maxrtc_write(sc, data, sizeof(data))) { 268 printf("%s: maxrtc_settime failed\n", sc->sc_dev.dv_xname); 269 return (-1); 270 } 271 272 return (0); 273 } 274