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