1 /* $OpenBSD: ds1307.c,v 1.3 2021/04/24 10:15:15 mpi 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 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 extern todr_chip_handle_t todr_handle; 88 89 /* 90 * Functions. 91 */ 92 int 93 maxrtc_match(struct device *parent, void *v, void *arg) 94 { 95 struct i2c_attach_args *ia = arg; 96 97 if (strcmp(ia->ia_name, "dallas,ds1307") == 0 || 98 strcmp(ia->ia_name, "ds1307") == 0) 99 return (1); 100 101 return (0); 102 } 103 104 void 105 maxrtc_attach(struct device *parent, struct device *self, void *arg) 106 { 107 struct maxrtc_softc *sc = (struct maxrtc_softc *)self; 108 struct i2c_attach_args *ia = arg; 109 110 sc->sc_tag = ia->ia_tag; 111 sc->sc_addr = ia->ia_addr; 112 sc->sc_todr.cookie = sc; 113 sc->sc_todr.todr_gettime = maxrtc_gettime; 114 sc->sc_todr.todr_settime = maxrtc_settime; 115 sc->sc_todr.todr_setwen = NULL; 116 117 if (maxrtc_enable_osc(sc) == -1) 118 return; 119 120 if (maxrtc_set_24h_mode(sc) == -1) 121 return; 122 123 todr_handle = &sc->sc_todr; 124 } 125 126 int 127 maxrtc_read(struct maxrtc_softc *sc, uint8_t *cmd, uint8_t cmd_len, 128 uint8_t *data, uint8_t data_len) 129 { 130 int r; 131 132 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 133 if ((r = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 134 cmd, cmd_len, data, data_len, I2C_F_POLL))) 135 printf("%s: maxrtc_read failed\n", sc->sc_dev.dv_xname); 136 iic_release_bus(sc->sc_tag, I2C_F_POLL); 137 138 return (r); 139 } 140 141 int 142 maxrtc_write(struct maxrtc_softc *sc, uint8_t *data, uint8_t data_len) 143 { 144 int r; 145 146 /* 147 * On write operation the DS1307 requires the target address to be 148 * stored in the first byte of the data packet. Therefore we don't 149 * fill up the command packet here. 150 */ 151 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 152 if ((r = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 153 NULL, 0, data, data_len, I2C_F_POLL))) 154 printf("%s: maxrtc_write failed\n", sc->sc_dev.dv_xname); 155 iic_release_bus(sc->sc_tag, I2C_F_POLL); 156 157 return (r); 158 } 159 160 int 161 maxrtc_enable_osc(struct maxrtc_softc *sc) 162 { 163 uint8_t cmd; 164 uint8_t data_r; 165 uint8_t data_w[2]; 166 167 cmd = DS1307_SEC_REG; 168 data_r = 0; 169 if (maxrtc_read(sc, &cmd, sizeof(cmd), &data_r, sizeof(data_r))) { 170 printf("%s: maxrtc_enable_osc failed\n", sc->sc_dev.dv_xname); 171 return (-1); 172 } 173 if ((data_r & DS1307_SEC_MASK_CH) == 0) { 174 /* oscilliator is already enabled */ 175 printf(": rtc is ok\n"); 176 return (0); 177 } 178 printf(": rtc was halted, check battery\n"); 179 180 /* enable the oscillator */ 181 data_r |= 0 << DS1307_SEC_BIT_CH; 182 data_w[0] = DS1307_SEC_REG; 183 data_w[1] = data_r; 184 if (maxrtc_write(sc, data_w, sizeof(data_w))) { 185 printf("%s: maxrtc_enable_osc failed\n", sc->sc_dev.dv_xname); 186 return (-1); 187 } 188 189 return (0); 190 } 191 192 int 193 maxrtc_set_24h_mode(struct maxrtc_softc *sc) 194 { 195 uint8_t cmd; 196 uint8_t data_r; 197 uint8_t data_w[2]; 198 199 cmd = DS1307_HOUR_REG; 200 data_r = 0; 201 if (maxrtc_read(sc, &cmd, sizeof(cmd), &data_r, sizeof(data_r))) { 202 printf("%s: maxrtc_set_24h_mode failed\n", sc->sc_dev.dv_xname); 203 return (-1); 204 } 205 if ((data_r & DS1307_HOUR_MASK_MODE) == 0) { 206 /* 24h mode is already set */ 207 return (0); 208 } 209 210 /* set 24h mode */ 211 data_r |= 0 << DS1307_HOUR_BIT_MODE; 212 data_w[0] = DS1307_HOUR_REG; 213 data_w[1] = data_r; 214 if (maxrtc_write(sc, data_w, sizeof(data_w))) { 215 printf("%s: maxrtc_set_24h_mode failed\n", sc->sc_dev.dv_xname); 216 return (-1); 217 } 218 219 return (0); 220 } 221 222 int 223 maxrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 224 { 225 struct maxrtc_softc *sc = ch->cookie; 226 struct clock_ymdhms dt; 227 uint8_t cmd; 228 uint8_t data[7]; 229 230 cmd = DS1307_SEC_REG; 231 memset(data, 0, sizeof(data)); 232 if (maxrtc_read(sc, &cmd, sizeof(cmd), data, sizeof(data))) { 233 printf("%s: maxrtc_gettime failed\n", sc->sc_dev.dv_xname); 234 return (-1); 235 } 236 237 dt.dt_sec = FROMBCD(data[DS1307_SEC_REG] & DS1307_SEC_MASK); 238 dt.dt_min = FROMBCD(data[DS1307_MIN_REG] & DS1307_MIN_MASK); 239 dt.dt_hour = FROMBCD(data[DS1307_HOUR_REG] & DS1307_HOUR_MASK); 240 dt.dt_wday = FROMBCD(data[DS1307_WDAY_REG] & DS1307_WDAY_MASK); 241 dt.dt_day = FROMBCD(data[DS1307_DATE_REG] & DS1307_DATE_MASK); 242 dt.dt_mon = FROMBCD(data[DS1307_MONTH_REG] & DS1307_MONTH_MASK); 243 dt.dt_year = FROMBCD(data[DS1307_YEAR_REG] & DS1307_YEAR_MASK) + 2000; 244 245 tv->tv_sec = clock_ymdhms_to_secs(&dt); 246 tv->tv_usec = 0; 247 248 return (0); 249 } 250 251 int 252 maxrtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 253 { 254 struct maxrtc_softc *sc = ch->cookie; 255 struct clock_ymdhms dt; 256 uint8_t data[8]; 257 258 clock_secs_to_ymdhms(tv->tv_sec, &dt); 259 260 data[0] = DS1307_SEC_REG; 261 data[1] = TOBCD(dt.dt_sec); /* this will also enable the osc */ 262 data[2] = TOBCD(dt.dt_min); 263 data[3] = TOBCD(dt.dt_hour); /* this will also set 24h mode */ 264 data[4] = TOBCD(dt.dt_wday); 265 data[5] = TOBCD(dt.dt_day); 266 data[6] = TOBCD(dt.dt_mon); 267 data[7] = TOBCD(dt.dt_year - 2000); 268 if (maxrtc_write(sc, data, sizeof(data))) { 269 printf("%s: maxrtc_settime failed\n", sc->sc_dev.dv_xname); 270 return (-1); 271 } 272 273 return (0); 274 } 275