1 /* $NetBSD: sht4x.c,v 1.3 2022/03/30 00:06:50 pgoyette Exp $ */
2
3 /*
4 * Copyright (c) 2021 Brad Spencer <brad@anduin.eldar.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/cdefs.h>
20 __KERNEL_RCSID(0, "$NetBSD: sht4x.c,v 1.3 2022/03/30 00:06:50 pgoyette Exp $");
21
22 /*
23 Driver for the Sensirion SHT40/SHT41/SHT45
24 */
25
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/kernel.h>
29 #include <sys/device.h>
30 #include <sys/module.h>
31 #include <sys/sysctl.h>
32 #include <sys/mutex.h>
33
34 #include <dev/sysmon/sysmonvar.h>
35 #include <dev/i2c/i2cvar.h>
36 #include <dev/i2c/sht4xreg.h>
37 #include <dev/i2c/sht4xvar.h>
38
39
40 static uint8_t sht4x_crc(uint8_t *, size_t);
41 static int sht4x_poke(i2c_tag_t, i2c_addr_t, bool);
42 static int sht4x_match(device_t, cfdata_t, void *);
43 static void sht4x_attach(device_t, device_t, void *);
44 static int sht4x_detach(device_t, int);
45 static void sht4x_refresh(struct sysmon_envsys *, envsys_data_t *);
46 static int sht4x_verify_sysctl(SYSCTLFN_ARGS);
47 static int sht4x_verify_sysctl_resolution(SYSCTLFN_ARGS);
48 static int sht4x_verify_sysctl_heateron(SYSCTLFN_ARGS);
49 static int sht4x_verify_sysctl_heatervalue(SYSCTLFN_ARGS);
50 static int sht4x_verify_sysctl_heaterpulse(SYSCTLFN_ARGS);
51
52 #define SHT4X_DEBUG
53 #ifdef SHT4X_DEBUG
54 #define DPRINTF(s, l, x) \
55 do { \
56 if (l <= s->sc_sht4xdebug) \
57 printf x; \
58 } while (/*CONSTCOND*/0)
59 #else
60 #define DPRINTF(s, l, x)
61 #endif
62
63 CFATTACH_DECL_NEW(sht4xtemp, sizeof(struct sht4x_sc),
64 sht4x_match, sht4x_attach, sht4x_detach, NULL);
65
66 static struct sht4x_sensor sht4x_sensors[] = {
67 {
68 .desc = "humidity",
69 .type = ENVSYS_SRELHUMIDITY,
70 },
71 {
72 .desc = "temperature",
73 .type = ENVSYS_STEMP,
74 }
75 };
76
77 /* The typical delays are documented in the datasheet for the chip.
78 There is no need to be very accurate with these, just rough estimates
79 will work fine.
80 */
81
82 static struct sht4x_timing sht4x_timings[] = {
83 {
84 .cmd = SHT4X_READ_SERIAL,
85 .typicaldelay = 5000,
86 },
87 {
88 .cmd = SHT4X_SOFT_RESET,
89 .typicaldelay = 1000,
90 },
91 {
92 .cmd = SHT4X_MEASURE_HIGH_PRECISION,
93 .typicaldelay = 8000,
94 },
95 {
96 .cmd = SHT4X_MEASURE_MEDIUM_PRECISION,
97 .typicaldelay = 4000,
98 },
99 {
100 .cmd = SHT4X_MEASURE_LOW_PRECISION,
101 .typicaldelay = 2000,
102 },
103 {
104 .cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_1_S,
105 .typicaldelay = 1000000,
106 },
107 {
108 .cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_1_S,
109 .typicaldelay = 1000000,
110 },
111 {
112 .cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_1_S,
113 .typicaldelay = 1000000,
114 },
115 {
116 .cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_TENTH_S,
117 .typicaldelay = 100000,
118 },
119 {
120 .cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_TENTH_S,
121 .typicaldelay = 100000,
122 },
123 {
124 .cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_TENTH_S,
125 .typicaldelay = 100000,
126 }
127 };
128
129 /* Used when the heater is not on to find the command to use for the
130 * measurement.
131 */
132
133 static struct sht4x_resolution sht4x_resolutions[] = {
134 {
135 .text = "high",
136 .cmd = SHT4X_MEASURE_HIGH_PRECISION,
137 },
138 {
139 .text = "medium",
140 .cmd = SHT4X_MEASURE_MEDIUM_PRECISION,
141 },
142 {
143 .text = "low",
144 .cmd = SHT4X_MEASURE_LOW_PRECISION,
145 }
146 };
147
148 static const char sht4x_resolution_names[] =
149 "high, medium, low";
150
151 static struct sht4x_heaterpulse sht4x_heaterpulses[] = {
152 {
153 .length = "short",
154 },
155 {
156 .length = "long",
157 }
158 };
159
160 /* This is consulted when the heater is on for which command is to be
161 used for the measurement.
162 */
163
164 static struct sht4x_heateron_command sht4x_heateron_commands[] = {
165 {
166 .heatervalue = 1,
167 .pulselength = "short",
168 .cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_TENTH_S,
169 },
170 {
171 .heatervalue = 2,
172 .pulselength = "short",
173 .cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_TENTH_S,
174 },
175 {
176 .heatervalue = 3,
177 .pulselength = "short",
178 .cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_TENTH_S,
179 },
180 {
181 .heatervalue = 1,
182 .pulselength = "long",
183 .cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_1_S,
184 },
185 {
186 .heatervalue = 2,
187 .pulselength = "long",
188 .cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_1_S,
189 },
190 {
191 .heatervalue = 3,
192 .pulselength = "long",
193 .cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_1_S,
194 }
195 };
196
197 static const char sht4x_heaterpulse_names[] =
198 "short, long";
199
200 int
sht4x_verify_sysctl(SYSCTLFN_ARGS)201 sht4x_verify_sysctl(SYSCTLFN_ARGS)
202 {
203 int error, t;
204 struct sysctlnode node;
205
206 node = *rnode;
207 t = *(int *)rnode->sysctl_data;
208 node.sysctl_data = &t;
209 error = sysctl_lookup(SYSCTLFN_CALL(&node));
210 if (error || newp == NULL)
211 return error;
212
213 if (t < 0)
214 return EINVAL;
215
216 *(int *)rnode->sysctl_data = t;
217
218 return 0;
219 }
220
221 /* None of the heater and resolutions sysctls change anything on the chip in
222 real time. The values set are used to send different commands depending on
223 how they are set up.
224
225 What this implies is that the chip could be reset and the driver would not care.
226
227 */
228
229 int
sht4x_verify_sysctl_resolution(SYSCTLFN_ARGS)230 sht4x_verify_sysctl_resolution(SYSCTLFN_ARGS)
231 {
232 char buf[SHT4X_RES_NAME];
233 struct sht4x_sc *sc;
234 struct sysctlnode node;
235 int error = 0;
236 size_t i;
237
238 node = *rnode;
239 sc = node.sysctl_data;
240 (void) memcpy(buf, sc->sc_resolution, SHT4X_RES_NAME);
241 node.sysctl_data = buf;
242 error = sysctl_lookup(SYSCTLFN_CALL(&node));
243 if (error || newp == NULL)
244 return error;
245
246 for (i = 0; i < __arraycount(sht4x_resolutions); i++) {
247 if (strncmp(node.sysctl_data, sht4x_resolutions[i].text,
248 SHT4X_RES_NAME) == 0) {
249 break;
250 }
251 }
252
253 if (i == __arraycount(sht4x_resolutions))
254 return EINVAL;
255 (void) memcpy(sc->sc_resolution, node.sysctl_data, SHT4X_RES_NAME);
256
257 return error;
258 }
259
260 int
sht4x_verify_sysctl_heateron(SYSCTLFN_ARGS)261 sht4x_verify_sysctl_heateron(SYSCTLFN_ARGS)
262 {
263 int error;
264 bool t;
265 struct sht4x_sc *sc;
266 struct sysctlnode node;
267
268 node = *rnode;
269 sc = node.sysctl_data;
270 t = sc->sc_heateron;
271 node.sysctl_data = &t;
272 error = sysctl_lookup(SYSCTLFN_CALL(&node));
273 if (error || newp == NULL)
274 return error;
275
276 sc->sc_heateron = t;
277
278 return error;
279 }
280
281 int
sht4x_verify_sysctl_heatervalue(SYSCTLFN_ARGS)282 sht4x_verify_sysctl_heatervalue(SYSCTLFN_ARGS)
283 {
284 int error = 0, t;
285 struct sht4x_sc *sc;
286 struct sysctlnode node;
287
288 node = *rnode;
289 sc = node.sysctl_data;
290 t = sc->sc_heaterval;
291 node.sysctl_data = &t;
292 error = sysctl_lookup(SYSCTLFN_CALL(&node));
293 if (error || newp == NULL)
294 return (error);
295
296 if (t < 1 || t > 3)
297 return (EINVAL);
298
299 sc->sc_heaterval = t;
300
301 return error;
302 }
303
304 int
sht4x_verify_sysctl_heaterpulse(SYSCTLFN_ARGS)305 sht4x_verify_sysctl_heaterpulse(SYSCTLFN_ARGS)
306 {
307 char buf[SHT4X_PULSE_NAME];
308 struct sht4x_sc *sc;
309 struct sysctlnode node;
310 int error = 0;
311 size_t i;
312
313 node = *rnode;
314 sc = node.sysctl_data;
315 (void) memcpy(buf, sc->sc_heaterpulse, SHT4X_PULSE_NAME);
316 node.sysctl_data = buf;
317 error = sysctl_lookup(SYSCTLFN_CALL(&node));
318 if (error || newp == NULL)
319 return error;
320
321 for (i = 0; i < __arraycount(sht4x_heaterpulses); i++) {
322 if (strncmp(node.sysctl_data, sht4x_heaterpulses[i].length,
323 SHT4X_RES_NAME) == 0) {
324 break;
325 }
326 }
327
328 if (i == __arraycount(sht4x_heaterpulses))
329 return EINVAL;
330 (void) memcpy(sc->sc_heaterpulse, node.sysctl_data, SHT4X_PULSE_NAME);
331
332 return error;
333 }
334
335 static int
sht4x_cmddelay(uint8_t cmd)336 sht4x_cmddelay(uint8_t cmd)
337 {
338 int r = -1;
339
340 for(int i = 0;i < __arraycount(sht4x_timings);i++) {
341 if (cmd == sht4x_timings[i].cmd) {
342 r = sht4x_timings[i].typicaldelay;
343 break;
344 }
345 }
346
347 if (r == -1) {
348 panic("Bad command look up in cmd delay: cmd: %d\n",cmd);
349 }
350
351 return r;
352 }
353
354 static int
sht4x_cmd(i2c_tag_t tag,i2c_addr_t addr,uint8_t * cmd,uint8_t clen,uint8_t * buf,size_t blen,int readattempts)355 sht4x_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
356 uint8_t clen, uint8_t *buf, size_t blen, int readattempts)
357 {
358 int error;
359 int cmddelay;
360
361 error = iic_exec(tag,I2C_OP_WRITE_WITH_STOP,addr,cmd,clen,NULL,0,0);
362
363 /* Every command returns something except for the soft reset
364 which returns nothing. This chip is also nice in that pretty
365 much every command that returns something does it in the same way.
366 */
367 if (error == 0 && cmd[0] != SHT4X_SOFT_RESET) {
368 cmddelay = sht4x_cmddelay(cmd[0]);
369 delay(cmddelay);
370
371 for (int aint = 0; aint < readattempts; aint++) {
372 error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,buf,blen,0);
373 if (error == 0)
374 break;
375 delay(1000);
376 }
377 }
378
379 return error;
380 }
381
382 static int
sht4x_cmdr(struct sht4x_sc * sc,uint8_t cmd,uint8_t * buf,size_t blen)383 sht4x_cmdr(struct sht4x_sc *sc, uint8_t cmd, uint8_t *buf, size_t blen)
384 {
385 return sht4x_cmd(sc->sc_tag, sc->sc_addr, &cmd, 1, buf, blen, sc->sc_readattempts);
386 }
387
388 static uint8_t
sht4x_crc(uint8_t * data,size_t size)389 sht4x_crc(uint8_t * data, size_t size)
390 {
391 uint8_t crc = 0xFF;
392
393 for (size_t i = 0; i < size; i++) {
394 crc ^= data[i];
395 for (size_t j = 8; j > 0; j--) {
396 if (crc & 0x80)
397 crc = (crc << 1) ^ 0x131;
398 else
399 crc <<= 1;
400 }
401 }
402 return crc;
403 }
404
405 static int
sht4x_poke(i2c_tag_t tag,i2c_addr_t addr,bool matchdebug)406 sht4x_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
407 {
408 uint8_t reg = SHT4X_READ_SERIAL;
409 uint8_t buf[6];
410 int error;
411
412 error = sht4x_cmd(tag, addr, ®, 1, buf, 6, 10);
413 if (matchdebug) {
414 printf("poke X 1: %d\n", error);
415 }
416 return error;
417 }
418
419 static int
sht4x_sysctl_init(struct sht4x_sc * sc)420 sht4x_sysctl_init(struct sht4x_sc *sc)
421 {
422 int error;
423 const struct sysctlnode *cnode;
424 int sysctlroot_num;
425
426 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
427 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
428 SYSCTL_DESCR("sht4x controls"), NULL, 0, NULL, 0, CTL_HW,
429 CTL_CREATE, CTL_EOL)) != 0)
430 return error;
431
432 sysctlroot_num = cnode->sysctl_num;
433
434 #ifdef SHT4X_DEBUG
435 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
436 CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
437 SYSCTL_DESCR("Debug level"), sht4x_verify_sysctl, 0,
438 &sc->sc_sht4xdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
439 CTL_EOL)) != 0)
440 return error;
441
442 #endif
443
444 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
445 CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
446 SYSCTL_DESCR("The number of times to attempt to read the values"),
447 sht4x_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
448 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
449 return error;
450
451 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
452 CTLFLAG_READONLY, CTLTYPE_STRING, "resolutions",
453 SYSCTL_DESCR("Valid resolutions"), 0, 0,
454 __UNCONST(sht4x_resolution_names),
455 sizeof(sht4x_resolution_names) + 1,
456 CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
457 return error;
458
459 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
460 CTLFLAG_READWRITE, CTLTYPE_STRING, "resolution",
461 SYSCTL_DESCR("Resolution of RH and Temp"),
462 sht4x_verify_sysctl_resolution, 0, (void *) sc,
463 SHT4X_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
464 return error;
465
466 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
467 CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
468 SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
469 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
470 return error;
471
472 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
473 CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
474 SYSCTL_DESCR("Heater on"), sht4x_verify_sysctl_heateron, 0,
475 (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
476 return error;
477
478 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
479 CTLFLAG_READWRITE, CTLTYPE_INT, "heaterstrength",
480 SYSCTL_DESCR("Heater strength 1 to 3"),
481 sht4x_verify_sysctl_heatervalue, 0, (void *)sc, 0, CTL_HW,
482 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
483 return error;
484
485 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
486 CTLFLAG_READONLY, CTLTYPE_STRING, "heaterpulses",
487 SYSCTL_DESCR("Valid heater pulse lengths"), 0, 0,
488 __UNCONST(sht4x_heaterpulse_names),
489 sizeof(sht4x_heaterpulse_names) + 1,
490 CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
491 return error;
492
493 if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
494 CTLFLAG_READWRITE, CTLTYPE_STRING, "heaterpulse",
495 SYSCTL_DESCR("Heater pulse length"),
496 sht4x_verify_sysctl_heaterpulse, 0, (void *) sc,
497 SHT4X_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
498 return error;
499 return 0;
500 }
501
502 static int
sht4x_match(device_t parent,cfdata_t match,void * aux)503 sht4x_match(device_t parent, cfdata_t match, void *aux)
504 {
505 struct i2c_attach_args *ia = aux;
506 int error, match_result;
507 const bool matchdebug = false;
508
509 if (iic_use_direct_match(ia, match, NULL, &match_result))
510 return match_result;
511
512 /* indirect config - check for configured address */
513 if (ia->ia_addr != SHT4X_TYPICAL_ADDR)
514 return 0;
515
516 /*
517 * Check to see if something is really at this i2c address. This will
518 * keep phantom devices from appearing
519 */
520 if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
521 if (matchdebug)
522 printf("in match acquire bus failed\n");
523 return 0;
524 }
525
526 error = sht4x_poke(ia->ia_tag, ia->ia_addr, matchdebug);
527 iic_release_bus(ia->ia_tag, 0);
528
529 return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
530 }
531
532 static void
sht4x_attach(device_t parent,device_t self,void * aux)533 sht4x_attach(device_t parent, device_t self, void *aux)
534 {
535 struct sht4x_sc *sc;
536 struct i2c_attach_args *ia;
537 int error, i;
538 int ecount = 0;
539 uint8_t buf[6];
540 uint8_t sncrcpt1, sncrcpt2;
541
542 ia = aux;
543 sc = device_private(self);
544
545 sc->sc_dev = self;
546 sc->sc_tag = ia->ia_tag;
547 sc->sc_addr = ia->ia_addr;
548 sc->sc_sht4xdebug = 0;
549 strlcpy(sc->sc_resolution,"high",SHT4X_RES_NAME);
550 sc->sc_readattempts = 10;
551 sc->sc_ignorecrc = false;
552 sc->sc_heateron = false;
553 sc->sc_heaterval = 1;
554 strlcpy(sc->sc_heaterpulse,"short",SHT4X_PULSE_NAME);
555 sc->sc_sme = NULL;
556
557 aprint_normal("\n");
558
559 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
560 sc->sc_numsensors = __arraycount(sht4x_sensors);
561
562 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
563 aprint_error_dev(self,
564 "Unable to create sysmon structure\n");
565 sc->sc_sme = NULL;
566 return;
567 }
568 if ((error = sht4x_sysctl_init(sc)) != 0) {
569 aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
570 goto out;
571 }
572
573 error = iic_acquire_bus(sc->sc_tag, 0);
574 if (error) {
575 aprint_error_dev(self, "Could not acquire iic bus: %d\n",
576 error);
577 goto out;
578 }
579
580 error = sht4x_cmdr(sc, SHT4X_SOFT_RESET, NULL, 0);
581 if (error != 0)
582 aprint_error_dev(self, "Reset failed: %d\n", error);
583
584 delay(1000); /* 1 ms max */
585
586 error = sht4x_cmdr(sc, SHT4X_READ_SERIAL, buf, 6);
587 if (error) {
588 aprint_error_dev(self, "Failed to read serial number: %d\n",
589 error);
590 ecount++;
591 }
592
593 sncrcpt1 = sht4x_crc(&buf[0],2);
594 sncrcpt2 = sht4x_crc(&buf[3],2);
595
596 DPRINTF(sc, 2, ("%s: read serial number values: %02x%02x - %02x, %02x%02x - %02x ; %02x %02x\n",
597 device_xname(sc->sc_dev), buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], sncrcpt1, sncrcpt2));
598
599 iic_release_bus(sc->sc_tag, 0);
600 if (error != 0) {
601 aprint_error_dev(self, "Unable to setup device\n");
602 goto out;
603 }
604
605 for (i = 0; i < sc->sc_numsensors; i++) {
606 strlcpy(sc->sc_sensors[i].desc, sht4x_sensors[i].desc,
607 sizeof(sc->sc_sensors[i].desc));
608
609 sc->sc_sensors[i].units = sht4x_sensors[i].type;
610 sc->sc_sensors[i].state = ENVSYS_SINVALID;
611
612 DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
613 sc->sc_sensors[i].desc));
614
615 error = sysmon_envsys_sensor_attach(sc->sc_sme,
616 &sc->sc_sensors[i]);
617 if (error) {
618 aprint_error_dev(self,
619 "Unable to attach sensor %d: %d\n", i, error);
620 goto out;
621 }
622 }
623
624 sc->sc_sme->sme_name = device_xname(sc->sc_dev);
625 sc->sc_sme->sme_cookie = sc;
626 sc->sc_sme->sme_refresh = sht4x_refresh;
627
628 DPRINTF(sc, 2, ("sht4x_attach: registering with envsys\n"));
629
630 if (sysmon_envsys_register(sc->sc_sme)) {
631 aprint_error_dev(self,
632 "unable to register with sysmon\n");
633 sysmon_envsys_destroy(sc->sc_sme);
634 sc->sc_sme = NULL;
635 return;
636 }
637
638 /* There is no documented way to ask the chip what version it is. This
639 is likely fine as the only apparent difference is in how precise the
640 measurements will be. The actual conversation with the chip is
641 identical no matter which one you are talking to.
642 */
643
644 aprint_normal_dev(self, "Sensirion SHT40/SHT41/SHT45, "
645 "Serial number: %02x%02x%02x%02x%s",
646 buf[0], buf[1], buf[3], buf[4],
647 (sncrcpt1 == buf[2] && sncrcpt2 == buf[5]) ? "\n" : " (bad crc)\n");
648 return;
649 out:
650 sysmon_envsys_destroy(sc->sc_sme);
651 sc->sc_sme = NULL;
652 }
653
654 /* If you use the heater on this chip, there is no documented choice but to use
655 the highest precision. If the heater is not in use one may select different
656 precisions or repeatability for the measurement.
657
658 Further, if the heater is used, it will only be active during the measurement.
659 The use of the heater will add delay to the measurement as chip will not
660 return anything until the heater pulse time is over.
661 */
662
663 static uint8_t
sht4x_compute_measure_command(char * resolution,bool heateron,int heatervalue,char * heaterpulse)664 sht4x_compute_measure_command(char *resolution, bool heateron,
665 int heatervalue, char *heaterpulse)
666 {
667 int i;
668 uint8_t r;
669
670 if (heateron == false) {
671 for (i = 0; i < __arraycount(sht4x_resolutions); i++) {
672 if (strncmp(resolution, sht4x_resolutions[i].text,
673 SHT4X_RES_NAME) == 0) {
674 r = sht4x_resolutions[i].cmd;
675 break;
676 }
677 }
678
679 if (i == __arraycount(sht4x_resolutions))
680 panic("Heater off could not find command for resolution: %s\n",resolution);
681 } else {
682 for (i = 0; i < __arraycount(sht4x_heateron_commands); i++) {
683 if (heatervalue == sht4x_heateron_commands[i].heatervalue &&
684 strncmp(heaterpulse, sht4x_heateron_commands[i].pulselength,
685 SHT4X_PULSE_NAME) == 0) {
686 r = sht4x_heateron_commands[i].cmd;
687 break;
688 }
689 }
690
691 if (i == __arraycount(sht4x_heateron_commands))
692 panic("Heater on could not find command for heatervalue, heaterpulse: %d %s\n",
693 heatervalue,heaterpulse);
694 }
695
696 return r;
697 }
698
699 static void
sht4x_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)700 sht4x_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
701 {
702 struct sht4x_sc *sc;
703 sc = sme->sme_cookie;
704 int error;
705 uint8_t rawdata[6];
706 uint8_t measurement_command;
707 edata->state = ENVSYS_SINVALID;
708
709 mutex_enter(&sc->sc_mutex);
710 error = iic_acquire_bus(sc->sc_tag, 0);
711 if (error) {
712 DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
713 device_xname(sc->sc_dev), error));
714 goto out;
715 }
716
717 /*
718 The documented conversion calculations for the raw values are as follows:
719
720 %RH = (-6 + 125 * rawvalue / 65535)
721
722 T in Celsius = (-45 + 175 * rawvalue / 65535)
723
724 It follows then:
725
726 T in Kelvin = (228.15 + 175 * rawvalue / 65535)
727
728 given the relationship between Celsius and Kelvin.
729
730 What follows reorders the calculation a bit and scales it up to avoid
731 the use of any floating point. All that would really have to happen
732 is a scale up to 10^6 for the sysenv framework, which wants
733 temperature in micro-kelvin and percent relative humidity scaled up
734 10^6, but since this conversion uses 64 bits due to intermediate
735 values that are bigger than 32 bits the conversion first scales up to
736 10^9 and the scales back down by 10^3 at the end. This preserves some
737 precision in the conversion that would otherwise be lost.
738 */
739
740 measurement_command = sht4x_compute_measure_command(sc->sc_resolution,
741 sc->sc_heateron, sc->sc_heaterval, sc->sc_heaterpulse);
742 DPRINTF(sc, 2, ("%s: Measurement command: %02x\n",
743 device_xname(sc->sc_dev), measurement_command));
744
745 /* This chip is pretty nice in that all commands are the same length and
746 return the same result. What is not so nice is that you can not ask
747 for temperature and humidity independently.
748
749 The result will be 16 bits of raw temperature and a CRC byte followed
750 by 16 bits of humidity followed by a CRC byte.
751 */
752
753 error = sht4x_cmdr(sc,measurement_command,rawdata,6);
754
755 if (error == 0) {
756 DPRINTF(sc, 2, ("%s: Raw data: %02x%02x %02x - %02x%02x %02x\n",
757 device_xname(sc->sc_dev), rawdata[0], rawdata[1], rawdata[2],
758 rawdata[3], rawdata[4], rawdata[5]));
759
760
761 uint8_t *svalptr;
762 uint64_t svalue;
763 int64_t v1;
764 uint64_t v2;
765 uint64_t d1 = 65535;
766 uint64_t mul1;
767 uint64_t mul2;
768 uint64_t div1 = 10000;
769 uint64_t q;
770
771 switch (edata->sensor) {
772 case SHT4X_TEMP_SENSOR:
773 svalptr = &rawdata[0];
774 v1 = 22815; /* this is scaled up already from 228.15 */
775 v2 = 175;
776 mul1 = 10000000000;
777 mul2 = 100000000;
778 break;
779 case SHT4X_HUMIDITY_SENSOR:
780 svalptr = &rawdata[3];
781 v1 = -6;
782 v2 = 125;
783 mul1 = 10000000000;
784 mul2 = 10000000000;
785 break;
786 default:
787 error = EINVAL;
788 break;
789 }
790
791 if (error == 0) {
792 uint8_t testcrc;
793
794 /* Fake out the CRC check if being asked to ignore CRC */
795 if (sc->sc_ignorecrc) {
796 testcrc = *(svalptr + 2);
797 } else {
798 testcrc = sht4x_crc(svalptr,2);
799 }
800
801 if (*(svalptr + 2) == testcrc) {
802 svalue = *svalptr << 8 | *(svalptr + 1);
803 DPRINTF(sc, 2, ("%s: Raw sensor 16 bit: %#jx\n",
804 device_xname(sc->sc_dev), (uintmax_t)svalue));
805
806 /* Scale up */
807 svalue = svalue * mul1;
808 v1 = v1 * mul2;
809 /* Perform the conversion */
810 q = ((v2 * (svalue / d1)) + v1) / div1;
811
812 DPRINTF(sc, 2, ("%s: Computed sensor: %#jx\n",
813 device_xname(sc->sc_dev), (uintmax_t)q));
814 /* The results will fit in 32 bits, so nothing will be lost */
815 edata->value_cur = (uint32_t) q;
816 edata->state = ENVSYS_SVALID;
817 } else {
818 error = EINVAL;
819 }
820 }
821 }
822
823 if (error) {
824 DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
825 device_xname(sc->sc_dev), error));
826 }
827
828 iic_release_bus(sc->sc_tag, 0);
829 out:
830 mutex_exit(&sc->sc_mutex);
831 }
832
833 static int
sht4x_detach(device_t self,int flags)834 sht4x_detach(device_t self, int flags)
835 {
836 struct sht4x_sc *sc;
837
838 sc = device_private(self);
839
840 mutex_enter(&sc->sc_mutex);
841
842 /* Remove the sensors */
843 if (sc->sc_sme != NULL) {
844 sysmon_envsys_unregister(sc->sc_sme);
845 sc->sc_sme = NULL;
846 }
847 mutex_exit(&sc->sc_mutex);
848
849 /* Remove the sysctl tree */
850 sysctl_teardown(&sc->sc_sht4xlog);
851
852 /* Remove the mutex */
853 mutex_destroy(&sc->sc_mutex);
854
855 return 0;
856 }
857
858 MODULE(MODULE_CLASS_DRIVER, sht4xtemp, "iic,sysmon_envsys");
859
860 #ifdef _MODULE
861 #include "ioconf.c"
862 #endif
863
864 static int
sht4xtemp_modcmd(modcmd_t cmd,void * opaque)865 sht4xtemp_modcmd(modcmd_t cmd, void *opaque)
866 {
867
868 switch (cmd) {
869 case MODULE_CMD_INIT:
870 #ifdef _MODULE
871 return config_init_component(cfdriver_ioconf_sht4xtemp,
872 cfattach_ioconf_sht4xtemp, cfdata_ioconf_sht4xtemp);
873 #else
874 return 0;
875 #endif
876 case MODULE_CMD_FINI:
877 #ifdef _MODULE
878 return config_fini_component(cfdriver_ioconf_sht4xtemp,
879 cfattach_ioconf_sht4xtemp, cfdata_ioconf_sht4xtemp);
880 #else
881 return 0;
882 #endif
883 default:
884 return ENOTTY;
885 }
886 }
887