sht3x.c revision 1.10 1 1.4 brad
2 1.10 brad /* $NetBSD: sht3x.c,v 1.10 2025/01/23 19:14:46 brad Exp $ */
3 1.1 brad
4 1.1 brad /*
5 1.1 brad * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org>
6 1.1 brad *
7 1.1 brad * Permission to use, copy, modify, and distribute this software for any
8 1.1 brad * purpose with or without fee is hereby granted, provided that the above
9 1.1 brad * copyright notice and this permission notice appear in all copies.
10 1.1 brad *
11 1.1 brad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.1 brad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.1 brad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.1 brad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.1 brad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.1 brad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.1 brad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.1 brad */
19 1.1 brad
20 1.1 brad #include <sys/cdefs.h>
21 1.10 brad __KERNEL_RCSID(0, "$NetBSD: sht3x.c,v 1.10 2025/01/23 19:14:46 brad Exp $");
22 1.1 brad
23 1.1 brad /*
24 1.1 brad Driver for the Sensirion SHT30/SHT31/SHT35
25 1.1 brad */
26 1.1 brad
27 1.1 brad #include <sys/param.h>
28 1.1 brad #include <sys/systm.h>
29 1.1 brad #include <sys/kernel.h>
30 1.1 brad #include <sys/device.h>
31 1.1 brad #include <sys/module.h>
32 1.1 brad #include <sys/conf.h>
33 1.1 brad #include <sys/sysctl.h>
34 1.1 brad #include <sys/mutex.h>
35 1.1 brad #include <sys/condvar.h>
36 1.1 brad #include <sys/kthread.h>
37 1.1 brad #include <sys/pool.h>
38 1.1 brad #include <sys/kmem.h>
39 1.1 brad
40 1.1 brad #include <dev/sysmon/sysmonvar.h>
41 1.1 brad #include <dev/i2c/i2cvar.h>
42 1.1 brad #include <dev/i2c/sht3xreg.h>
43 1.1 brad #include <dev/i2c/sht3xvar.h>
44 1.1 brad
45 1.1 brad static int sht3x_take_break(void *, bool);
46 1.1 brad static int sht3x_get_status_register(void *, uint16_t *, bool);
47 1.1 brad static int sht3x_clear_status_register(void *, bool);
48 1.1 brad static uint8_t sht3x_crc(uint8_t *, size_t);
49 1.1 brad static int sht3x_cmdr(struct sht3x_sc *, uint16_t, uint8_t *, size_t);
50 1.1 brad static int sht3x_poke(i2c_tag_t, i2c_addr_t, bool);
51 1.1 brad static int sht3x_match(device_t, cfdata_t, void *);
52 1.1 brad static void sht3x_attach(device_t, device_t, void *);
53 1.1 brad static int sht3x_detach(device_t, int);
54 1.1 brad static void sht3x_refresh(struct sysmon_envsys *, envsys_data_t *);
55 1.1 brad static int sht3x_verify_sysctl(SYSCTLFN_ARGS);
56 1.1 brad static int sht3x_verify_sysctl_heateron(SYSCTLFN_ARGS);
57 1.1 brad static int sht3x_verify_sysctl_modes(SYSCTLFN_ARGS);
58 1.1 brad static int sht3x_verify_sysctl_repeatability(SYSCTLFN_ARGS);
59 1.1 brad static int sht3x_verify_sysctl_rate(SYSCTLFN_ARGS);
60 1.1 brad static int sht3x_set_heater(struct sht3x_sc *);
61 1.1 brad static void sht3x_thread(void *);
62 1.1 brad static int sht3x_init_periodic_measurement(void *, int *);
63 1.1 brad static void sht3x_take_periodic_measurement(void *);
64 1.1 brad static void sht3x_start_thread(void *);
65 1.1 brad static void sht3x_stop_thread(void *);
66 1.1 brad static int sht3x_activate(device_t, enum devact);
67 1.1 brad
68 1.1 brad #define SHT3X_DEBUG
69 1.1 brad #ifdef SHT3X_DEBUG
70 1.1 brad #define DPRINTF(s, l, x) \
71 1.1 brad do { \
72 1.1 brad if (l <= s->sc_sht3xdebug) \
73 1.1 brad printf x; \
74 1.1 brad } while (/*CONSTCOND*/0)
75 1.1 brad #else
76 1.1 brad #define DPRINTF(s, l, x)
77 1.1 brad #endif
78 1.1 brad
79 1.1 brad CFATTACH_DECL_NEW(sht3xtemp, sizeof(struct sht3x_sc),
80 1.1 brad sht3x_match, sht3x_attach, sht3x_detach, sht3x_activate);
81 1.1 brad
82 1.1 brad extern struct cfdriver sht3xtemp_cd;
83 1.1 brad
84 1.1 brad static dev_type_open(sht3xopen);
85 1.1 brad static dev_type_read(sht3xread);
86 1.1 brad static dev_type_close(sht3xclose);
87 1.1 brad const struct cdevsw sht3x_cdevsw = {
88 1.1 brad .d_open = sht3xopen,
89 1.1 brad .d_close = sht3xclose,
90 1.1 brad .d_read = sht3xread,
91 1.1 brad .d_write = nowrite,
92 1.1 brad .d_ioctl = noioctl,
93 1.1 brad .d_stop = nostop,
94 1.1 brad .d_tty = notty,
95 1.1 brad .d_poll = nopoll,
96 1.1 brad .d_mmap = nommap,
97 1.1 brad .d_kqfilter = nokqfilter,
98 1.1 brad .d_discard = nodiscard,
99 1.1 brad .d_flag = D_OTHER
100 1.1 brad };
101 1.1 brad
102 1.1 brad static struct sht3x_sensor sht3x_sensors[] = {
103 1.1 brad {
104 1.1 brad .desc = "humidity",
105 1.1 brad .type = ENVSYS_SRELHUMIDITY,
106 1.1 brad },
107 1.1 brad {
108 1.1 brad .desc = "temperature",
109 1.1 brad .type = ENVSYS_STEMP,
110 1.1 brad }
111 1.1 brad };
112 1.1 brad
113 1.1 brad /* The typical delays are MOSTLY documented in the datasheet for the chip.
114 1.1 brad There is no need to be very accurate with these, just rough estimates
115 1.1 brad will work fine.
116 1.1 brad */
117 1.1 brad
118 1.1 brad static struct sht3x_timing sht3x_timings[] = {
119 1.1 brad {
120 1.1 brad .cmd = SHT3X_SOFT_RESET,
121 1.1 brad .typicaldelay = 3000,
122 1.1 brad },
123 1.1 brad {
124 1.1 brad .cmd = SHT3X_GET_STATUS_REGISTER,
125 1.1 brad .typicaldelay = 100,
126 1.1 brad },
127 1.1 brad {
128 1.1 brad .cmd = SHT3X_BREAK,
129 1.1 brad .typicaldelay = 100,
130 1.1 brad },
131 1.1 brad {
132 1.1 brad .cmd = SHT3X_CLEAR_STATUS_REGISTER,
133 1.1 brad .typicaldelay = 100,
134 1.1 brad },
135 1.1 brad {
136 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_CS_HIGH,
137 1.1 brad .typicaldelay = 15000,
138 1.1 brad },
139 1.1 brad {
140 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_CS_MEDIUM,
141 1.1 brad .typicaldelay = 6000,
142 1.1 brad },
143 1.1 brad {
144 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_CS_LOW,
145 1.1 brad .typicaldelay = 4000,
146 1.1 brad },
147 1.1 brad {
148 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_HIGH,
149 1.1 brad .typicaldelay = 15000,
150 1.1 brad },
151 1.1 brad {
152 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_MEDIUM,
153 1.1 brad .typicaldelay = 6000,
154 1.1 brad },
155 1.1 brad {
156 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_LOW,
157 1.1 brad .typicaldelay = 4000,
158 1.1 brad },
159 1.1 brad {
160 1.1 brad .cmd = SHT3X_WRITE_HIGH_ALERT_SET,
161 1.1 brad .typicaldelay = 5000,
162 1.1 brad },
163 1.1 brad {
164 1.1 brad .cmd = SHT3X_WRITE_HIGH_ALERT_CLEAR,
165 1.1 brad .typicaldelay = 5000,
166 1.1 brad },
167 1.1 brad {
168 1.1 brad .cmd = SHT3X_WRITE_LOW_ALERT_SET,
169 1.1 brad .typicaldelay = 5000,
170 1.1 brad },
171 1.1 brad {
172 1.1 brad .cmd = SHT3X_WRITE_LOW_ALERT_CLEAR,
173 1.1 brad .typicaldelay = 5000,
174 1.8 brad },
175 1.8 brad {
176 1.8 brad .cmd = SHT3X_READ_SERIAL_NUMBER,
177 1.8 brad .typicaldelay = 500,
178 1.1 brad }
179 1.1 brad };
180 1.1 brad
181 1.1 brad /* In single shot mode, find the command */
182 1.1 brad
183 1.1 brad static struct sht3x_repeatability sht3x_repeatability_ss[] = {
184 1.1 brad {
185 1.1 brad .text = "high",
186 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_HIGH,
187 1.10 brad .cscmd = SHT3X_MEASURE_REPEATABILITY_CS_HIGH,
188 1.1 brad },
189 1.1 brad {
190 1.1 brad .text = "medium",
191 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_MEDIUM,
192 1.10 brad .cscmd = SHT3X_MEASURE_REPEATABILITY_CS_MEDIUM,
193 1.1 brad },
194 1.1 brad {
195 1.1 brad .text = "low",
196 1.1 brad .cmd = SHT3X_MEASURE_REPEATABILITY_NOCS_LOW,
197 1.10 brad .cscmd = SHT3X_MEASURE_REPEATABILITY_CS_LOW,
198 1.1 brad }
199 1.1 brad };
200 1.1 brad
201 1.1 brad
202 1.1 brad /* For periodic, look at the repeatability and the rate.
203 1.1 brad * ART is a bit fake here, as the repeatability is not really
204 1.1 brad * used.
205 1.1 brad */
206 1.1 brad
207 1.1 brad static struct sht3x_periodic sht3x_periodic_rate[] = {
208 1.1 brad {
209 1.1 brad .repeatability = "high",
210 1.1 brad .rate = "0.5mps",
211 1.1 brad .sdelay = 1000,
212 1.1 brad .cmd = SHT3X_HALF_MPS_HIGH,
213 1.1 brad },
214 1.1 brad {
215 1.1 brad .repeatability = "medium",
216 1.1 brad .rate = "0.5mps",
217 1.1 brad .sdelay = 1000,
218 1.1 brad .cmd = SHT3X_HALF_MPS_MEDIUM,
219 1.1 brad },
220 1.1 brad {
221 1.1 brad .repeatability = "low",
222 1.1 brad .rate = "0.5mps",
223 1.1 brad .sdelay = 1000,
224 1.1 brad .cmd = SHT3X_HALF_MPS_LOW,
225 1.1 brad },
226 1.1 brad {
227 1.1 brad .repeatability = "high",
228 1.1 brad .rate = "1.0mps",
229 1.1 brad .sdelay = 500,
230 1.1 brad .cmd = SHT3X_ONE_MPS_HIGH,
231 1.1 brad },
232 1.1 brad {
233 1.1 brad .repeatability = "medium",
234 1.1 brad .rate = "1.0mps",
235 1.1 brad .sdelay = 500,
236 1.1 brad .cmd = SHT3X_ONE_MPS_MEDIUM,
237 1.1 brad },
238 1.1 brad {
239 1.1 brad .repeatability = "low",
240 1.1 brad .rate = "1.0mps",
241 1.1 brad .sdelay = 500,
242 1.1 brad .cmd = SHT3X_ONE_MPS_LOW,
243 1.1 brad },
244 1.1 brad {
245 1.1 brad .repeatability = "high",
246 1.1 brad .rate = "2.0mps",
247 1.1 brad .sdelay = 250,
248 1.1 brad .cmd = SHT3X_TWO_MPS_HIGH,
249 1.1 brad },
250 1.1 brad {
251 1.1 brad .repeatability = "medium",
252 1.1 brad .rate = "2.0mps",
253 1.1 brad .sdelay = 250,
254 1.1 brad .cmd = SHT3X_TWO_MPS_MEDIUM,
255 1.1 brad },
256 1.1 brad {
257 1.1 brad .repeatability = "low",
258 1.1 brad .rate = "2.0mps",
259 1.1 brad .sdelay = 250,
260 1.1 brad .cmd = SHT3X_TWO_MPS_LOW,
261 1.1 brad },
262 1.1 brad {
263 1.1 brad .repeatability = "high",
264 1.1 brad .rate = "4.0mps",
265 1.1 brad .sdelay = 100,
266 1.1 brad .cmd = SHT3X_FOUR_MPS_HIGH,
267 1.1 brad },
268 1.1 brad {
269 1.1 brad .repeatability = "medium",
270 1.1 brad .rate = "4.0mps",
271 1.1 brad .sdelay = 100,
272 1.1 brad .cmd = SHT3X_FOUR_MPS_MEDIUM,
273 1.1 brad },
274 1.1 brad {
275 1.1 brad .repeatability = "low",
276 1.1 brad .rate = "4.0mps",
277 1.1 brad .sdelay = 100,
278 1.1 brad .cmd = SHT3X_FOUR_MPS_LOW,
279 1.1 brad },
280 1.1 brad {
281 1.1 brad .repeatability = "high",
282 1.1 brad .rate = "10.0mps",
283 1.1 brad .sdelay = 50,
284 1.1 brad .cmd = SHT3X_TEN_MPS_HIGH,
285 1.1 brad },
286 1.1 brad {
287 1.1 brad .repeatability = "medium",
288 1.1 brad .rate = "10.0mps",
289 1.1 brad .sdelay = 50,
290 1.1 brad .cmd = SHT3X_FOUR_MPS_MEDIUM,
291 1.1 brad },
292 1.1 brad {
293 1.1 brad .repeatability = "low",
294 1.1 brad .rate = "10.0mps",
295 1.1 brad .sdelay = 50,
296 1.1 brad .cmd = SHT3X_FOUR_MPS_LOW,
297 1.1 brad },
298 1.1 brad {
299 1.1 brad .repeatability = "high",
300 1.1 brad .rate = "ART",
301 1.1 brad .sdelay = 100,
302 1.1 brad .cmd = SHT3X_ART_ENABLE,
303 1.1 brad },
304 1.1 brad {
305 1.1 brad .repeatability = "medium",
306 1.1 brad .rate = "ART",
307 1.1 brad .sdelay = 100,
308 1.1 brad .cmd = SHT3X_ART_ENABLE,
309 1.1 brad },
310 1.1 brad {
311 1.1 brad .repeatability = "low",
312 1.1 brad .rate = "ART",
313 1.1 brad .sdelay = 100,
314 1.1 brad .cmd = SHT3X_ART_ENABLE,
315 1.1 brad }
316 1.1 brad };
317 1.1 brad
318 1.1 brad static const char sht3x_rate_names[] =
319 1.1 brad "0.5mps, 1.0mps, 2.0mps, 4.0mps, 10.0mps, ART";
320 1.1 brad
321 1.1 brad static const char sht3x_mode_names[] =
322 1.1 brad "single-shot, periodic";
323 1.1 brad
324 1.1 brad static const char sht3x_repeatability_names[] =
325 1.1 brad "high, medium, low";
326 1.1 brad
327 1.1 brad static int
328 1.1 brad sht3x_take_break(void *aux, bool have_bus)
329 1.1 brad {
330 1.1 brad struct sht3x_sc *sc;
331 1.1 brad sc = aux;
332 1.1 brad int error = 0;
333 1.1 brad
334 1.1 brad if (! have_bus) {
335 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
336 1.1 brad if (error) {
337 1.2 christos DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
338 1.2 christos "breaking %d\n", device_xname(sc->sc_dev), error));
339 1.1 brad goto out;
340 1.1 brad }
341 1.1 brad }
342 1.1 brad error = sht3x_cmdr(sc, SHT3X_BREAK, NULL, 0);
343 1.1 brad if (error) {
344 1.1 brad DPRINTF(sc, 2, ("%s: Error breaking: %d\n",
345 1.1 brad device_xname(sc->sc_dev), error));
346 1.1 brad }
347 1.2 christos out:
348 1.1 brad if (! have_bus) {
349 1.1 brad iic_release_bus(sc->sc_tag, 0);
350 1.1 brad }
351 1.1 brad
352 1.1 brad sc->sc_isperiodic = false;
353 1.2 christos strlcpy(sc->sc_mode, "single-shot", SHT3X_MODE_NAME);
354 1.1 brad
355 1.1 brad return error;
356 1.1 brad }
357 1.1 brad
358 1.1 brad static int
359 1.1 brad sht3x_get_status_register(void *aux, uint16_t *reg, bool have_bus)
360 1.1 brad {
361 1.2 christos struct sht3x_sc *sc = aux;
362 1.1 brad uint8_t buf[3];
363 1.2 christos int error;
364 1.1 brad
365 1.1 brad if (! have_bus) {
366 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
367 1.1 brad if (error) {
368 1.2 christos DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
369 1.2 christos "getting status %d\n", device_xname(sc->sc_dev),
370 1.2 christos error));
371 1.2 christos return error;
372 1.1 brad }
373 1.1 brad }
374 1.1 brad error = sht3x_cmdr(sc, SHT3X_GET_STATUS_REGISTER, buf, 3);
375 1.1 brad if (error) {
376 1.1 brad DPRINTF(sc, 2, ("%s: Error getting status: %d\n",
377 1.1 brad device_xname(sc->sc_dev), error));
378 1.2 christos goto out;
379 1.1 brad }
380 1.2 christos
381 1.2 christos uint8_t c = sht3x_crc(&buf[0], 2);
382 1.2 christos if (c == buf[2]) {
383 1.2 christos *reg = buf[0] << 8 | buf[1];
384 1.2 christos } else {
385 1.2 christos error = EINVAL;
386 1.2 christos }
387 1.2 christos out:
388 1.1 brad if (! have_bus) {
389 1.1 brad iic_release_bus(sc->sc_tag, 0);
390 1.1 brad }
391 1.1 brad
392 1.1 brad return error;
393 1.1 brad }
394 1.1 brad
395 1.1 brad static int
396 1.1 brad sht3x_clear_status_register(void *aux, bool have_bus)
397 1.1 brad {
398 1.2 christos struct sht3x_sc *sc = aux;
399 1.2 christos int error;
400 1.1 brad
401 1.1 brad if (! have_bus) {
402 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
403 1.1 brad if (error) {
404 1.2 christos DPRINTF(sc, 2, ("%s: Could not acquire iic bus for "
405 1.2 christos "clearing status %d\n", device_xname(sc->sc_dev),
406 1.2 christos error));
407 1.2 christos return error;
408 1.1 brad }
409 1.1 brad }
410 1.1 brad error = sht3x_cmdr(sc, SHT3X_CLEAR_STATUS_REGISTER, NULL, 0);
411 1.1 brad if (error) {
412 1.1 brad DPRINTF(sc, 2, ("%s: Error clear status register: %d\n",
413 1.1 brad device_xname(sc->sc_dev), error));
414 1.1 brad }
415 1.1 brad if (! have_bus) {
416 1.1 brad iic_release_bus(sc->sc_tag, 0);
417 1.1 brad }
418 1.1 brad
419 1.1 brad return error;
420 1.1 brad }
421 1.1 brad
422 1.1 brad void
423 1.1 brad sht3x_thread(void *aux)
424 1.1 brad {
425 1.1 brad struct sht3x_sc *sc = aux;
426 1.1 brad int error, rv;
427 1.1 brad int sdelay = 100;
428 1.1 brad
429 1.1 brad mutex_enter(&sc->sc_threadmutex);
430 1.1 brad
431 1.1 brad while (!sc->sc_stopping && !sc->sc_dying) {
432 1.1 brad if (sc->sc_initperiodic) {
433 1.2 christos error = sht3x_init_periodic_measurement(sc, &sdelay);
434 1.1 brad if (error) {
435 1.2 christos DPRINTF(sc, 2, ("%s: Error initing periodic "
436 1.2 christos "measurement in thread: %d\n",
437 1.2 christos device_xname(sc->sc_dev), error));
438 1.1 brad }
439 1.1 brad sc->sc_initperiodic = false;
440 1.1 brad }
441 1.1 brad rv = cv_timedwait(&sc->sc_condvar, &sc->sc_threadmutex,
442 1.1 brad mstohz(sdelay));
443 1.2 christos if (rv == EWOULDBLOCK && !sc->sc_stopping &&
444 1.2 christos !sc->sc_initperiodic && !sc->sc_dying) {
445 1.1 brad sht3x_take_periodic_measurement(sc);
446 1.1 brad }
447 1.1 brad }
448 1.1 brad mutex_exit(&sc->sc_threadmutex);
449 1.1 brad kthread_exit(0);
450 1.1 brad }
451 1.1 brad
452 1.1 brad int
453 1.1 brad sht3x_init_periodic_measurement(void *aux, int *sdelay)
454 1.1 brad {
455 1.2 christos struct sht3x_sc *sc = aux;
456 1.2 christos size_t i;
457 1.2 christos int error;
458 1.2 christos uint16_t r;
459 1.1 brad
460 1.1 brad for (i = 0; i < __arraycount(sht3x_periodic_rate); i++) {
461 1.2 christos if (strncmp(sc->sc_repeatability,
462 1.2 christos sht3x_periodic_rate[i].repeatability, SHT3X_REP_NAME) == 0 &&
463 1.2 christos strncmp(sc->sc_periodic_rate, sht3x_periodic_rate[i].rate,
464 1.2 christos SHT3X_RATE_NAME) == 0)
465 1.2 christos {
466 1.1 brad r = sht3x_periodic_rate[i].cmd;
467 1.1 brad *sdelay = sht3x_periodic_rate[i].sdelay;
468 1.1 brad break;
469 1.1 brad }
470 1.1 brad }
471 1.1 brad
472 1.1 brad if (i == __arraycount(sht3x_periodic_rate)) {
473 1.1 brad *sdelay = 100;
474 1.2 christos return ENODEV;
475 1.1 brad }
476 1.1 brad
477 1.1 brad DPRINTF(sc, 2, ("%s: Would init with: %x\n",
478 1.1 brad device_xname(sc->sc_dev), r));
479 1.1 brad
480 1.2 christos mutex_enter(&sc->sc_mutex);
481 1.2 christos
482 1.2 christos error = iic_acquire_bus(sc->sc_tag, 0);
483 1.2 christos if (error) {
484 1.2 christos DPRINTF(sc, 2, ("%s: Could not acquire iic bus for initing: "
485 1.2 christos " %d\n", device_xname(sc->sc_dev), error));
486 1.4 brad goto outm;
487 1.2 christos }
488 1.1 brad
489 1.2 christos error = sht3x_take_break(sc, true);
490 1.2 christos if (error) {
491 1.2 christos DPRINTF(sc, 2, ("%s: Could not acquire iic bus for initing: "
492 1.2 christos " %d\n", device_xname(sc->sc_dev), error));
493 1.2 christos goto out;
494 1.2 christos }
495 1.1 brad
496 1.2 christos error = sht3x_cmdr(sc, r, NULL, 0);
497 1.2 christos if (error) {
498 1.2 christos DPRINTF(sc, 2,
499 1.2 christos ("%s: Error sending periodic measurement command: %d\n",
500 1.2 christos device_xname(sc->sc_dev), error));
501 1.2 christos goto out;
502 1.1 brad }
503 1.1 brad
504 1.2 christos sc->sc_isperiodic = true;
505 1.2 christos strlcpy(sc->sc_mode, "periodic", SHT3X_MODE_NAME);
506 1.2 christos
507 1.2 christos out:
508 1.2 christos iic_release_bus(sc->sc_tag, 0);
509 1.4 brad outm:
510 1.2 christos mutex_exit(&sc->sc_mutex);
511 1.1 brad return error;
512 1.1 brad }
513 1.1 brad
514 1.1 brad static void
515 1.1 brad sht3x_take_periodic_measurement(void *aux)
516 1.1 brad {
517 1.2 christos struct sht3x_sc *sc = aux;
518 1.2 christos int error;
519 1.1 brad struct sht3x_read_q *pp;
520 1.2 christos uint8_t rawbuf[MAX(sizeof(sc->sc_pbuffer), sizeof(pp->measurement))];
521 1.2 christos uint16_t status_reg;
522 1.1 brad
523 1.1 brad mutex_enter(&sc->sc_mutex);
524 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
525 1.1 brad if (error) {
526 1.1 brad DPRINTF(sc, 2, ("%s: Could not acquire iic bus for getting "
527 1.1 brad "periodic data: %d\n", device_xname(sc->sc_dev), error));
528 1.2 christos goto out;
529 1.2 christos }
530 1.2 christos
531 1.2 christos error = sht3x_get_status_register(sc, &status_reg, true);
532 1.2 christos if (error) {
533 1.2 christos DPRINTF(sc, 2,
534 1.2 christos ("%s: Error getting status register periodic: %d\n",
535 1.2 christos device_xname(sc->sc_dev), error));
536 1.2 christos goto err;
537 1.2 christos }
538 1.2 christos
539 1.2 christos if (status_reg & SHT3X_RESET_DETECTED) {
540 1.2 christos aprint_error_dev(sc->sc_dev, "Reset detected in periodic mode. "
541 1.2 christos "Heater may have been reset.\n");
542 1.2 christos delay(3000);
543 1.2 christos sht3x_take_break(sc, true);
544 1.2 christos sht3x_clear_status_register(sc, true);
545 1.2 christos sc->sc_heateron = status_reg & SHT3X_HEATER_STATUS;
546 1.2 christos sc->sc_initperiodic = true;
547 1.1 brad } else {
548 1.2 christos int data_error = sht3x_cmdr(sc, SHT3X_PERIODIC_FETCH_DATA,
549 1.2 christos rawbuf, sizeof(rawbuf));
550 1.2 christos /*
551 1.2 christos * EIO is actually expected if the poll interval is faster
552 1.9 andvar * than the rate that the sensor is set to. Unfortunately,
553 1.2 christos * this will also mess with the ability to detect an actual
554 1.2 christos * problem with the sensor in periodic mode, so we do the best
555 1.2 christos * we can here.
556 1.2 christos */
557 1.2 christos if (data_error) {
558 1.2 christos if (data_error != EIO) {
559 1.2 christos DPRINTF(sc, 2, ("%s: Error sending periodic "
560 1.2 christos "fetch command: %d\n",
561 1.2 christos device_xname(sc->sc_dev), data_error));
562 1.1 brad }
563 1.2 christos goto err;
564 1.1 brad }
565 1.2 christos }
566 1.2 christos
567 1.2 christos iic_release_bus(sc->sc_tag, 0);
568 1.2 christos /*
569 1.2 christos * If there was no errors from anything then the data should be
570 1.2 christos * valid.
571 1.2 christos */
572 1.2 christos DPRINTF(sc, 2, ("%s: Raw periodic: %x%x - %x -- %x%x - %x\n",
573 1.2 christos device_xname(sc->sc_dev), rawbuf[0], rawbuf[1], rawbuf[2],
574 1.2 christos rawbuf[3], rawbuf[4], rawbuf[5]));
575 1.2 christos memcpy(sc->sc_pbuffer, rawbuf, sizeof(sc->sc_pbuffer));
576 1.1 brad
577 1.2 christos if (sc->sc_opened) {
578 1.2 christos mutex_enter(&sc->sc_read_mutex);
579 1.2 christos pp = pool_cache_get(sc->sc_readpool, PR_NOWAIT);
580 1.2 christos if (pp == NULL) {
581 1.2 christos aprint_error_dev(sc->sc_dev,
582 1.2 christos "Could not allocate memory for pool read\n");
583 1.1 brad } else {
584 1.2 christos memcpy(pp->measurement, rawbuf, sizeof(pp->measurement));
585 1.2 christos DPRINTF(sc, 4, ("%s: Queue insert\n",
586 1.2 christos device_xname(sc->sc_dev)));
587 1.2 christos SIMPLEQ_INSERT_HEAD(&sc->sc_read_queue, pp, read_q);
588 1.1 brad }
589 1.2 christos cv_signal(&sc->sc_condreadready);
590 1.2 christos mutex_exit(&sc->sc_read_mutex);
591 1.1 brad }
592 1.2 christos out:
593 1.2 christos mutex_exit(&sc->sc_mutex);
594 1.2 christos return;
595 1.2 christos err:
596 1.2 christos /*
597 1.2 christos * We are only going to worry about errors when it was not related
598 1.2 christos * to actually getting data. That is a likely indicator of a problem
599 1.2 christos * with the sensor.
600 1.2 christos */
601 1.2 christos DPRINTF(sc, 2, ("%s: Raw periodic with error: %x%x - %x -- "
602 1.2 christos "%x%x - %x -- %d\n", device_xname(sc->sc_dev), rawbuf[0], rawbuf[1],
603 1.2 christos rawbuf[2], rawbuf[3], rawbuf[4], rawbuf[5], error));
604 1.2 christos iic_release_bus(sc->sc_tag, 0);
605 1.4 brad if (error != 0) {
606 1.4 brad memcpy(sc->sc_pbuffer, "dedbef", sizeof(sc->sc_pbuffer));
607 1.4 brad }
608 1.1 brad mutex_exit(&sc->sc_mutex);
609 1.1 brad }
610 1.1 brad
611 1.1 brad static void
612 1.1 brad sht3x_stop_thread(void *aux)
613 1.1 brad {
614 1.1 brad struct sht3x_sc *sc;
615 1.1 brad sc = aux;
616 1.1 brad
617 1.1 brad if (!sc->sc_isperiodic) {
618 1.1 brad return;
619 1.1 brad }
620 1.1 brad
621 1.1 brad mutex_enter(&sc->sc_threadmutex);
622 1.1 brad sc->sc_stopping = true;
623 1.1 brad cv_signal(&sc->sc_condvar);
624 1.1 brad mutex_exit(&sc->sc_threadmutex);
625 1.1 brad
626 1.1 brad /* wait for the thread to exit */
627 1.1 brad kthread_join(sc->sc_thread);
628 1.1 brad
629 1.1 brad mutex_enter(&sc->sc_mutex);
630 1.1 brad sht3x_take_break(sc,false);
631 1.1 brad mutex_exit(&sc->sc_mutex);
632 1.1 brad }
633 1.1 brad
634 1.1 brad static void
635 1.1 brad sht3x_start_thread(void *aux)
636 1.1 brad {
637 1.1 brad struct sht3x_sc *sc;
638 1.1 brad sc = aux;
639 1.1 brad int error;
640 1.1 brad
641 1.1 brad error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
642 1.1 brad sht3x_thread, sc, &sc->sc_thread, "%s", device_xname(sc->sc_dev));
643 1.1 brad if (error) {
644 1.1 brad DPRINTF(sc, 2, ("%s: Unable to create measurement thread: %d\n",
645 1.1 brad device_xname(sc->sc_dev), error));
646 1.1 brad }
647 1.1 brad }
648 1.1 brad
649 1.1 brad int
650 1.1 brad sht3x_verify_sysctl(SYSCTLFN_ARGS)
651 1.1 brad {
652 1.1 brad int error, t;
653 1.1 brad struct sysctlnode node;
654 1.1 brad
655 1.1 brad node = *rnode;
656 1.1 brad t = *(int *)rnode->sysctl_data;
657 1.1 brad node.sysctl_data = &t;
658 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
659 1.1 brad if (error || newp == NULL)
660 1.1 brad return error;
661 1.1 brad
662 1.1 brad if (t < 0)
663 1.1 brad return EINVAL;
664 1.1 brad
665 1.1 brad *(int *)rnode->sysctl_data = t;
666 1.1 brad
667 1.1 brad return 0;
668 1.1 brad }
669 1.1 brad
670 1.1 brad int
671 1.1 brad sht3x_verify_sysctl_heateron(SYSCTLFN_ARGS)
672 1.1 brad {
673 1.1 brad int error;
674 1.1 brad bool t;
675 1.1 brad struct sht3x_sc *sc;
676 1.1 brad struct sysctlnode node;
677 1.1 brad
678 1.1 brad node = *rnode;
679 1.1 brad sc = node.sysctl_data;
680 1.1 brad t = sc->sc_heateron;
681 1.1 brad node.sysctl_data = &t;
682 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
683 1.1 brad if (error || newp == NULL)
684 1.1 brad return error;
685 1.1 brad
686 1.1 brad sc->sc_heateron = t;
687 1.1 brad error = sht3x_set_heater(sc);
688 1.1 brad
689 1.1 brad return error;
690 1.1 brad }
691 1.1 brad
692 1.1 brad static int
693 1.1 brad sht3x_set_heater(struct sht3x_sc *sc)
694 1.1 brad {
695 1.1 brad int error = 0;
696 1.1 brad uint16_t cmd;
697 1.1 brad
698 1.1 brad mutex_enter(&sc->sc_mutex);
699 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
700 1.1 brad if (error) {
701 1.1 brad DPRINTF(sc, 2, ("%s:%s: Failed to acquire bus: %d\n",
702 1.1 brad device_xname(sc->sc_dev), __func__, error));
703 1.2 christos goto out;
704 1.1 brad }
705 1.1 brad
706 1.1 brad if (sc->sc_heateron) {
707 1.1 brad cmd = SHT3X_HEATER_ENABLE;
708 1.1 brad } else {
709 1.1 brad cmd = SHT3X_HEATER_DISABLE;
710 1.1 brad }
711 1.1 brad
712 1.1 brad error = sht3x_cmdr(sc, cmd, NULL, 0);
713 1.1 brad
714 1.1 brad iic_release_bus(sc->sc_tag,0);
715 1.2 christos out:
716 1.1 brad mutex_exit(&sc->sc_mutex);
717 1.1 brad
718 1.1 brad return error;
719 1.1 brad }
720 1.1 brad
721 1.1 brad int
722 1.1 brad sht3x_verify_sysctl_modes(SYSCTLFN_ARGS)
723 1.1 brad {
724 1.1 brad char buf[SHT3X_MODE_NAME];
725 1.1 brad struct sht3x_sc *sc;
726 1.1 brad struct sysctlnode node;
727 1.1 brad bool is_ss = false;
728 1.1 brad bool is_periodic = false;
729 1.2 christos int error;
730 1.1 brad
731 1.1 brad node = *rnode;
732 1.1 brad sc = node.sysctl_data;
733 1.1 brad (void) memcpy(buf, sc->sc_mode, SHT3X_MODE_NAME);
734 1.1 brad node.sysctl_data = buf;
735 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
736 1.1 brad if (error || newp == NULL)
737 1.1 brad return error;
738 1.1 brad
739 1.1 brad if (sc->sc_opened) {
740 1.1 brad return EINVAL;
741 1.1 brad }
742 1.1 brad
743 1.2 christos is_ss = strncmp(node.sysctl_data, "single-shot", SHT3X_MODE_NAME) == 0;
744 1.2 christos is_periodic = strncmp(node.sysctl_data, "periodic", SHT3X_MODE_NAME)
745 1.2 christos == 0;
746 1.1 brad
747 1.2 christos if (!is_ss && !is_periodic) {
748 1.2 christos return EINVAL;
749 1.2 christos }
750 1.2 christos
751 1.2 christos (void) memcpy(sc->sc_mode, node.sysctl_data, SHT3X_MODE_NAME);
752 1.2 christos if (is_ss) {
753 1.2 christos sht3x_stop_thread(sc);
754 1.2 christos sc->sc_stopping = false;
755 1.2 christos sc->sc_initperiodic = false;
756 1.2 christos sc->sc_isperiodic = false;
757 1.1 brad }
758 1.1 brad
759 1.2 christos if (is_periodic) {
760 1.2 christos sc->sc_stopping = false;
761 1.2 christos sc->sc_initperiodic = true;
762 1.2 christos sc->sc_isperiodic = true;
763 1.2 christos sht3x_start_thread(sc);
764 1.1 brad }
765 1.1 brad
766 1.2 christos return 0;
767 1.1 brad }
768 1.1 brad
769 1.1 brad int
770 1.1 brad sht3x_verify_sysctl_repeatability(SYSCTLFN_ARGS)
771 1.1 brad {
772 1.1 brad char buf[SHT3X_REP_NAME];
773 1.1 brad struct sht3x_sc *sc;
774 1.1 brad struct sysctlnode node;
775 1.2 christos int error;
776 1.1 brad size_t i;
777 1.1 brad
778 1.1 brad node = *rnode;
779 1.1 brad sc = node.sysctl_data;
780 1.1 brad (void) memcpy(buf, sc->sc_repeatability, SHT3X_REP_NAME);
781 1.1 brad node.sysctl_data = buf;
782 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
783 1.1 brad if (error || newp == NULL)
784 1.1 brad return error;
785 1.1 brad
786 1.1 brad for (i = 0; i < __arraycount(sht3x_repeatability_ss); i++) {
787 1.1 brad if (strncmp(node.sysctl_data, sht3x_repeatability_ss[i].text,
788 1.1 brad SHT3X_REP_NAME) == 0) {
789 1.1 brad break;
790 1.1 brad }
791 1.1 brad }
792 1.1 brad
793 1.1 brad if (i == __arraycount(sht3x_repeatability_ss))
794 1.1 brad return EINVAL;
795 1.1 brad (void) memcpy(sc->sc_repeatability, node.sysctl_data, SHT3X_REP_NAME);
796 1.1 brad
797 1.1 brad if (sc->sc_isperiodic) {
798 1.1 brad sc->sc_initperiodic = true;
799 1.1 brad }
800 1.1 brad
801 1.1 brad return error;
802 1.1 brad }
803 1.1 brad
804 1.1 brad int
805 1.1 brad sht3x_verify_sysctl_rate(SYSCTLFN_ARGS)
806 1.1 brad {
807 1.1 brad char buf[SHT3X_RATE_NAME];
808 1.1 brad struct sht3x_sc *sc;
809 1.1 brad struct sysctlnode node;
810 1.2 christos int error;
811 1.1 brad size_t i;
812 1.1 brad
813 1.1 brad node = *rnode;
814 1.1 brad sc = node.sysctl_data;
815 1.1 brad (void) memcpy(buf, sc->sc_periodic_rate, SHT3X_RATE_NAME);
816 1.1 brad node.sysctl_data = buf;
817 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node));
818 1.1 brad if (error || newp == NULL)
819 1.1 brad return error;
820 1.1 brad
821 1.1 brad for (i = 0; i < __arraycount(sht3x_periodic_rate); i++) {
822 1.1 brad if (strncmp(node.sysctl_data, sht3x_periodic_rate[i].rate,
823 1.1 brad SHT3X_RATE_NAME) == 0) {
824 1.1 brad break;
825 1.1 brad }
826 1.1 brad }
827 1.1 brad
828 1.1 brad if (i == __arraycount(sht3x_periodic_rate))
829 1.1 brad return EINVAL;
830 1.2 christos
831 1.1 brad (void) memcpy(sc->sc_periodic_rate, node.sysctl_data, SHT3X_RATE_NAME);
832 1.1 brad
833 1.1 brad if (sc->sc_isperiodic) {
834 1.1 brad sc->sc_initperiodic = true;
835 1.1 brad }
836 1.1 brad
837 1.1 brad return error;
838 1.1 brad }
839 1.1 brad
840 1.1 brad static int
841 1.1 brad sht3x_cmddelay(uint16_t cmd)
842 1.1 brad {
843 1.2 christos size_t i;
844 1.1 brad
845 1.2 christos for (i = 0; i < __arraycount(sht3x_timings); i++) {
846 1.1 brad if (cmd == sht3x_timings[i].cmd) {
847 1.1 brad break;
848 1.1 brad }
849 1.1 brad }
850 1.1 brad
851 1.2 christos if (i == __arraycount(sht3x_timings)) {
852 1.2 christos return -1;
853 1.1 brad }
854 1.2 christos return sht3x_timings[i].typicaldelay;
855 1.1 brad }
856 1.1 brad
857 1.1 brad static int
858 1.1 brad sht3x_cmd(i2c_tag_t tag, i2c_addr_t addr, uint16_t *cmd,
859 1.1 brad uint8_t clen, uint8_t *buf, size_t blen, int readattempts)
860 1.1 brad {
861 1.1 brad int error;
862 1.1 brad int cmddelay;
863 1.1 brad uint8_t cmd8[2];
864 1.1 brad
865 1.1 brad /* All commands are two bytes and must be in a proper order */
866 1.1 brad KASSERT(clen == 2);
867 1.1 brad
868 1.1 brad cmd8[0] = cmd[0] >> 8;
869 1.1 brad cmd8[1] = cmd[0] & 0x00ff;
870 1.1 brad
871 1.10 brad if (cmd[0] == SHT3X_MEASURE_REPEATABILITY_CS_HIGH ||
872 1.10 brad cmd[0] == SHT3X_MEASURE_REPEATABILITY_CS_MEDIUM ||
873 1.10 brad cmd[0] == SHT3X_MEASURE_REPEATABILITY_CS_LOW) {
874 1.10 brad error = iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd8[0], clen,
875 1.10 brad buf, blen, 0);
876 1.10 brad } else {
877 1.10 brad error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd8[0], clen,
878 1.10 brad NULL, 0, 0);
879 1.10 brad if (error)
880 1.10 brad return error;
881 1.2 christos
882 1.10 brad cmddelay = sht3x_cmddelay(cmd[0]);
883 1.10 brad if (cmddelay != -1) {
884 1.10 brad delay(cmddelay);
885 1.10 brad }
886 1.1 brad
887 1.10 brad /* Not all commands return anything */
888 1.10 brad if (blen == 0) {
889 1.10 brad return 0;
890 1.10 brad }
891 1.1 brad
892 1.10 brad for (int aint = 0; aint < readattempts; aint++) {
893 1.10 brad error = iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0, buf,
894 1.10 brad blen, 0);
895 1.10 brad if (error == 0)
896 1.10 brad break;
897 1.10 brad delay(1000);
898 1.10 brad }
899 1.1 brad }
900 1.1 brad
901 1.1 brad return error;
902 1.1 brad }
903 1.1 brad
904 1.1 brad static int
905 1.1 brad sht3x_cmdr(struct sht3x_sc *sc, uint16_t cmd, uint8_t *buf, size_t blen)
906 1.1 brad {
907 1.2 christos return sht3x_cmd(sc->sc_tag, sc->sc_addr, &cmd, 2, buf, blen,
908 1.2 christos sc->sc_readattempts);
909 1.1 brad }
910 1.1 brad
911 1.1 brad static uint8_t
912 1.2 christos sht3x_crc(uint8_t *data, size_t size)
913 1.1 brad {
914 1.1 brad uint8_t crc = 0xFF;
915 1.1 brad
916 1.1 brad for (size_t i = 0; i < size; i++) {
917 1.1 brad crc ^= data[i];
918 1.1 brad for (size_t j = 8; j > 0; j--) {
919 1.1 brad if (crc & 0x80)
920 1.1 brad crc = (crc << 1) ^ 0x31;
921 1.1 brad else
922 1.1 brad crc <<= 1;
923 1.1 brad }
924 1.1 brad }
925 1.1 brad return crc;
926 1.1 brad }
927 1.1 brad
928 1.1 brad static int
929 1.1 brad sht3x_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
930 1.1 brad {
931 1.1 brad uint16_t reg = SHT3X_GET_STATUS_REGISTER;
932 1.1 brad uint8_t buf[3];
933 1.1 brad int error;
934 1.1 brad
935 1.1 brad error = sht3x_cmd(tag, addr, ®, 2, buf, 3, 10);
936 1.1 brad if (matchdebug) {
937 1.1 brad printf("poke X 1: %d\n", error);
938 1.1 brad }
939 1.1 brad return error;
940 1.1 brad }
941 1.1 brad
942 1.1 brad static int
943 1.1 brad sht3x_sysctl_init(struct sht3x_sc *sc)
944 1.1 brad {
945 1.1 brad int error;
946 1.1 brad const struct sysctlnode *cnode;
947 1.1 brad int sysctlroot_num;
948 1.1 brad
949 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
950 1.1 brad 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
951 1.1 brad SYSCTL_DESCR("sht3x controls"), NULL, 0, NULL, 0, CTL_HW,
952 1.1 brad CTL_CREATE, CTL_EOL)) != 0)
953 1.1 brad return error;
954 1.1 brad
955 1.1 brad sysctlroot_num = cnode->sysctl_num;
956 1.1 brad
957 1.1 brad #ifdef SHT3X_DEBUG
958 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
959 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
960 1.1 brad SYSCTL_DESCR("Debug level"), sht3x_verify_sysctl, 0,
961 1.1 brad &sc->sc_sht3xdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
962 1.1 brad CTL_EOL)) != 0)
963 1.1 brad return error;
964 1.1 brad
965 1.1 brad #endif
966 1.1 brad
967 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
968 1.10 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "clockstretch",
969 1.10 brad SYSCTL_DESCR("Use clock stretch commands for measurements"), NULL, 0,
970 1.10 brad &sc->sc_clockstretch, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
971 1.10 brad CTL_EOL)) != 0)
972 1.10 brad return error;
973 1.10 brad
974 1.10 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
975 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
976 1.1 brad SYSCTL_DESCR("The number of times to attempt to read the values"),
977 1.1 brad sht3x_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
978 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
979 1.1 brad return error;
980 1.1 brad
981 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
982 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "modes",
983 1.1 brad SYSCTL_DESCR("Valid modes"), 0, 0,
984 1.1 brad __UNCONST(sht3x_mode_names),
985 1.1 brad sizeof(sht3x_mode_names) + 1,
986 1.1 brad CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
987 1.1 brad return error;
988 1.1 brad
989 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
990 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "mode",
991 1.1 brad SYSCTL_DESCR("Mode for measurement collection"),
992 1.1 brad sht3x_verify_sysctl_modes, 0, (void *) sc,
993 1.1 brad SHT3X_MODE_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
994 1.1 brad return error;
995 1.1 brad
996 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
997 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "repeatabilities",
998 1.1 brad SYSCTL_DESCR("Valid repeatability values"), 0, 0,
999 1.1 brad __UNCONST(sht3x_repeatability_names),
1000 1.1 brad sizeof(sht3x_repeatability_names) + 1,
1001 1.1 brad CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1002 1.1 brad return error;
1003 1.1 brad
1004 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
1005 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "repeatability",
1006 1.1 brad SYSCTL_DESCR("Repeatability of RH and Temp"),
1007 1.1 brad sht3x_verify_sysctl_repeatability, 0, (void *) sc,
1008 1.1 brad SHT3X_REP_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1009 1.1 brad return error;
1010 1.1 brad
1011 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
1012 1.1 brad CTLFLAG_READONLY, CTLTYPE_STRING, "rates",
1013 1.9 andvar SYSCTL_DESCR("Valid periodic rates"), 0, 0,
1014 1.1 brad __UNCONST(sht3x_rate_names),
1015 1.1 brad sizeof(sht3x_rate_names) + 1,
1016 1.1 brad CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1017 1.1 brad return error;
1018 1.1 brad
1019 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
1020 1.1 brad CTLFLAG_READWRITE, CTLTYPE_STRING, "rate",
1021 1.1 brad SYSCTL_DESCR("Rate for periodic measurements"),
1022 1.1 brad sht3x_verify_sysctl_rate, 0, (void *) sc,
1023 1.1 brad SHT3X_RATE_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1024 1.1 brad return error;
1025 1.1 brad
1026 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
1027 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
1028 1.1 brad SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
1029 1.1 brad 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1030 1.1 brad return error;
1031 1.1 brad
1032 1.1 brad if ((error = sysctl_createv(&sc->sc_sht3xlog, 0, NULL, &cnode,
1033 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
1034 1.1 brad SYSCTL_DESCR("Heater on"), sht3x_verify_sysctl_heateron, 0,
1035 1.1 brad (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
1036 1.1 brad return error;
1037 1.1 brad
1038 1.1 brad return 0;
1039 1.1 brad }
1040 1.1 brad
1041 1.1 brad static int
1042 1.1 brad sht3x_match(device_t parent, cfdata_t match, void *aux)
1043 1.1 brad {
1044 1.1 brad struct i2c_attach_args *ia = aux;
1045 1.1 brad int error, match_result;
1046 1.1 brad const bool matchdebug = false;
1047 1.1 brad
1048 1.1 brad if (iic_use_direct_match(ia, match, NULL, &match_result))
1049 1.1 brad return match_result;
1050 1.1 brad
1051 1.1 brad if (matchdebug) {
1052 1.1 brad printf("Looking at ia_addr: %x\n",ia->ia_addr);
1053 1.1 brad }
1054 1.1 brad
1055 1.1 brad /* indirect config - check for configured address */
1056 1.2 christos if (ia->ia_addr != SHT3X_TYPICAL_ADDR_1 &&
1057 1.2 christos ia->ia_addr != SHT3X_TYPICAL_ADDR_2)
1058 1.2 christos return 0;
1059 1.1 brad
1060 1.2 christos /*
1061 1.2 christos * Check to see if something is really at this i2c address.
1062 1.2 christos * This will keep phantom devices from appearing
1063 1.2 christos */
1064 1.2 christos if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
1065 1.2 christos if (matchdebug)
1066 1.2 christos printf("in match acquire bus failed\n");
1067 1.1 brad return 0;
1068 1.1 brad }
1069 1.2 christos
1070 1.2 christos error = sht3x_poke(ia->ia_tag, ia->ia_addr, matchdebug);
1071 1.2 christos iic_release_bus(ia->ia_tag, 0);
1072 1.2 christos
1073 1.2 christos return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
1074 1.1 brad }
1075 1.1 brad
1076 1.1 brad static void
1077 1.1 brad sht3x_attach(device_t parent, device_t self, void *aux)
1078 1.1 brad {
1079 1.1 brad struct sht3x_sc *sc;
1080 1.1 brad struct i2c_attach_args *ia;
1081 1.1 brad int error, i;
1082 1.1 brad int ecount = 0;
1083 1.1 brad uint8_t buf[6];
1084 1.1 brad uint32_t serialnumber;
1085 1.1 brad uint8_t sncrcpt1, sncrcpt2;
1086 1.1 brad
1087 1.1 brad ia = aux;
1088 1.1 brad sc = device_private(self);
1089 1.1 brad
1090 1.1 brad sc->sc_dev = self;
1091 1.1 brad sc->sc_tag = ia->ia_tag;
1092 1.1 brad sc->sc_addr = ia->ia_addr;
1093 1.1 brad sc->sc_sht3xdebug = 0;
1094 1.2 christos strlcpy(sc->sc_mode, "single-shot", SHT3X_MODE_NAME);
1095 1.1 brad sc->sc_isperiodic = false;
1096 1.2 christos strlcpy(sc->sc_repeatability, "high", SHT3X_REP_NAME);
1097 1.2 christos strlcpy(sc->sc_periodic_rate, "1.0mps", SHT3X_RATE_NAME);
1098 1.1 brad sc->sc_readattempts = 10;
1099 1.1 brad sc->sc_ignorecrc = false;
1100 1.1 brad sc->sc_heateron = false;
1101 1.1 brad sc->sc_sme = NULL;
1102 1.1 brad sc->sc_stopping = false;
1103 1.1 brad sc->sc_initperiodic = false;
1104 1.1 brad sc->sc_opened = false;
1105 1.10 brad sc->sc_clockstretch = false;
1106 1.1 brad sc->sc_dying = false;
1107 1.1 brad sc->sc_readpoolname = NULL;
1108 1.1 brad
1109 1.1 brad aprint_normal("\n");
1110 1.1 brad
1111 1.1 brad mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_NONE);
1112 1.1 brad mutex_init(&sc->sc_read_mutex, MUTEX_DEFAULT, IPL_NONE);
1113 1.1 brad mutex_init(&sc->sc_threadmutex, MUTEX_DEFAULT, IPL_NONE);
1114 1.1 brad mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
1115 1.1 brad cv_init(&sc->sc_condvar, "sht3xcv");
1116 1.1 brad cv_init(&sc->sc_condreadready, "sht3xread");
1117 1.1 brad cv_init(&sc->sc_cond_dying, "sht3xdie");
1118 1.1 brad sc->sc_numsensors = __arraycount(sht3x_sensors);
1119 1.1 brad
1120 1.1 brad if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
1121 1.1 brad aprint_error_dev(self,
1122 1.1 brad "Unable to create sysmon structure\n");
1123 1.1 brad sc->sc_sme = NULL;
1124 1.1 brad return;
1125 1.1 brad }
1126 1.1 brad if ((error = sht3x_sysctl_init(sc)) != 0) {
1127 1.1 brad aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
1128 1.1 brad goto out;
1129 1.1 brad }
1130 1.1 brad
1131 1.1 brad sc->sc_readpoolname = kmem_asprintf("sht3xrp%d",device_unit(self));
1132 1.2 christos sc->sc_readpool = pool_cache_init(sizeof(struct sht3x_read_q), 0, 0, 0,
1133 1.2 christos sc->sc_readpoolname, NULL, IPL_VM, NULL, NULL, NULL);
1134 1.1 brad pool_cache_sethiwat(sc->sc_readpool,100);
1135 1.1 brad
1136 1.1 brad SIMPLEQ_INIT(&sc->sc_read_queue);
1137 1.1 brad
1138 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
1139 1.1 brad if (error) {
1140 1.1 brad aprint_error_dev(self, "Could not acquire iic bus: %d\n",
1141 1.1 brad error);
1142 1.1 brad goto out;
1143 1.1 brad }
1144 1.1 brad
1145 1.1 brad error = sht3x_cmdr(sc, SHT3X_SOFT_RESET, NULL, 0);
1146 1.1 brad if (error != 0)
1147 1.1 brad aprint_error_dev(self, "Reset failed: %d\n", error);
1148 1.1 brad
1149 1.1 brad error = sht3x_clear_status_register(sc, true);
1150 1.1 brad if (error) {
1151 1.1 brad aprint_error_dev(self, "Failed to clear status register: %d\n",
1152 1.1 brad error);
1153 1.1 brad ecount++;
1154 1.1 brad }
1155 1.1 brad
1156 1.1 brad uint16_t status_reg;
1157 1.1 brad error = sht3x_get_status_register(sc, &status_reg, true);
1158 1.1 brad if (error) {
1159 1.1 brad aprint_error_dev(self, "Failed to read status register: %d\n",
1160 1.1 brad error);
1161 1.1 brad ecount++;
1162 1.1 brad }
1163 1.1 brad
1164 1.1 brad DPRINTF(sc, 2, ("%s: read status register values: %04x\n",
1165 1.1 brad device_xname(sc->sc_dev), status_reg));
1166 1.1 brad
1167 1.1 brad error = sht3x_cmdr(sc, SHT3X_READ_SERIAL_NUMBER, buf, 6);
1168 1.1 brad if (error) {
1169 1.1 brad aprint_error_dev(self, "Failed to read serial number: %d\n",
1170 1.1 brad error);
1171 1.1 brad ecount++;
1172 1.1 brad }
1173 1.1 brad
1174 1.1 brad sncrcpt1 = sht3x_crc(&buf[0],2);
1175 1.1 brad sncrcpt2 = sht3x_crc(&buf[3],2);
1176 1.1 brad serialnumber = (buf[0] << 24) | (buf[1] << 16) | (buf[3] << 8) | buf[4];
1177 1.1 brad
1178 1.2 christos DPRINTF(sc, 2, ("%s: read serial number values: %02x%02x - %02x - "
1179 1.2 christos "%02x%02x - %02x -- %02x %02x\n", device_xname(sc->sc_dev), buf[0],
1180 1.2 christos buf[1], buf[2], buf[3], buf[4], buf[5], sncrcpt1, sncrcpt2));
1181 1.1 brad
1182 1.1 brad iic_release_bus(sc->sc_tag, 0);
1183 1.1 brad if (error != 0) {
1184 1.1 brad aprint_error_dev(self, "Unable to setup device\n");
1185 1.1 brad goto out;
1186 1.1 brad }
1187 1.1 brad
1188 1.1 brad for (i = 0; i < sc->sc_numsensors; i++) {
1189 1.1 brad strlcpy(sc->sc_sensors[i].desc, sht3x_sensors[i].desc,
1190 1.1 brad sizeof(sc->sc_sensors[i].desc));
1191 1.1 brad
1192 1.1 brad sc->sc_sensors[i].units = sht3x_sensors[i].type;
1193 1.1 brad sc->sc_sensors[i].state = ENVSYS_SINVALID;
1194 1.1 brad
1195 1.1 brad DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
1196 1.1 brad sc->sc_sensors[i].desc));
1197 1.1 brad
1198 1.1 brad error = sysmon_envsys_sensor_attach(sc->sc_sme,
1199 1.1 brad &sc->sc_sensors[i]);
1200 1.1 brad if (error) {
1201 1.1 brad aprint_error_dev(self,
1202 1.1 brad "Unable to attach sensor %d: %d\n", i, error);
1203 1.1 brad goto out;
1204 1.1 brad }
1205 1.1 brad }
1206 1.1 brad
1207 1.1 brad sc->sc_sme->sme_name = device_xname(sc->sc_dev);
1208 1.1 brad sc->sc_sme->sme_cookie = sc;
1209 1.1 brad sc->sc_sme->sme_refresh = sht3x_refresh;
1210 1.1 brad
1211 1.1 brad DPRINTF(sc, 2, ("sht3x_attach: registering with envsys\n"));
1212 1.1 brad
1213 1.1 brad if (sysmon_envsys_register(sc->sc_sme)) {
1214 1.2 christos aprint_error_dev(self, "unable to register with sysmon\n");
1215 1.1 brad sysmon_envsys_destroy(sc->sc_sme);
1216 1.1 brad sc->sc_sme = NULL;
1217 1.1 brad return;
1218 1.1 brad }
1219 1.1 brad
1220 1.2 christos /*
1221 1.2 christos * There is no documented way to ask the chip what version it is. This
1222 1.2 christos * is likely fine as the only apparent difference is in how precise the
1223 1.2 christos * measurements will be. The actual conversation with the chip is
1224 1.2 christos * identical no matter which one you are talking to.
1225 1.2 christos */
1226 1.1 brad
1227 1.1 brad aprint_normal_dev(self, "Sensirion SHT30/SHT31/SHT35, "
1228 1.2 christos "Serial number: %x%s", serialnumber,
1229 1.1 brad (sncrcpt1 == buf[2] && sncrcpt2 == buf[5]) ? "\n" : " (bad crc)\n");
1230 1.1 brad return;
1231 1.1 brad out:
1232 1.1 brad sysmon_envsys_destroy(sc->sc_sme);
1233 1.1 brad sc->sc_sme = NULL;
1234 1.1 brad }
1235 1.1 brad
1236 1.1 brad static uint16_t
1237 1.10 brad sht3x_compute_measure_command_ss(const char *repeatability, bool clockstretch)
1238 1.1 brad {
1239 1.1 brad int i;
1240 1.1 brad uint16_t r;
1241 1.1 brad
1242 1.1 brad for (i = 0; i < __arraycount(sht3x_repeatability_ss); i++) {
1243 1.1 brad if (strncmp(repeatability, sht3x_repeatability_ss[i].text,
1244 1.1 brad SHT3X_REP_NAME) == 0) {
1245 1.10 brad if (clockstretch)
1246 1.10 brad r = sht3x_repeatability_ss[i].cscmd;
1247 1.10 brad else
1248 1.10 brad r = sht3x_repeatability_ss[i].cmd;
1249 1.1 brad break;
1250 1.1 brad }
1251 1.1 brad }
1252 1.1 brad
1253 1.1 brad if (i == __arraycount(sht3x_repeatability_ss))
1254 1.2 christos panic("Single-shot could not find command for "
1255 1.2 christos "repeatability: %s\n", repeatability);
1256 1.1 brad
1257 1.1 brad return r;
1258 1.1 brad }
1259 1.1 brad
1260 1.1 brad /*
1261 1.2 christos * The documented conversion calculations for the raw values are as follows:
1262 1.2 christos *
1263 1.2 christos * %RH = (-6 + 125 * rawvalue / 65535)
1264 1.2 christos *
1265 1.2 christos * T in Celsius = (-45 + 175 * rawvalue / 65535)
1266 1.2 christos *
1267 1.2 christos * It follows then:
1268 1.2 christos *
1269 1.2 christos * T in Kelvin = (228.15 + 175 * rawvalue / 65535)
1270 1.2 christos *
1271 1.2 christos * given the relationship between Celsius and Kelvin
1272 1.2 christos *
1273 1.2 christos * What follows reorders the calculation a bit and scales it up to avoid
1274 1.2 christos * the use of any floating point. All that would really have to happen
1275 1.2 christos * is a scale up to 10^6 for the sysenv framework, which wants
1276 1.2 christos * temperature in micro-kelvin and percent relative humidity scaled up
1277 1.2 christos * 10^6, but since this conversion uses 64 bits due to intermediate
1278 1.2 christos * values that are bigger than 32 bits the conversion first scales up to
1279 1.2 christos * 10^9 and the scales back down by 10^3 at the end. This preserves some
1280 1.2 christos * precision in the conversion that would otherwise be lost.
1281 1.2 christos */
1282 1.1 brad
1283 1.1 brad static uint64_t
1284 1.1 brad sht3x_compute_temp_from_raw(uint8_t msb, uint8_t lsb) {
1285 1.1 brad uint64_t svalue;
1286 1.1 brad int64_t v1;
1287 1.1 brad uint64_t v2;
1288 1.1 brad uint64_t d1 = 65535;
1289 1.1 brad uint64_t mul1;
1290 1.1 brad uint64_t mul2;
1291 1.1 brad uint64_t div1 = 10000;
1292 1.1 brad uint64_t q;
1293 1.1 brad
1294 1.1 brad svalue = msb << 8 | lsb;
1295 1.1 brad
1296 1.1 brad v1 = 22815; /* this is scaled up already from 228.15 */
1297 1.1 brad v2 = 175;
1298 1.1 brad mul1 = 10000000000;
1299 1.1 brad mul2 = 100000000;
1300 1.1 brad
1301 1.1 brad svalue = svalue * mul1;
1302 1.1 brad v1 = v1 * mul2;
1303 1.1 brad /* Perform the conversion */
1304 1.1 brad q = ((v2 * (svalue / d1)) + v1) / div1;
1305 1.1 brad
1306 1.1 brad return q;
1307 1.1 brad }
1308 1.1 brad
1309 1.1 brad static uint64_t
1310 1.1 brad sht3x_compute_rh_from_raw(uint8_t msb, uint8_t lsb) {
1311 1.1 brad uint64_t svalue;
1312 1.1 brad int64_t v1;
1313 1.1 brad uint64_t v2;
1314 1.1 brad uint64_t d1 = 65535;
1315 1.1 brad uint64_t mul1;
1316 1.1 brad uint64_t mul2;
1317 1.1 brad uint64_t div1 = 10000;
1318 1.1 brad uint64_t q;
1319 1.1 brad
1320 1.1 brad svalue = msb << 8 | lsb;
1321 1.1 brad
1322 1.1 brad v1 = 0;
1323 1.1 brad v2 = 100;
1324 1.1 brad mul1 = 10000000000;
1325 1.1 brad mul2 = 10000000000;
1326 1.1 brad
1327 1.1 brad svalue = svalue * mul1;
1328 1.1 brad v1 = v1 * mul2;
1329 1.1 brad /* Perform the conversion */
1330 1.1 brad q = ((v2 * (svalue / d1)) + v1) / div1;
1331 1.1 brad
1332 1.1 brad return q;
1333 1.1 brad }
1334 1.1 brad
1335 1.2 christos static int
1336 1.2 christos sht3x_parse_data(struct sht3x_sc *sc, envsys_data_t *edata, uint8_t *rawdata)
1337 1.1 brad {
1338 1.1 brad uint64_t current_value;
1339 1.1 brad uint8_t *svalptr;
1340 1.1 brad
1341 1.2 christos DPRINTF(sc, 2, ("%s: Raw data: %02x%02x %02x - %02x%02x %02x\n",
1342 1.2 christos device_xname(sc->sc_dev), rawdata[0], rawdata[1], rawdata[2],
1343 1.2 christos rawdata[3], rawdata[4], rawdata[5]));
1344 1.1 brad
1345 1.1 brad switch (edata->sensor) {
1346 1.1 brad case SHT3X_TEMP_SENSOR:
1347 1.2 christos current_value = sht3x_compute_temp_from_raw(rawdata[0],
1348 1.2 christos rawdata[1]);
1349 1.2 christos svalptr = &rawdata[0];
1350 1.1 brad break;
1351 1.1 brad case SHT3X_HUMIDITY_SENSOR:
1352 1.2 christos current_value = sht3x_compute_rh_from_raw(rawdata[3],
1353 1.2 christos rawdata[4]);
1354 1.2 christos svalptr = &rawdata[3];
1355 1.1 brad break;
1356 1.1 brad default:
1357 1.2 christos DPRINTF(sc, 2, ("%s: bad sensor type %d\n",
1358 1.2 christos device_xname(sc->sc_dev), edata->sensor));
1359 1.2 christos return EINTR;
1360 1.2 christos }
1361 1.2 christos uint8_t testcrc;
1362 1.2 christos /* Fake out the CRC check if being asked to ignore CRC */
1363 1.2 christos if (sc->sc_ignorecrc) {
1364 1.2 christos testcrc = *(svalptr + 2);
1365 1.2 christos } else {
1366 1.2 christos testcrc = sht3x_crc(svalptr, 2);
1367 1.1 brad }
1368 1.1 brad
1369 1.2 christos if (*(svalptr + 2) != testcrc) {
1370 1.2 christos DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d != %d\n",
1371 1.2 christos device_xname(sc->sc_dev), (*svalptr + 2), testcrc));
1372 1.2 christos return EINVAL;
1373 1.1 brad }
1374 1.2 christos edata->value_cur = (uint32_t) current_value;
1375 1.2 christos edata->state = ENVSYS_SVALID;
1376 1.2 christos return 0;
1377 1.1 brad }
1378 1.1 brad
1379 1.2 christos static int
1380 1.2 christos sht3x_refresh_periodic(struct sysmon_envsys *sme, envsys_data_t *edata)
1381 1.1 brad {
1382 1.2 christos struct sht3x_sc *sc = sme->sme_cookie;
1383 1.2 christos uint8_t rawdata[sizeof(sc->sc_pbuffer)];
1384 1.1 brad
1385 1.2 christos memcpy(rawdata, sc->sc_pbuffer, sizeof(rawdata));
1386 1.1 brad
1387 1.2 christos return sht3x_parse_data(sc, edata, rawdata);
1388 1.1 brad
1389 1.1 brad }
1390 1.1 brad
1391 1.2 christos static int
1392 1.2 christos sht3x_refresh_oneshot(struct sysmon_envsys *sme, envsys_data_t *edata)
1393 1.1 brad {
1394 1.1 brad struct sht3x_sc *sc = sme->sme_cookie;
1395 1.2 christos uint16_t measurement_command_ss;
1396 1.2 christos uint8_t rawdata[sizeof(sc->sc_pbuffer)];
1397 1.1 brad int error;
1398 1.1 brad
1399 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0);
1400 1.1 brad if (error) {
1401 1.1 brad DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
1402 1.1 brad device_xname(sc->sc_dev), error));
1403 1.2 christos return error;
1404 1.1 brad }
1405 1.1 brad
1406 1.2 christos measurement_command_ss = sht3x_compute_measure_command_ss(
1407 1.10 brad sc->sc_repeatability, sc->sc_clockstretch);
1408 1.2 christos error = sht3x_cmdr(sc, measurement_command_ss, rawdata, sizeof(rawdata));
1409 1.4 brad DPRINTF(sc, 2, ("%s: Status for single-shot measurement cmd %04x "
1410 1.4 brad "Error %d\n", device_xname(sc->sc_dev), measurement_command_ss, error));
1411 1.2 christos if (error == 0) {
1412 1.4 brad error = sht3x_parse_data(sc, edata, rawdata);
1413 1.1 brad }
1414 1.1 brad
1415 1.2 christos uint16_t sbuf;
1416 1.2 christos int status_error = sht3x_get_status_register(sc, &sbuf, true);
1417 1.1 brad
1418 1.2 christos if (!status_error) {
1419 1.2 christos DPRINTF(sc, 2, ("%s: read status register single-shot: %04x\n",
1420 1.2 christos device_xname(sc->sc_dev), sbuf));
1421 1.1 brad
1422 1.2 christos if (sbuf & SHT3X_RESET_DETECTED) {
1423 1.2 christos aprint_error_dev(sc->sc_dev,
1424 1.2 christos "Reset detected in single shot mode. "
1425 1.2 christos "Heater may have been reset\n");
1426 1.2 christos sht3x_clear_status_register(sc, true);
1427 1.2 christos }
1428 1.1 brad
1429 1.2 christos sc->sc_heateron = sbuf & SHT3X_HEATER_STATUS;
1430 1.1 brad }
1431 1.1 brad
1432 1.2 christos iic_release_bus(sc->sc_tag, 0);
1433 1.4 brad
1434 1.4 brad return error;
1435 1.2 christos }
1436 1.1 brad
1437 1.2 christos static void
1438 1.2 christos sht3x_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1439 1.2 christos {
1440 1.2 christos struct sht3x_sc *sc = sme->sme_cookie;
1441 1.1 brad
1442 1.2 christos edata->state = ENVSYS_SINVALID;
1443 1.1 brad
1444 1.2 christos mutex_enter(&sc->sc_mutex);
1445 1.1 brad
1446 1.2 christos if (sc->sc_isperiodic) {
1447 1.2 christos sht3x_refresh_periodic(sme, edata);
1448 1.2 christos } else {
1449 1.2 christos sht3x_refresh_oneshot(sme, edata);
1450 1.1 brad }
1451 1.1 brad
1452 1.1 brad mutex_exit(&sc->sc_mutex);
1453 1.1 brad }
1454 1.1 brad
1455 1.1 brad static int
1456 1.1 brad sht3xopen(dev_t dev, int flags, int fmt, struct lwp *l)
1457 1.1 brad {
1458 1.1 brad struct sht3x_sc *sc;
1459 1.1 brad
1460 1.1 brad sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
1461 1.1 brad if (!sc)
1462 1.2 christos return ENXIO;
1463 1.1 brad
1464 1.1 brad if (sc->sc_opened)
1465 1.2 christos return EBUSY;
1466 1.1 brad
1467 1.1 brad mutex_enter(&sc->sc_mutex);
1468 1.1 brad sc->sc_opened = true;
1469 1.1 brad
1470 1.1 brad sc->sc_wassingleshot = false;
1471 1.1 brad if (!sc->sc_isperiodic) {
1472 1.1 brad sc->sc_stopping = false;
1473 1.1 brad sc->sc_initperiodic = true;
1474 1.1 brad sc->sc_isperiodic = true;
1475 1.1 brad sc->sc_wassingleshot = true;
1476 1.1 brad sht3x_start_thread(sc);
1477 1.1 brad }
1478 1.1 brad mutex_exit(&sc->sc_mutex);
1479 1.1 brad
1480 1.2 christos return 0;
1481 1.1 brad }
1482 1.1 brad
1483 1.1 brad static int
1484 1.1 brad sht3xread(dev_t dev, struct uio *uio, int flags)
1485 1.1 brad {
1486 1.1 brad struct sht3x_sc *sc;
1487 1.1 brad struct sht3x_read_q *pp;
1488 1.1 brad int error,any;
1489 1.1 brad
1490 1.1 brad sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
1491 1.1 brad if (!sc)
1492 1.2 christos return ENXIO;
1493 1.1 brad
1494 1.1 brad while (uio->uio_resid) {
1495 1.1 brad any = 0;
1496 1.1 brad error = 0;
1497 1.1 brad mutex_enter(&sc->sc_read_mutex);
1498 1.1 brad
1499 1.1 brad while (any == 0) {
1500 1.1 brad pp = SIMPLEQ_FIRST(&sc->sc_read_queue);
1501 1.1 brad if (pp != NULL) {
1502 1.1 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
1503 1.1 brad any = 1;
1504 1.1 brad break;
1505 1.1 brad }
1506 1.2 christos error = cv_wait_sig(&sc->sc_condreadready,
1507 1.2 christos &sc->sc_read_mutex);
1508 1.2 christos if (sc->sc_dying)
1509 1.2 christos error = EIO;
1510 1.2 christos if (error == 0)
1511 1.2 christos continue;
1512 1.2 christos break;
1513 1.1 brad }
1514 1.1 brad
1515 1.1 brad if (any == 1 && error == 0) {
1516 1.2 christos uint8_t *p = pp->measurement;
1517 1.1 brad mutex_exit(&sc->sc_read_mutex);
1518 1.1 brad pool_cache_put(sc->sc_readpool,pp);
1519 1.1 brad
1520 1.2 christos DPRINTF(sc,2, ("%s: sending %02x%02x %02x -- %02x%02x "
1521 1.2 christos "%02x -- %x\n", device_xname(sc->sc_dev), p[0],
1522 1.2 christos p[1], p[2], p[3], p[4], p[5],
1523 1.2 christos mutex_owned(&sc->sc_read_mutex)));
1524 1.2 christos if ((error = uiomove(pp->measurement,
1525 1.2 christos sizeof(pp->measurement), uio)) != 0) {
1526 1.2 christos DPRINTF(sc,2, ("%s: send error %d\n",
1527 1.2 christos device_xname(sc->sc_dev), error));
1528 1.1 brad break;
1529 1.1 brad }
1530 1.1 brad } else {
1531 1.1 brad mutex_exit(&sc->sc_read_mutex);
1532 1.1 brad if (error) {
1533 1.1 brad break;
1534 1.1 brad }
1535 1.1 brad }
1536 1.1 brad }
1537 1.1 brad
1538 1.1 brad DPRINTF(sc,2, ("%s: loop done: %d\n",device_xname(sc->sc_dev),error));
1539 1.1 brad if (sc->sc_dying) {
1540 1.1 brad DPRINTF(sc, 2, ("%s: Telling all we are almost dead\n",
1541 1.1 brad device_xname(sc->sc_dev)));
1542 1.1 brad mutex_enter(&sc->sc_dying_mutex);
1543 1.1 brad cv_signal(&sc->sc_cond_dying);
1544 1.1 brad mutex_exit(&sc->sc_dying_mutex);
1545 1.1 brad }
1546 1.1 brad return error;
1547 1.1 brad }
1548 1.1 brad
1549 1.1 brad static int
1550 1.1 brad sht3xclose(dev_t dev, int flags, int fmt, struct lwp *l)
1551 1.1 brad {
1552 1.1 brad struct sht3x_sc *sc;
1553 1.1 brad struct sht3x_read_q *pp;
1554 1.1 brad
1555 1.1 brad sc = device_lookup_private(&sht3xtemp_cd, minor(dev));
1556 1.1 brad
1557 1.1 brad if (sc->sc_wassingleshot) {
1558 1.1 brad sht3x_stop_thread(sc);
1559 1.1 brad sc->sc_stopping = false;
1560 1.1 brad sc->sc_initperiodic = false;
1561 1.1 brad sc->sc_isperiodic = false;
1562 1.1 brad }
1563 1.1 brad
1564 1.1 brad mutex_enter(&sc->sc_mutex);
1565 1.1 brad /* Drain any read pools */
1566 1.1 brad while ((pp = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
1567 1.1 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
1568 1.1 brad pool_cache_put(sc->sc_readpool,pp);
1569 1.1 brad }
1570 1.1 brad
1571 1.1 brad /* Say that the device is now free */
1572 1.1 brad sc->sc_opened = false;
1573 1.1 brad mutex_exit(&sc->sc_mutex);
1574 1.1 brad
1575 1.1 brad return(0);
1576 1.1 brad }
1577 1.1 brad
1578 1.1 brad static int
1579 1.1 brad sht3x_detach(device_t self, int flags)
1580 1.1 brad {
1581 1.1 brad struct sht3x_sc *sc;
1582 1.1 brad struct sht3x_read_q *pp;
1583 1.1 brad
1584 1.1 brad sc = device_private(self);
1585 1.1 brad
1586 1.1 brad if (sc->sc_isperiodic) {
1587 1.1 brad sht3x_stop_thread(sc);
1588 1.1 brad }
1589 1.1 brad
1590 1.1 brad mutex_enter(&sc->sc_mutex);
1591 1.1 brad
1592 1.1 brad sc->sc_dying = true;
1593 1.1 brad
1594 1.1 brad /* If this is true we are still open, destroy the condvar */
1595 1.1 brad if (sc->sc_opened) {
1596 1.1 brad mutex_enter(&sc->sc_dying_mutex);
1597 1.1 brad mutex_enter(&sc->sc_read_mutex);
1598 1.1 brad cv_signal(&sc->sc_condreadready);
1599 1.1 brad mutex_exit(&sc->sc_read_mutex);
1600 1.1 brad DPRINTF(sc, 2, ("%s: Will wait for anything to exit\n",
1601 1.1 brad device_xname(sc->sc_dev)));
1602 1.4 brad /* In the worst case this will time out after 5 seconds.
1603 1.4 brad * It really should not take that long for the drain / whatever
1604 1.4 brad * to happen
1605 1.4 brad */
1606 1.2 christos cv_timedwait_sig(&sc->sc_cond_dying,
1607 1.2 christos &sc->sc_dying_mutex, mstohz(5000));
1608 1.1 brad mutex_exit(&sc->sc_dying_mutex);
1609 1.1 brad cv_destroy(&sc->sc_condreadready);
1610 1.1 brad cv_destroy(&sc->sc_cond_dying);
1611 1.1 brad }
1612 1.1 brad
1613 1.1 brad /* Drain any read pools */
1614 1.1 brad while ((pp = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
1615 1.1 brad SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
1616 1.1 brad pool_cache_put(sc->sc_readpool,pp);
1617 1.1 brad }
1618 1.1 brad
1619 1.1 brad /* Destroy the pool cache now that nothing is using it */
1620 1.1 brad pool_cache_destroy(sc->sc_readpool);
1621 1.1 brad
1622 1.1 brad /* Remove the sensors */
1623 1.1 brad if (sc->sc_sme != NULL) {
1624 1.1 brad sysmon_envsys_unregister(sc->sc_sme);
1625 1.1 brad sc->sc_sme = NULL;
1626 1.1 brad }
1627 1.1 brad mutex_exit(&sc->sc_mutex);
1628 1.1 brad
1629 1.1 brad /* Remove the sysctl tree */
1630 1.1 brad sysctl_teardown(&sc->sc_sht3xlog);
1631 1.1 brad
1632 1.1 brad /* Remove the mutex */
1633 1.1 brad mutex_destroy(&sc->sc_mutex);
1634 1.1 brad mutex_destroy(&sc->sc_threadmutex);
1635 1.1 brad mutex_destroy(&sc->sc_read_mutex);
1636 1.1 brad mutex_destroy(&sc->sc_dying_mutex);
1637 1.1 brad
1638 1.1 brad /* Free the poolname string */
1639 1.1 brad if (sc->sc_readpoolname != NULL) {
1640 1.1 brad kmem_free(sc->sc_readpoolname,strlen(sc->sc_readpoolname) + 1);
1641 1.1 brad }
1642 1.1 brad
1643 1.1 brad return 0;
1644 1.1 brad }
1645 1.1 brad
1646 1.1 brad int
1647 1.1 brad sht3x_activate(device_t self, enum devact act)
1648 1.1 brad {
1649 1.1 brad struct sht3x_sc *sc = device_private(self);
1650 1.1 brad
1651 1.1 brad switch (act) {
1652 1.1 brad case DVACT_DEACTIVATE:
1653 1.1 brad sc->sc_dying = true;
1654 1.1 brad return 0;
1655 1.1 brad default:
1656 1.1 brad return EOPNOTSUPP;
1657 1.1 brad }
1658 1.1 brad }
1659 1.1 brad
1660 1.5 pgoyette MODULE(MODULE_CLASS_DRIVER, sht3xtemp, "iic,sysmon_envsys");
1661 1.1 brad
1662 1.1 brad #ifdef _MODULE
1663 1.1 brad #include "ioconf.c"
1664 1.1 brad #endif
1665 1.1 brad
1666 1.1 brad static int
1667 1.1 brad sht3xtemp_modcmd(modcmd_t cmd, void *opaque)
1668 1.1 brad {
1669 1.1 brad int error;
1670 1.1 brad #ifdef _MODULE
1671 1.1 brad int bmaj = -1, cmaj = -1;
1672 1.1 brad #endif
1673 1.1 brad
1674 1.1 brad switch (cmd) {
1675 1.1 brad case MODULE_CMD_INIT:
1676 1.1 brad #ifdef _MODULE
1677 1.1 brad error = devsw_attach("sht3xtemp", NULL, &bmaj,
1678 1.1 brad &sht3x_cdevsw, &cmaj);
1679 1.1 brad if (error) {
1680 1.1 brad aprint_error("%s: unable to attach devsw\n",
1681 1.1 brad sht3xtemp_cd.cd_name);
1682 1.6 pgoyette return error;
1683 1.6 pgoyette }
1684 1.6 pgoyette
1685 1.6 pgoyette error = config_init_component(cfdriver_ioconf_sht3xtemp,
1686 1.6 pgoyette cfattach_ioconf_sht3xtemp, cfdata_ioconf_sht3xtemp);
1687 1.6 pgoyette if (error) {
1688 1.6 pgoyette aprint_error("%s: unable to init component\n",
1689 1.6 pgoyette sht3xtemp_cd.cd_name);
1690 1.6 pgoyette devsw_detach(NULL, &sht3x_cdevsw);
1691 1.1 brad }
1692 1.1 brad return error;
1693 1.1 brad #else
1694 1.1 brad return 0;
1695 1.1 brad #endif
1696 1.1 brad case MODULE_CMD_FINI:
1697 1.1 brad #ifdef _MODULE
1698 1.6 pgoyette error = config_fini_component(cfdriver_ioconf_sht3xtemp,
1699 1.6 pgoyette cfattach_ioconf_sht3xtemp, cfdata_ioconf_sht3xtemp);
1700 1.1 brad devsw_detach(NULL, &sht3x_cdevsw);
1701 1.6 pgoyette return error;
1702 1.1 brad #else
1703 1.1 brad return 0;
1704 1.1 brad #endif
1705 1.1 brad default:
1706 1.1 brad return ENOTTY;
1707 1.1 brad }
1708 1.1 brad }
1709