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