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
dsxrtc_match(struct device * parent,void * match,void * aux)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
dsxrtc_attach(struct device * parent,struct device * self,void * aux)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
dsxrtc_gettime(struct todr_chip_handle * handle,struct timeval * tv)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
dsxrtc_settime(struct todr_chip_handle * handle,struct timeval * tv)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
dsxrtc_reg_read(struct dsxrtc_softc * sc,int reg)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
dsxrtc_reg_write(struct dsxrtc_softc * sc,int reg,uint8_t val)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
dsxrtc_clock_read(struct dsxrtc_softc * sc,struct clock_ymdhms * dt)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
dsxrtc_clock_write(struct dsxrtc_softc * sc,struct clock_ymdhms * dt)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