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.15 2022/03/30 00:06:50 pgoyette 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 sc->sc_sme = NULL; 208 return; 209 } 210 211 /* create a sysctl node for setting the measurement interval */ 212 rnode = node = NULL; 213 sysctl_createv(NULL, 0, NULL, &rnode, 214 CTLFLAG_READWRITE, 215 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 216 NULL, 0, NULL, 0, 217 CTL_HW, CTL_CREATE, CTL_EOL); 218 219 if (rnode != NULL) 220 sysctl_createv(NULL, 0, NULL, &node, 221 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 222 CTLTYPE_INT, "interval", 223 SYSCTL_DESCR("Sensor sampling interval in seconds"), 224 sysctl_hytp14_interval, 0, (void *)sc, 0, 225 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 226 227 228 /* set up the default measurement interval for worker thread */ 229 sc->sc_mrinterval = HYTP14_MR_INTERVAL; 230 231 /* create worker kthread */ 232 rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, 233 hytp14_thread, sc, &sc->sc_thread, 234 "%s", device_xname(sc->sc_dev)); 235 if (rv) 236 aprint_error_dev(self, "unable to create intr thread\n"); 237 238 aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); 239 } 240 241 static int 242 hytp14_detach(device_t self, int flags) 243 { 244 struct hytp14_sc *sc; 245 246 sc = device_private(self); 247 248 if (sc->sc_sme != NULL) 249 sysmon_envsys_unregister(sc->sc_sme); 250 251 /* stop measurement thread */ 252 mutex_enter(&sc->sc_mutex); 253 sc->sc_state = HYTP14_THR_STOP; 254 cv_signal(&sc->sc_condvar); 255 mutex_exit(&sc->sc_mutex); 256 257 /* await thread completion */ 258 kthread_join(sc->sc_thread); 259 260 /* cleanup */ 261 cv_destroy(&sc->sc_condvar); 262 mutex_destroy(&sc->sc_mutex); 263 264 return 0; 265 } 266 267 static void 268 hytp14_thread(void *aux) 269 { 270 struct hytp14_sc *sc = aux; 271 int rv; 272 273 mutex_enter(&sc->sc_mutex); 274 275 DPRINTF(2, ("%s(%s): thread start - state=%d\n", 276 __func__, device_xname(sc->sc_dev), 277 sc->sc_state)); 278 279 while (sc->sc_state != HYTP14_THR_STOP) { 280 sc->sc_state = HYTP14_THR_RUN; 281 282 DPRINTF(2, ("%s(%s): waiting %d seconds\n", 283 __func__, device_xname(sc->sc_dev), 284 sc->sc_mrinterval)); 285 286 rv = cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz * sc->sc_mrinterval); 287 288 if (rv == EWOULDBLOCK) { 289 /* timeout - run measurement */ 290 DPRINTF(2, ("%s(%s): timeout -> measurement\n", 291 __func__, device_xname(sc->sc_dev))); 292 293 hytp14_measurement_request(sc); 294 } else { 295 DPRINTF(2, ("%s(%s): condvar signalled - state=%d\n", 296 __func__, device_xname(sc->sc_dev), 297 sc->sc_state)); 298 } 299 } 300 301 mutex_exit(&sc->sc_mutex); 302 303 DPRINTF(2, ("%s(%s): thread exit\n", 304 __func__, device_xname(sc->sc_dev))); 305 306 kthread_exit(0); 307 } 308 309 static void 310 hytp14_measurement_request(void *aux) 311 { 312 uint8_t buf[I2C_EXEC_MAX_BUFLEN]; 313 struct hytp14_sc *sc; 314 int error; 315 316 sc = aux; 317 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 318 319 error = iic_acquire_bus(sc->sc_tag, 0); 320 if (error == 0) { 321 322 /* send DF command - read last data from sensor */ 323 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 324 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 325 if (error != 0) { 326 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 327 device_xname(sc->sc_dev), __func__, 328 sc->sc_addr, error)); 329 sc->sc_valid = ENVSYS_SINVALID; 330 } else { 331 DPRINTF(3, ("%s(%s): DF success : " 332 "0x%02x%02x%02x%02x\n", 333 __func__, device_xname(sc->sc_dev), 334 sc->sc_data[0], sc->sc_data[1], 335 sc->sc_data[2], sc->sc_data[3])); 336 337 /* remember last data, when valid */ 338 if (!(sc->sc_data[0] & 339 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 340 memcpy(sc->sc_last, sc->sc_data, 341 sizeof(sc->sc_last)); 342 sc->sc_valid = ENVSYS_SVALID; 343 } 344 } 345 346 /* send MR command to request a new measurement */ 347 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 348 sc->sc_addr, NULL, 0, buf, sizeof(buf), 0); 349 350 if (error == 0) { 351 DPRINTF(3, ("%s(%s): MR sent\n", 352 __func__, device_xname(sc->sc_dev))); 353 } else { 354 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 355 device_xname(sc->sc_dev), __func__, 356 sc->sc_addr, error)); 357 } 358 359 iic_release_bus(sc->sc_tag, 0); 360 DPRINTF(3, ("%s(%s): bus released\n", 361 __func__, device_xname(sc->sc_dev))); 362 } else { 363 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 364 device_xname(sc->sc_dev), __func__, error)); 365 } 366 } 367 368 static int 369 hytp14_refresh_sensor(struct hytp14_sc *sc) 370 { 371 int error; 372 373 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 374 375 error = iic_acquire_bus(sc->sc_tag, 0); 376 if (error == 0) { 377 378 /* send DF command - read last data from sensor */ 379 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 380 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 381 if (error != 0) { 382 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 383 device_xname(sc->sc_dev), __func__, 384 sc->sc_addr, error)); 385 sc->sc_valid = ENVSYS_SINVALID; 386 } else { 387 DPRINTF(3, ("%s(%s): DF success : " 388 "0x%02x%02x%02x%02x\n", 389 __func__, device_xname(sc->sc_dev), 390 sc->sc_data[0], sc->sc_data[1], 391 sc->sc_data[2], sc->sc_data[3])); 392 393 /* 394 * Use old data from sc_last[] when new data 395 * is not yet valid (i.e. DF command came too 396 * quickly after the last command). 397 */ 398 if (!(sc->sc_data[0] & 399 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 400 memcpy(sc->sc_last, sc->sc_data, 401 sizeof(sc->sc_last)); 402 sc->sc_valid = ENVSYS_SVALID; 403 } else 404 memcpy(sc->sc_data, sc->sc_last, 405 sizeof(sc->sc_data)); 406 } 407 408 iic_release_bus(sc->sc_tag, 0); 409 DPRINTF(3, ("%s(%s): bus released\n", 410 __func__, device_xname(sc->sc_dev))); 411 } else { 412 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 413 device_xname(sc->sc_dev), __func__, error)); 414 } 415 416 return sc->sc_valid; 417 } 418 419 420 static void 421 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata) 422 { 423 uint16_t hyg; 424 int status; 425 426 status = hytp14_refresh_sensor(sc); 427 428 if (status == ENVSYS_SVALID) { 429 hyg = (sc->sc_data[0] << 8) | sc->sc_data[1]; 430 431 edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg); 432 edata->value_cur /= 10; 433 } 434 435 edata->state = status; 436 } 437 438 static void 439 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata) 440 { 441 uint16_t temp; 442 int status; 443 444 status = hytp14_refresh_sensor(sc); 445 446 if (status == ENVSYS_SVALID) { 447 temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]); 448 449 edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE; 450 edata->value_cur *= (int32_t)temp; 451 edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000; 452 } 453 454 edata->state = status; 455 } 456 457 static void 458 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 459 { 460 struct hytp14_sc *sc; 461 462 sc = sme->sme_cookie; 463 hytp14_sensors[edata->sensor].refresh(sc, edata); 464 } 465 466 static int 467 sysctl_hytp14_interval(SYSCTLFN_ARGS) 468 { 469 struct sysctlnode node; 470 struct hytp14_sc *sc; 471 int32_t t; 472 int error; 473 474 node = *rnode; 475 sc = node.sysctl_data; 476 477 t = sc->sc_mrinterval; 478 node.sysctl_data = &t; 479 480 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 481 if (error || newp == NULL) 482 return error; 483 if (t <= 0) 484 return EINVAL; 485 486 sc->sc_mrinterval = t; 487 return 0; 488 } 489 490 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "iic,sysmon_envsys"); 491 492 #ifdef _MODULE 493 #include "ioconf.c" 494 #endif 495 496 static int 497 hythygtemp_modcmd(modcmd_t cmd, void *opaque) 498 { 499 int error; 500 501 error = 0; 502 503 switch (cmd) { 504 case MODULE_CMD_INIT: 505 #ifdef _MODULE 506 error = config_init_component(cfdriver_ioconf_hythygtemp, 507 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 508 #endif 509 return error; 510 511 case MODULE_CMD_FINI: 512 #ifdef _MODULE 513 error = config_fini_component(cfdriver_ioconf_hythygtemp, 514 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 515 #endif 516 return error; 517 518 default: 519 return ENOTTY; 520 } 521 } 522