xref: /openbsd/sys/dev/i2c/ds1307.c (revision f49fa4f4)
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
maxrtc_match(struct device * parent,void * v,void * arg)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
maxrtc_attach(struct device * parent,struct device * self,void * arg)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
maxrtc_read(struct maxrtc_softc * sc,uint8_t * cmd,uint8_t cmd_len,uint8_t * data,uint8_t data_len)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
maxrtc_write(struct maxrtc_softc * sc,uint8_t * data,uint8_t data_len)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
maxrtc_enable_osc(struct maxrtc_softc * sc)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
maxrtc_set_24h_mode(struct maxrtc_softc * sc)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
maxrtc_gettime(struct todr_chip_handle * ch,struct timeval * tv)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
maxrtc_settime(struct todr_chip_handle * ch,struct timeval * tv)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