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