xref: /openbsd/sys/dev/onewire/owctr.c (revision 471aeecf)
1 /*	$OpenBSD: owctr.c,v 1.9 2022/04/06 18:59:29 naddy Exp $	*/
2 /*
3  * Copyright (c) 2010 John L. Scarfone <john@scarfone.net>
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 /*
19  * DS2423 1-Wire 4kbit SRAM with Counter family type device driver.
20  * Provides 4096 bits of SRAM and four 32-bit, read-only counters.
21  * This driver provides access to the two externally triggered
22  * counters.
23  */
24 
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/device.h>
28 #include <sys/malloc.h>
29 #include <sys/rwlock.h>
30 #include <sys/sensors.h>
31 
32 #include <dev/onewire/onewiredevs.h>
33 #include <dev/onewire/onewirereg.h>
34 #include <dev/onewire/onewirevar.h>
35 
36 /* Commands */
37 #define	DSCTR_CMD_READ_MEMCOUNTER	0xa5
38 
39 /* External counter banks */
40 #define DS2423_COUNTER_BANK_A		0x1c0
41 #define DS2423_COUNTER_BANK_B		0x1e0
42 
43 /* Buffer offsets */
44 #define DS2423_COUNTER_BUF_COUNTER	35
45 #define DS2423_COUNTER_BUF_CRC		43
46 
47 #define DS2423_COUNTER_BUFSZ		45
48 
49 struct owctr_softc {
50 	struct device		sc_dev;
51 
52 	void *			sc_onewire;
53 	u_int64_t		sc_rom;
54 
55 	struct ksensordev	sc_sensordev;
56 
57 	struct ksensor		sc_counterA;
58 	struct ksensor		sc_counterB;
59 
60 	struct sensor_task	*sc_sensortask;
61 
62 	struct rwlock		sc_lock;
63 };
64 
65 int	owctr_match(struct device *, void *, void *);
66 void	owctr_attach(struct device *, struct device *, void *);
67 int	owctr_detach(struct device *, int);
68 int	owctr_activate(struct device *, int);
69 
70 void	owctr_update(void *);
71 void	owctr_update_counter(void *, int);
72 
73 const struct cfattach owctr_ca = {
74 	sizeof(struct owctr_softc),
75 	owctr_match,
76 	owctr_attach,
77 	owctr_detach,
78 	owctr_activate
79 };
80 
81 struct cfdriver owctr_cd = {
82 	NULL, "owctr", DV_DULL
83 };
84 
85 static const struct onewire_matchfam owctr_fams[] = {
86 	{ ONEWIRE_FAMILY_DS2423 }
87 };
88 
89 int
owctr_match(struct device * parent,void * match,void * aux)90 owctr_match(struct device *parent, void *match, void *aux)
91 {
92 	return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams)));
93 }
94 
95 void
owctr_attach(struct device * parent,struct device * self,void * aux)96 owctr_attach(struct device *parent, struct device *self, void *aux)
97 {
98 	struct owctr_softc *sc = (struct owctr_softc *)self;
99 	struct onewire_attach_args *oa = aux;
100 
101 	sc->sc_onewire = oa->oa_onewire;
102 	sc->sc_rom = oa->oa_rom;
103 
104 	/* Initialize counter sensors */
105 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
106 		sizeof(sc->sc_sensordev.xname));
107 	sc->sc_counterA.type = SENSOR_INTEGER;
108 	snprintf(sc->sc_counterA.desc, sizeof(sc->sc_counterA.desc),
109 		"Counter A sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
110 	sensor_attach(&sc->sc_sensordev, &sc->sc_counterA);
111 	sc->sc_counterB.type = SENSOR_INTEGER;
112 	snprintf(sc->sc_counterB.desc, sizeof(sc->sc_counterB.desc),
113 		"Counter B sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
114 	sensor_attach(&sc->sc_sensordev, &sc->sc_counterB);
115 
116 	sc->sc_sensortask = sensor_task_register(sc, owctr_update, 10);
117 	if (sc->sc_sensortask == NULL) {
118 		printf(": unable to register update task\n");
119 		return;
120 	}
121 
122 	sensordev_install(&sc->sc_sensordev);
123 
124 	rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
125 	printf("\n");
126 }
127 
128 int
owctr_detach(struct device * self,int flags)129 owctr_detach(struct device *self, int flags)
130 {
131 	struct owctr_softc *sc = (struct owctr_softc *)self;
132 
133 	rw_enter_write(&sc->sc_lock);
134 	sensordev_deinstall(&sc->sc_sensordev);
135 	if (sc->sc_sensortask != NULL)
136 		sensor_task_unregister(sc->sc_sensortask);
137 	rw_exit_write(&sc->sc_lock);
138 
139 	return (0);
140 }
141 
142 int
owctr_activate(struct device * self,int act)143 owctr_activate(struct device *self, int act)
144 {
145 	return (0);
146 }
147 
148 void
owctr_update(void * arg)149 owctr_update(void *arg)
150 {
151 	owctr_update_counter(arg, DS2423_COUNTER_BANK_A);
152 	owctr_update_counter(arg, DS2423_COUNTER_BANK_B);
153 }
154 
155 void
owctr_update_counter(void * arg,int bank)156 owctr_update_counter(void *arg, int bank)
157 {
158 	struct owctr_softc *sc = arg;
159 	u_int32_t counter;
160 	u_int16_t crc;
161 	u_int8_t *buf;
162 
163 	rw_enter_write(&sc->sc_lock);
164 	onewire_lock(sc->sc_onewire, 0);
165 	if (onewire_reset(sc->sc_onewire) != 0)
166 		goto done;
167 
168 	buf = malloc(DS2423_COUNTER_BUFSZ, M_DEVBUF, M_NOWAIT);
169 	if (buf == NULL) {
170 		printf("%s: malloc() failed\n", sc->sc_dev.dv_xname);
171 		goto done;
172 	}
173 
174 	onewire_matchrom(sc->sc_onewire, sc->sc_rom);
175 	buf[0] = DSCTR_CMD_READ_MEMCOUNTER;
176 	buf[1] = bank;
177 	buf[2] = bank >> 8;
178 	onewire_write_byte(sc->sc_onewire, buf[0]);
179 	onewire_write_byte(sc->sc_onewire, buf[1]);
180 	onewire_write_byte(sc->sc_onewire, buf[2]);
181 	onewire_read_block(sc->sc_onewire, &buf[3], DS2423_COUNTER_BUFSZ-3);
182 
183 	crc = onewire_crc16(buf, DS2423_COUNTER_BUFSZ-2);
184 	crc ^= buf[DS2423_COUNTER_BUF_CRC]
185 		| (buf[DS2423_COUNTER_BUF_CRC+1] << 8);
186 	if ( crc != 0xffff) {
187 		printf("%s: invalid CRC\n", sc->sc_dev.dv_xname);
188 		if (bank == DS2423_COUNTER_BANK_A) {
189 			sc->sc_counterA.value = 0;
190 			sc->sc_counterA.status = SENSOR_S_UNKNOWN;
191 			sc->sc_counterA.flags |= SENSOR_FUNKNOWN;
192 		} else {
193 			sc->sc_counterB.value = 0;
194 			sc->sc_counterB.status = SENSOR_S_UNKNOWN;
195 			sc->sc_counterB.flags |= SENSOR_FUNKNOWN;
196 		}
197 	} else {
198 		counter = buf[DS2423_COUNTER_BUF_COUNTER]
199 			| (buf[DS2423_COUNTER_BUF_COUNTER+1] << 8)
200 			| (buf[DS2423_COUNTER_BUF_COUNTER+2] << 16)
201 			| (buf[DS2423_COUNTER_BUF_COUNTER+3] << 24);
202 		if (bank == DS2423_COUNTER_BANK_A) {
203 			sc->sc_counterA.value = counter;
204 			sc->sc_counterA.status = SENSOR_S_UNSPEC;
205 			sc->sc_counterA.flags &= ~SENSOR_FUNKNOWN;
206 		} else {
207 			sc->sc_counterB.value = counter;
208 			sc->sc_counterB.status = SENSOR_S_UNSPEC;
209 			sc->sc_counterB.flags &= ~SENSOR_FUNKNOWN;
210 		}
211 	}
212 
213 	onewire_reset(sc->sc_onewire);
214 	free(buf, M_DEVBUF, DS2423_COUNTER_BUFSZ);
215 
216 done:
217 	onewire_unlock(sc->sc_onewire);
218 	rw_exit_write(&sc->sc_lock);
219 }
220