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