1 /*- 2 * Copyright (c) 2014,2016 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Frank Kardel. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * IST-AG P14 calibrated Hygro-/Temperature sensor module 32 * Devices: HYT-271, HYT-221 and HYT-939 33 * 34 * see: 35 * http://www.ist-ag.com/eh/ist-ag/resource.nsf/imgref/Download_AHHYTM_E2.1.pdf/ 36 * $FILE/AHHYTM_E2.1.pdf 37 */ 38 39 /* 40 * FDT direct configuration fragment to be added to i2cX definition in dtsi file 41 * like in bcm2835-rpi.dtsi or another specific file. 42 * 43 * &i2c1 { 44 * pinctrl-names = "default"; 45 * pinctrl-0 = <&i2c1_gpio2>; 46 * status = "okay"; 47 * clock-frequency = <100000>; 48 * #address-cells = <1>; 49 * #size-cells = <0>; 50 * hythygtemp@28 { 51 * compatible = "ist-ag,i2c-hytp14"; 52 * reg = <0x28>; 53 * status = "okay"; 54 * }; 55 * hythygtemp@29 { 56 * compatible = "ist-ag,i2c-hytp14"; 57 * reg = <0x29>; 58 * status = "okay"; 59 * }; 60 * }; 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.13 2021/01/27 02:29:48 thorpej Exp $"); 65 66 #include <sys/param.h> 67 #include <sys/systm.h> 68 #include <sys/kernel.h> 69 #include <sys/device.h> 70 #include <sys/module.h> 71 #include <sys/sysctl.h> 72 #include <sys/mutex.h> 73 #include <sys/condvar.h> 74 #include <sys/kthread.h> 75 76 #include <dev/sysmon/sysmonvar.h> 77 #include <dev/i2c/i2cvar.h> 78 #include <dev/i2c/hytp14reg.h> 79 #include <dev/i2c/hytp14var.h> 80 81 static int hytp14_match(device_t, cfdata_t, void *); 82 static void hytp14_attach(device_t, device_t, void *); 83 static int hytp14_detach(device_t, int); 84 static void hytp14_measurement_request(void *); 85 static int hytp14_refresh_sensor(struct hytp14_sc *sc); 86 static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *); 87 static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *); 88 static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *); 89 static void hytp14_thread(void *); 90 static int sysctl_hytp14_interval(SYSCTLFN_ARGS); 91 92 /* #define HYT_DEBUG 3 */ 93 94 #ifdef HYT_DEBUG 95 volatile int hythygtemp_debug = HYT_DEBUG; 96 97 #define DPRINTF(_L_, _X_) do { \ 98 if ((_L_) <= hythygtemp_debug) { \ 99 printf _X_; \ 100 } \ 101 } while (0) 102 #else 103 #define DPRINTF(_L_, _X_) 104 #endif 105 106 CFATTACH_DECL_NEW(hythygtemp, sizeof(struct hytp14_sc), 107 hytp14_match, hytp14_attach, hytp14_detach, NULL); 108 109 static struct hytp14_sensor hytp14_sensors[] = { 110 { 111 .desc = "humidity", 112 .type = ENVSYS_SRELHUMIDITY, 113 .refresh = hytp14_refresh_humidity 114 }, 115 { 116 .desc = "temperature", 117 .type = ENVSYS_STEMP, 118 .refresh = hytp14_refresh_temp 119 } 120 }; 121 122 static const struct device_compatible_entry compat_data[] = { 123 { .compat = "i2c-hytp14" }, 124 DEVICE_COMPAT_EOL 125 }; 126 127 static int 128 hytp14_match(device_t parent, cfdata_t match, void *aux) 129 { 130 struct i2c_attach_args *ia = aux; 131 int match_result; 132 133 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 134 return match_result; 135 136 /* 137 * This device can be reprogrammed to use a different 138 * I2C address, thus checking for specific addresses 139 * is not helpful here. 140 * reprogramming is done via setting new values in 141 * the device EEPROM via the hytctl utility and 142 * a special GPIO setup - see hythygtemp(4) for more 143 * information. 144 */ 145 return I2C_MATCH_ADDRESS_ONLY; 146 } 147 148 static void 149 hytp14_attach(device_t parent, device_t self, void *aux) 150 { 151 const struct sysctlnode *rnode, *node; 152 struct hytp14_sc *sc; 153 struct i2c_attach_args *ia; 154 int i, rv; 155 156 ia = aux; 157 sc = device_private(self); 158 159 sc->sc_dev = self; 160 sc->sc_tag = ia->ia_tag; 161 sc->sc_addr = ia->ia_addr; 162 163 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 164 cv_init(&sc->sc_condvar, "hytcv"); 165 166 sc->sc_state = HYTP14_THR_INIT; 167 168 sc->sc_valid = ENVSYS_SINVALID; 169 sc->sc_numsensors = __arraycount(hytp14_sensors); 170 171 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 172 aprint_error_dev(sc->sc_dev, 173 "unable to create sysmon structure\n"); 174 return; 175 } 176 177 for (i = 0; i < sc->sc_numsensors; i++) { 178 strlcpy(sc->sc_sensors[i].desc, 179 hytp14_sensors[i].desc, 180 sizeof sc->sc_sensors[i].desc); 181 182 sc->sc_sensors[i].units = hytp14_sensors[i].type; 183 sc->sc_sensors[i].state = ENVSYS_SINVALID; 184 185 DPRINTF(2, ("hytp14_attach: registering sensor %d (%s)\n", i, 186 sc->sc_sensors[i].desc)); 187 188 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i])) { 189 aprint_error_dev(sc->sc_dev, 190 "unable to attach sensor\n"); 191 sysmon_envsys_destroy(sc->sc_sme); 192 sc->sc_sme = NULL; 193 return; 194 } 195 } 196 197 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 198 sc->sc_sme->sme_cookie = sc; 199 sc->sc_sme->sme_refresh = hytp14_refresh; 200 201 DPRINTF(2, ("hytp14_attach: registering with envsys\n")); 202 203 if (sysmon_envsys_register(sc->sc_sme)) { 204 aprint_error_dev(sc->sc_dev, 205 "unable to register with sysmon\n"); 206 sysmon_envsys_destroy(sc->sc_sme); 207 return; 208 } 209 210 /* create a sysctl node for setting the measurement interval */ 211 rnode = node = NULL; 212 sysctl_createv(NULL, 0, NULL, &rnode, 213 CTLFLAG_READWRITE, 214 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 215 NULL, 0, NULL, 0, 216 CTL_HW, CTL_CREATE, CTL_EOL); 217 218 if (rnode != NULL) 219 sysctl_createv(NULL, 0, NULL, &node, 220 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 221 CTLTYPE_INT, "interval", 222 SYSCTL_DESCR("Sensor sampling interval in seconds"), 223 sysctl_hytp14_interval, 0, (void *)sc, 0, 224 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 225 226 227 /* set up the default measurement interval for worker thread */ 228 sc->sc_mrinterval = HYTP14_MR_INTERVAL; 229 230 /* create worker kthread */ 231 rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, 232 hytp14_thread, sc, &sc->sc_thread, 233 "%s", device_xname(sc->sc_dev)); 234 if (rv) 235 aprint_error_dev(self, "unable to create intr thread\n"); 236 237 aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); 238 } 239 240 static int 241 hytp14_detach(device_t self, int flags) 242 { 243 struct hytp14_sc *sc; 244 245 sc = device_private(self); 246 247 if (sc->sc_sme != NULL) { 248 sysmon_envsys_unregister(sc->sc_sme); 249 sc->sc_sme = NULL; 250 } 251 252 /* stop measurement thread */ 253 mutex_enter(&sc->sc_mutex); 254 sc->sc_state = HYTP14_THR_STOP; 255 cv_signal(&sc->sc_condvar); 256 mutex_exit(&sc->sc_mutex); 257 258 /* await thread completion */ 259 kthread_join(sc->sc_thread); 260 261 /* cleanup */ 262 cv_destroy(&sc->sc_condvar); 263 mutex_destroy(&sc->sc_mutex); 264 265 return 0; 266 } 267 268 static void 269 hytp14_thread(void *aux) 270 { 271 struct hytp14_sc *sc = aux; 272 int rv; 273 274 mutex_enter(&sc->sc_mutex); 275 276 DPRINTF(2, ("%s(%s): thread start - state=%d\n", 277 __func__, device_xname(sc->sc_dev), 278 sc->sc_state)); 279 280 while (sc->sc_state != HYTP14_THR_STOP) { 281 sc->sc_state = HYTP14_THR_RUN; 282 283 DPRINTF(2, ("%s(%s): waiting %d seconds\n", 284 __func__, device_xname(sc->sc_dev), 285 sc->sc_mrinterval)); 286 287 rv = cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz * sc->sc_mrinterval); 288 289 if (rv == EWOULDBLOCK) { 290 /* timeout - run measurement */ 291 DPRINTF(2, ("%s(%s): timeout -> measurement\n", 292 __func__, device_xname(sc->sc_dev))); 293 294 hytp14_measurement_request(sc); 295 } else { 296 DPRINTF(2, ("%s(%s): condvar signalled - state=%d\n", 297 __func__, device_xname(sc->sc_dev), 298 sc->sc_state)); 299 } 300 } 301 302 mutex_exit(&sc->sc_mutex); 303 304 DPRINTF(2, ("%s(%s): thread exit\n", 305 __func__, device_xname(sc->sc_dev))); 306 307 kthread_exit(0); 308 } 309 310 static void 311 hytp14_measurement_request(void *aux) 312 { 313 uint8_t buf[I2C_EXEC_MAX_BUFLEN]; 314 struct hytp14_sc *sc; 315 int error; 316 317 sc = aux; 318 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 319 320 error = iic_acquire_bus(sc->sc_tag, 0); 321 if (error == 0) { 322 323 /* send DF command - read last data from sensor */ 324 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 325 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 326 if (error != 0) { 327 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 328 device_xname(sc->sc_dev), __func__, 329 sc->sc_addr, error)); 330 sc->sc_valid = ENVSYS_SINVALID; 331 } else { 332 DPRINTF(3, ("%s(%s): DF success : " 333 "0x%02x%02x%02x%02x\n", 334 __func__, device_xname(sc->sc_dev), 335 sc->sc_data[0], sc->sc_data[1], 336 sc->sc_data[2], sc->sc_data[3])); 337 338 /* remember last data, when valid */ 339 if (!(sc->sc_data[0] & 340 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 341 memcpy(sc->sc_last, sc->sc_data, 342 sizeof(sc->sc_last)); 343 sc->sc_valid = ENVSYS_SVALID; 344 } 345 } 346 347 /* send MR command to request a new measurement */ 348 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 349 sc->sc_addr, NULL, 0, buf, sizeof(buf), 0); 350 351 if (error == 0) { 352 DPRINTF(3, ("%s(%s): MR sent\n", 353 __func__, device_xname(sc->sc_dev))); 354 } else { 355 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 356 device_xname(sc->sc_dev), __func__, 357 sc->sc_addr, error)); 358 } 359 360 iic_release_bus(sc->sc_tag, 0); 361 DPRINTF(3, ("%s(%s): bus released\n", 362 __func__, device_xname(sc->sc_dev))); 363 } else { 364 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 365 device_xname(sc->sc_dev), __func__, error)); 366 } 367 } 368 369 static int 370 hytp14_refresh_sensor(struct hytp14_sc *sc) 371 { 372 int error; 373 374 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 375 376 error = iic_acquire_bus(sc->sc_tag, 0); 377 if (error == 0) { 378 379 /* send DF command - read last data from sensor */ 380 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 381 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 382 if (error != 0) { 383 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 384 device_xname(sc->sc_dev), __func__, 385 sc->sc_addr, error)); 386 sc->sc_valid = ENVSYS_SINVALID; 387 } else { 388 DPRINTF(3, ("%s(%s): DF success : " 389 "0x%02x%02x%02x%02x\n", 390 __func__, device_xname(sc->sc_dev), 391 sc->sc_data[0], sc->sc_data[1], 392 sc->sc_data[2], sc->sc_data[3])); 393 394 /* 395 * Use old data from sc_last[] when new data 396 * is not yet valid (i.e. DF command came too 397 * quickly after the last command). 398 */ 399 if (!(sc->sc_data[0] & 400 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 401 memcpy(sc->sc_last, sc->sc_data, 402 sizeof(sc->sc_last)); 403 sc->sc_valid = ENVSYS_SVALID; 404 } else 405 memcpy(sc->sc_data, sc->sc_last, 406 sizeof(sc->sc_data)); 407 } 408 409 iic_release_bus(sc->sc_tag, 0); 410 DPRINTF(3, ("%s(%s): bus released\n", 411 __func__, device_xname(sc->sc_dev))); 412 } else { 413 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 414 device_xname(sc->sc_dev), __func__, error)); 415 } 416 417 return sc->sc_valid; 418 } 419 420 421 static void 422 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata) 423 { 424 uint16_t hyg; 425 int status; 426 427 status = hytp14_refresh_sensor(sc); 428 429 if (status == ENVSYS_SVALID) { 430 hyg = (sc->sc_data[0] << 8) | sc->sc_data[1]; 431 432 edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg); 433 edata->value_cur /= 10; 434 } 435 436 edata->state = status; 437 } 438 439 static void 440 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata) 441 { 442 uint16_t temp; 443 int status; 444 445 status = hytp14_refresh_sensor(sc); 446 447 if (status == ENVSYS_SVALID) { 448 temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]); 449 450 edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE; 451 edata->value_cur *= (int32_t)temp; 452 edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000; 453 } 454 455 edata->state = status; 456 } 457 458 static void 459 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 460 { 461 struct hytp14_sc *sc; 462 463 sc = sme->sme_cookie; 464 hytp14_sensors[edata->sensor].refresh(sc, edata); 465 } 466 467 static int 468 sysctl_hytp14_interval(SYSCTLFN_ARGS) 469 { 470 struct sysctlnode node; 471 struct hytp14_sc *sc; 472 int32_t t; 473 int error; 474 475 node = *rnode; 476 sc = node.sysctl_data; 477 478 t = sc->sc_mrinterval; 479 node.sysctl_data = &t; 480 481 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 482 if (error || newp == NULL) 483 return error; 484 if (t <= 0) 485 return EINVAL; 486 487 sc->sc_mrinterval = t; 488 return 0; 489 } 490 491 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "i2cexec,sysmon_envsys"); 492 493 #ifdef _MODULE 494 #include "ioconf.c" 495 #endif 496 497 static int 498 hythygtemp_modcmd(modcmd_t cmd, void *opaque) 499 { 500 int error; 501 502 error = 0; 503 504 switch (cmd) { 505 case MODULE_CMD_INIT: 506 #ifdef _MODULE 507 error = config_init_component(cfdriver_ioconf_hythygtemp, 508 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 509 #endif 510 return error; 511 512 case MODULE_CMD_FINI: 513 #ifdef _MODULE 514 error = config_fini_component(cfdriver_ioconf_hythygtemp, 515 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 516 #endif 517 return error; 518 519 default: 520 return ENOTTY; 521 } 522 } 523