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