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 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.8 2018/06/16 21:24:36 thorpej Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 #include <sys/module.h> 47 #include <sys/sysctl.h> 48 #include <sys/mutex.h> 49 #include <sys/condvar.h> 50 #include <sys/kthread.h> 51 52 #include <dev/sysmon/sysmonvar.h> 53 #include <dev/i2c/i2cvar.h> 54 #include <dev/i2c/hytp14reg.h> 55 #include <dev/i2c/hytp14var.h> 56 57 static int hytp14_match(device_t, cfdata_t, void *); 58 static void hytp14_attach(device_t, device_t, void *); 59 static int hytp14_detach(device_t, int); 60 static void hytp14_measurement_request(void *); 61 static int hytp14_refresh_sensor(struct hytp14_sc *sc); 62 static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *); 63 static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *); 64 static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *); 65 static void hytp14_thread(void *); 66 static int sysctl_hytp14_interval(SYSCTLFN_ARGS); 67 68 /* #define HYT_DEBUG 3 */ 69 70 #ifdef HYT_DEBUG 71 volatile int hythygtemp_debug = HYT_DEBUG; 72 73 #define DPRINTF(_L_, _X_) do { \ 74 if ((_L_) <= hythygtemp_debug) { \ 75 printf _X_; \ 76 } \ 77 } while (0) 78 #else 79 #define DPRINTF(_L_, _X_) 80 #endif 81 82 CFATTACH_DECL_NEW(hythygtemp, sizeof(struct hytp14_sc), 83 hytp14_match, hytp14_attach, hytp14_detach, NULL); 84 85 static struct hytp14_sensor hytp14_sensors[] = { 86 { 87 .desc = "humidity", 88 .type = ENVSYS_SRELHUMIDITY, 89 .refresh = hytp14_refresh_humidity 90 }, 91 { 92 .desc = "temperature", 93 .type = ENVSYS_STEMP, 94 .refresh = hytp14_refresh_temp 95 } 96 }; 97 98 static int 99 hytp14_match(device_t parent, cfdata_t match, void *aux) 100 { 101 struct i2c_attach_args *ia = aux; 102 int match_result; 103 104 if (iic_use_direct_match(ia, match, NULL, &match_result)) 105 return match_result; 106 107 if (ia->ia_addr == 0x28) 108 return I2C_MATCH_ADDRESS_ONLY; 109 110 /* 111 * XXXJRT 112 * This device is an odd-ball; the i2c address can be changed 113 * at run-time using a command sequence documented in the 114 * application note, but the timing is critical (within 10ms 115 * after power-on of the device), and the device always starts 116 * up at address 0x28. 117 * 118 * How should we handle this? 119 */ 120 return 0; 121 } 122 123 static void 124 hytp14_attach(device_t parent, device_t self, void *aux) 125 { 126 const struct sysctlnode *rnode, *node; 127 struct hytp14_sc *sc; 128 struct i2c_attach_args *ia; 129 int i, rv; 130 131 ia = aux; 132 sc = device_private(self); 133 134 sc->sc_dev = self; 135 sc->sc_tag = ia->ia_tag; 136 sc->sc_addr = ia->ia_addr; 137 138 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 139 cv_init(&sc->sc_condvar, "hytcv"); 140 141 sc->sc_state = HYTP14_THR_INIT; 142 143 sc->sc_valid = ENVSYS_SINVALID; 144 sc->sc_numsensors = __arraycount(hytp14_sensors); 145 146 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 147 aprint_error_dev(sc->sc_dev, 148 "unable to create sysmon structure\n"); 149 return; 150 } 151 152 for (i = 0; i < sc->sc_numsensors; i++) { 153 strlcpy(sc->sc_sensors[i].desc, 154 hytp14_sensors[i].desc, 155 sizeof sc->sc_sensors[i].desc); 156 157 sc->sc_sensors[i].units = hytp14_sensors[i].type; 158 sc->sc_sensors[i].state = ENVSYS_SINVALID; 159 160 DPRINTF(2, ("hytp14_attach: registering sensor %d (%s)\n", i, 161 sc->sc_sensors[i].desc)); 162 163 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i])) { 164 aprint_error_dev(sc->sc_dev, 165 "unable to attach sensor\n"); 166 sysmon_envsys_destroy(sc->sc_sme); 167 return; 168 } 169 } 170 171 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 172 sc->sc_sme->sme_cookie = sc; 173 sc->sc_sme->sme_refresh = hytp14_refresh; 174 175 DPRINTF(2, ("hytp14_attach: registering with envsys\n")); 176 177 if (sysmon_envsys_register(sc->sc_sme)) { 178 aprint_error_dev(sc->sc_dev, 179 "unable to register with sysmon\n"); 180 sysmon_envsys_destroy(sc->sc_sme); 181 return; 182 } 183 184 /* create a sysctl node for setting the measurement interval */ 185 rnode = node = NULL; 186 sysctl_createv(NULL, 0, NULL, &rnode, 187 CTLFLAG_READWRITE, 188 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 189 NULL, 0, NULL, 0, 190 CTL_HW, CTL_CREATE, CTL_EOL); 191 192 if (rnode != NULL) 193 sysctl_createv(NULL, 0, NULL, &node, 194 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 195 CTLTYPE_INT, "interval", 196 SYSCTL_DESCR("Sensor sampling interval in seconds"), 197 sysctl_hytp14_interval, 0, (void *)sc, 0, 198 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 199 200 201 /* set up the default measurement interval for worker thread */ 202 sc->sc_mrinterval = HYTP14_MR_INTERVAL; 203 204 /* create worker kthread */ 205 rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, 206 hytp14_thread, sc, &sc->sc_thread, 207 "%s", device_xname(sc->sc_dev)); 208 if (rv) 209 aprint_error_dev(self, "unable to create intr thread\n"); 210 211 aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); 212 } 213 214 static int 215 hytp14_detach(device_t self, int flags) 216 { 217 struct hytp14_sc *sc; 218 219 sc = device_private(self); 220 221 if (sc->sc_sme != NULL) { 222 sysmon_envsys_unregister(sc->sc_sme); 223 sc->sc_sme = NULL; 224 } 225 226 /* stop measurement thread */ 227 mutex_enter(&sc->sc_mutex); 228 sc->sc_state = HYTP14_THR_STOP; 229 cv_signal(&sc->sc_condvar); 230 mutex_exit(&sc->sc_mutex); 231 232 /* await thread completion */ 233 kthread_join(sc->sc_thread); 234 235 /* cleanup */ 236 cv_destroy(&sc->sc_condvar); 237 mutex_destroy(&sc->sc_mutex); 238 239 return 0; 240 } 241 242 static void 243 hytp14_thread(void *aux) 244 { 245 struct hytp14_sc *sc = aux; 246 int rv; 247 248 mutex_enter(&sc->sc_mutex); 249 250 DPRINTF(2, ("%s(%s): thread start - state=%d\n", 251 __func__, device_xname(sc->sc_dev), 252 sc->sc_state)); 253 254 while (sc->sc_state != HYTP14_THR_STOP) { 255 sc->sc_state = HYTP14_THR_RUN; 256 257 DPRINTF(2, ("%s(%s): waiting %d seconds\n", 258 __func__, device_xname(sc->sc_dev), 259 sc->sc_mrinterval)); 260 261 rv = cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz * sc->sc_mrinterval); 262 263 if (rv == EWOULDBLOCK) { 264 /* timeout - run measurement */ 265 DPRINTF(2, ("%s(%s): timeout -> measurement\n", 266 __func__, device_xname(sc->sc_dev))); 267 268 hytp14_measurement_request(sc); 269 } else { 270 DPRINTF(2, ("%s(%s): condvar signalled - state=%d\n", 271 __func__, device_xname(sc->sc_dev), 272 sc->sc_state)); 273 } 274 } 275 276 mutex_exit(&sc->sc_mutex); 277 278 DPRINTF(2, ("%s(%s): thread exit\n", 279 __func__, device_xname(sc->sc_dev))); 280 281 kthread_exit(0); 282 } 283 284 static void 285 hytp14_measurement_request(void *aux) 286 { 287 uint8_t buf[I2C_EXEC_MAX_BUFLEN]; 288 struct hytp14_sc *sc; 289 int error; 290 291 sc = aux; 292 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 293 294 error = iic_acquire_bus(sc->sc_tag, 0); 295 if (error == 0) { 296 297 /* send DF command - read last data from sensor */ 298 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 299 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 300 if (error != 0) { 301 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 302 device_xname(sc->sc_dev), __func__, 303 sc->sc_addr, error)); 304 sc->sc_valid = ENVSYS_SINVALID; 305 } else { 306 DPRINTF(3, ("%s(%s): DF success : " 307 "0x%02x%02x%02x%02x\n", 308 __func__, device_xname(sc->sc_dev), 309 sc->sc_data[0], sc->sc_data[1], 310 sc->sc_data[2], sc->sc_data[3])); 311 312 /* remember last data, when valid */ 313 if (!(sc->sc_data[0] & 314 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 315 memcpy(sc->sc_last, sc->sc_data, 316 sizeof(sc->sc_last)); 317 sc->sc_valid = ENVSYS_SVALID; 318 } 319 } 320 321 /* send MR command to request a new measurement */ 322 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 323 sc->sc_addr, NULL, 0, buf, sizeof(buf), 0); 324 325 if (error == 0) { 326 DPRINTF(3, ("%s(%s): MR sent\n", 327 __func__, device_xname(sc->sc_dev))); 328 } else { 329 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 330 device_xname(sc->sc_dev), __func__, 331 sc->sc_addr, error)); 332 } 333 334 iic_release_bus(sc->sc_tag, 0); 335 DPRINTF(3, ("%s(%s): bus released\n", 336 __func__, device_xname(sc->sc_dev))); 337 } else { 338 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 339 device_xname(sc->sc_dev), __func__, error)); 340 } 341 } 342 343 static int 344 hytp14_refresh_sensor(struct hytp14_sc *sc) 345 { 346 int error; 347 348 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 349 350 error = iic_acquire_bus(sc->sc_tag, 0); 351 if (error == 0) { 352 353 /* send DF command - read last data from sensor */ 354 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 355 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 356 if (error != 0) { 357 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 358 device_xname(sc->sc_dev), __func__, 359 sc->sc_addr, error)); 360 sc->sc_valid = ENVSYS_SINVALID; 361 } else { 362 DPRINTF(3, ("%s(%s): DF success : " 363 "0x%02x%02x%02x%02x\n", 364 __func__, device_xname(sc->sc_dev), 365 sc->sc_data[0], sc->sc_data[1], 366 sc->sc_data[2], sc->sc_data[3])); 367 368 /* 369 * Use old data from sc_last[] when new data 370 * is not yet valid (i.e. DF command came too 371 * quickly after the last command). 372 */ 373 if (!(sc->sc_data[0] & 374 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 375 memcpy(sc->sc_last, sc->sc_data, 376 sizeof(sc->sc_last)); 377 sc->sc_valid = ENVSYS_SVALID; 378 } else 379 memcpy(sc->sc_data, sc->sc_last, 380 sizeof(sc->sc_data)); 381 } 382 383 iic_release_bus(sc->sc_tag, 0); 384 DPRINTF(3, ("%s(%s): bus released\n", 385 __func__, device_xname(sc->sc_dev))); 386 } else { 387 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 388 device_xname(sc->sc_dev), __func__, error)); 389 } 390 391 return sc->sc_valid; 392 } 393 394 395 static void 396 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata) 397 { 398 uint16_t hyg; 399 int status; 400 401 status = hytp14_refresh_sensor(sc); 402 403 if (status == ENVSYS_SVALID) { 404 hyg = (sc->sc_data[0] << 8) | sc->sc_data[1]; 405 406 edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg); 407 edata->value_cur /= 10; 408 } 409 410 edata->state = status; 411 } 412 413 static void 414 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata) 415 { 416 uint16_t temp; 417 int status; 418 419 status = hytp14_refresh_sensor(sc); 420 421 if (status == ENVSYS_SVALID) { 422 temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]); 423 424 edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE; 425 edata->value_cur *= (int32_t)temp; 426 edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000; 427 } 428 429 edata->state = status; 430 } 431 432 static void 433 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 434 { 435 struct hytp14_sc *sc; 436 437 sc = sme->sme_cookie; 438 hytp14_sensors[edata->sensor].refresh(sc, edata); 439 } 440 441 static int 442 sysctl_hytp14_interval(SYSCTLFN_ARGS) 443 { 444 struct sysctlnode node; 445 struct hytp14_sc *sc; 446 int32_t t; 447 int error; 448 449 node = *rnode; 450 sc = node.sysctl_data; 451 452 t = sc->sc_mrinterval; 453 node.sysctl_data = &t; 454 455 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 456 if (error || newp == NULL) 457 return error; 458 if (t <= 0) 459 return EINVAL; 460 461 sc->sc_mrinterval = t; 462 return 0; 463 } 464 465 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "i2cexec,sysmon_envsys"); 466 467 #ifdef _MODULE 468 #include "ioconf.c" 469 #endif 470 471 static int 472 hythygtemp_modcmd(modcmd_t cmd, void *opaque) 473 { 474 int error; 475 476 error = 0; 477 478 switch (cmd) { 479 case MODULE_CMD_INIT: 480 #ifdef _MODULE 481 error = config_init_component(cfdriver_ioconf_hythygtemp, 482 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 483 #endif 484 return error; 485 486 case MODULE_CMD_FINI: 487 #ifdef _MODULE 488 error = config_fini_component(cfdriver_ioconf_hythygtemp, 489 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 490 #endif 491 return error; 492 493 default: 494 return ENOTTY; 495 } 496 } 497