1 /* $OpenBSD: uthum.c,v 1.32 2017/01/09 14:44:28 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010 Yojiro UO <yuo@nui.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Driver for HID base TEMPer seriese Temperature(/Humidity) sensors */ 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/kernel.h> 24 #include <sys/device.h> 25 #include <sys/conf.h> 26 #include <sys/sensors.h> 27 28 #include <dev/usb/usb.h> 29 #include <dev/usb/usbhid.h> 30 #include <dev/usb/usbdi.h> 31 #include <dev/usb/usbdi_util.h> 32 #include <dev/usb/usbdevs.h> 33 #include <dev/usb/uhidev.h> 34 35 #ifdef UTHUM_DEBUG 36 #define DPRINTF(x) do { printf x; } while (0) 37 #else 38 #define DPRINTF(x) 39 #endif 40 41 /* Device types */ 42 #define UTHUM_TYPE_TEMPERHUM 0x535a 43 #define UTHUM_TYPE_TEMPERHUM_2 0x575a /* alternative TEMPerHUM */ 44 #define UTHUM_TYPE_TEMPER1 0x5758 /* TEMPer1 and HID TEMPer */ 45 #define UTHUM_TYPE_TEMPER2 0x5759 46 #define UTHUM_TYPE_TEMPERNTC 0x575b 47 #define UTHUM_TYPE_UNKNOWN 0xffff 48 49 /* Common */ 50 #define UTHUM_CAL_OFFSET 0x14 51 #define UTHUM_MAX_SENSORS 2 52 #define CMD_DEVTYPE 0x52 53 #define DEVTYPE_EOF 0x53 54 55 /* query commands */ 56 #define CMD_GETDATA_NTC 0x41 /* TEMPerNTC NTC part */ 57 #define CMD_RESET0 0x43 /* TEMPer, TEMPer[12], TEMPerNTC */ 58 #define CMD_RESET1 0x44 /* TEMPer, TEMPer[12] */ 59 #define CMD_GETDATA 0x48 /* TEMPerHUM */ 60 #define CMD_GETDATA_OUTER 0x53 /* TEMPer, TEMPer[12], TEMPerNTC */ 61 #define CMD_GETDATA_INNER 0x54 /* TEMPer, TEMPer[12], TEMPerNTC */ 62 #define CMD_GETDATA_EOF 0x31 63 #define CMD_GETDATA_EOF2 0xaa 64 65 /* temperntc mode */ 66 #define TEMPERNTC_MODE_BASE 0x61 /* 0x61 - 0x68 */ 67 #define TEMPERNTC_MODE_MAX 0x68 68 #define CMD_TEMPERNTC_MODE_DONE 0x69 69 #define UTHUM_NTC_MIN_THRESHOLD 0xb300 70 #define UTHUM_NTC_MAX_THRESHOLD 0xf200 71 72 /* sensor name */ 73 #define UTHUM_TEMPER_INNER 0 74 #define UTHUM_TEMPER_OUTER 1 75 #define UTHUM_TEMPER_NTC 1 76 #define UTHUM_TEMPERHUM_TEMP 0 77 #define UTHUM_TEMPERHUM_HUM 1 78 79 enum uthum_sensor_type { 80 UTHUM_SENSOR_UNKNOWN, 81 UTHUM_SENSOR_SHT1X, 82 UTHUM_SENSOR_DS75, 83 UTHUM_SENSOR_NTC, 84 UTHUM_SENSOR_MAXTYPES, 85 }; 86 87 static const char * const uthum_sensor_type_s[UTHUM_SENSOR_MAXTYPES] = { 88 "unknown", 89 "sht1x", 90 "ds75/12bit", 91 "NTC" 92 }; 93 94 static uint8_t cmd_issue[8] = 95 { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x02, 0x00 }; 96 static uint8_t cmd_query[8] = 97 { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x01, 0x00 }; 98 99 struct uthum_sensor { 100 struct ksensor sensor; 101 int cal_offset; /* mC or m%RH */ 102 int attached; 103 enum uthum_sensor_type dev_type; 104 int cur_state; /* for TEMPerNTC */ 105 }; 106 107 struct uthum_softc { 108 struct uhidev sc_hdev; 109 struct usbd_device *sc_udev; 110 int sc_device_type; 111 int sc_num_sensors; 112 113 /* uhidev parameters */ 114 size_t sc_flen; /* feature report length */ 115 size_t sc_ilen; /* input report length */ 116 size_t sc_olen; /* output report length */ 117 118 /* sensor framework */ 119 struct uthum_sensor sc_sensor[UTHUM_MAX_SENSORS]; 120 struct ksensordev sc_sensordev; 121 struct sensor_task *sc_sensortask; 122 }; 123 124 const struct usb_devno uthum_devs[] = { 125 /* XXX: various TEMPer variants are using same VID/PID */ 126 { USB_VENDOR_TENX, USB_PRODUCT_TENX_TEMPER}, 127 }; 128 #define uthum_lookup(v, p) usb_lookup(uthum_devs, v, p) 129 130 int uthum_match(struct device *, void *, void *); 131 void uthum_attach(struct device *, struct device *, void *); 132 int uthum_detach(struct device *, int); 133 134 int uthum_issue_cmd(struct uthum_softc *, uint8_t, int); 135 int uthum_read_data(struct uthum_softc *, uint8_t, uint8_t *, size_t, int); 136 int uthum_check_device_info(struct uthum_softc *); 137 void uthum_reset_device(struct uthum_softc *); 138 void uthum_setup_sensors(struct uthum_softc *); 139 140 void uthum_intr(struct uhidev *, void *, u_int); 141 void uthum_refresh(void *); 142 void uthum_refresh_temper(struct uthum_softc *, int); 143 void uthum_refresh_temperhum(struct uthum_softc *); 144 void uthum_refresh_temperntc(struct uthum_softc *, int); 145 146 int uthum_ntc_getdata(struct uthum_softc *, int *); 147 int uthum_ntc_tuning(struct uthum_softc *, int, int *); 148 int64_t uthum_ntc_temp(int64_t, int); 149 int uthum_sht1x_temp(uint8_t, uint8_t); 150 int uthum_sht1x_rh(uint8_t, uint8_t, int); 151 int uthum_ds75_temp(uint8_t, uint8_t); 152 void uthum_print_sensorinfo(struct uthum_softc *, int); 153 154 struct cfdriver uthum_cd = { 155 NULL, "uthum", DV_DULL 156 }; 157 158 const struct cfattach uthum_ca = { 159 sizeof(struct uthum_softc), 160 uthum_match, 161 uthum_attach, 162 uthum_detach 163 }; 164 165 int 166 uthum_match(struct device *parent, void *match, void *aux) 167 { 168 struct uhidev_attach_arg *uha = aux; 169 170 if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID) 171 return (UMATCH_NONE); 172 173 if (uthum_lookup(uha->uaa->vendor, uha->uaa->product) == NULL) 174 return UMATCH_NONE; 175 176 #if 0 /* attach only sensor part of HID as uthum* */ 177 #define HUG_UNKNOWN_3 0x0003 178 void *desc; 179 int size; 180 uhidev_get_report_desc(uha->parent, &desc, &size); 181 if (!hid_is_collection(desc, size, uha->reportid, 182 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_UNKNOWN_3))) 183 return (UMATCH_NONE); 184 #undef HUG_UNKNOWN_3 185 #endif 186 187 return (UMATCH_VENDOR_PRODUCT); 188 } 189 190 void 191 uthum_attach(struct device *parent, struct device *self, void *aux) 192 { 193 struct uthum_softc *sc = (struct uthum_softc *)self; 194 struct usb_attach_arg *uaa = aux; 195 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; 196 struct usbd_device *dev = uha->parent->sc_udev; 197 int i, size, repid; 198 void *desc; 199 200 sc->sc_udev = dev; 201 sc->sc_hdev.sc_intr = uthum_intr; 202 sc->sc_hdev.sc_parent = uha->parent; 203 sc->sc_hdev.sc_report_id = uha->reportid; 204 sc->sc_num_sensors = 0; 205 206 uhidev_get_report_desc(uha->parent, &desc, &size); 207 repid = uha->reportid; 208 sc->sc_ilen = hid_report_size(desc, size, hid_input, repid); 209 sc->sc_olen = hid_report_size(desc, size, hid_output, repid); 210 sc->sc_flen = hid_report_size(desc, size, hid_feature, repid); 211 212 printf("\n"); 213 214 if (sc->sc_flen < 32) { 215 /* not sensor interface, just attach */ 216 return; 217 } 218 219 /* maybe unsupported device */ 220 if (uthum_check_device_info(sc) < 0) { 221 DPRINTF(("uthum: unknown device\n")); 222 return; 223 }; 224 225 /* attach sensor */ 226 strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname, 227 sizeof(sc->sc_sensordev.xname)); 228 uthum_setup_sensors(sc); 229 230 /* attach sensors */ 231 for (i = 0; i < UTHUM_MAX_SENSORS; i++) { 232 if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_UNKNOWN) 233 continue; 234 uthum_print_sensorinfo(sc, i); 235 sc->sc_sensor[i].sensor.flags |= SENSOR_FINVALID; 236 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i].sensor); 237 sc->sc_sensor[i].attached = 1; 238 sc->sc_num_sensors++; 239 } 240 241 if (sc->sc_num_sensors > 0) { 242 /* 0.1Hz */ 243 sc->sc_sensortask = sensor_task_register(sc, uthum_refresh, 6); 244 if (sc->sc_sensortask == NULL) { 245 printf(", unable to register update task\n"); 246 return; 247 } 248 sensordev_install(&sc->sc_sensordev); 249 } 250 251 DPRINTF(("uthum_attach: complete\n")); 252 } 253 254 int 255 uthum_detach(struct device *self, int flags) 256 { 257 struct uthum_softc *sc = (struct uthum_softc *)self; 258 int i, rv = 0; 259 260 if (sc->sc_num_sensors > 0) { 261 wakeup(&sc->sc_sensortask); 262 sensordev_deinstall(&sc->sc_sensordev); 263 for (i = 0; i < UTHUM_MAX_SENSORS; i++) { 264 if (sc->sc_sensor[i].attached) 265 sensor_detach(&sc->sc_sensordev, 266 &sc->sc_sensor[i].sensor); 267 } 268 if (sc->sc_sensortask != NULL) 269 sensor_task_unregister(sc->sc_sensortask); 270 } 271 272 uthum_reset_device(sc); 273 274 return (rv); 275 } 276 277 void 278 uthum_intr(struct uhidev *addr, void *ibuf, u_int len) 279 { 280 /* do nothing */ 281 } 282 283 int 284 uthum_issue_cmd(struct uthum_softc *sc, uint8_t target_cmd, int delay) 285 { 286 uint8_t cmdbuf[32]; 287 int i, actlen; 288 289 bzero(cmdbuf, sizeof(cmdbuf)); 290 memcpy(cmdbuf, cmd_issue, sizeof(cmd_issue)); 291 actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 292 sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen); 293 if (actlen != sc->sc_olen) 294 return EIO; 295 296 bzero(cmdbuf, sizeof(cmdbuf)); 297 cmdbuf[0] = target_cmd; 298 actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 299 sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen); 300 if (actlen != sc->sc_olen) 301 return EIO; 302 303 bzero(cmdbuf, sizeof(cmdbuf)); 304 for (i = 0; i < 7; i++) { 305 actlen = uhidev_set_report(sc->sc_hdev.sc_parent, 306 UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, cmdbuf, 307 sc->sc_olen); 308 if (actlen != sc->sc_olen) 309 return EIO; 310 } 311 312 /* wait if required */ 313 if (delay > 0) 314 tsleep(&sc->sc_sensortask, 0, "uthum", (delay*hz+999)/1000 + 1); 315 316 return 0; 317 } 318 319 int 320 uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf, 321 size_t len, int delay) 322 { 323 uint8_t cmdbuf[32], report[256]; 324 325 /* if return buffer is null, do nothing */ 326 if ((buf == NULL) || len == 0) 327 return 0; 328 329 if (uthum_issue_cmd(sc, target_cmd, 50)) 330 return 0; 331 332 bzero(cmdbuf, sizeof(cmdbuf)); 333 memcpy(cmdbuf, cmd_query, sizeof(cmd_query)); 334 if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, 335 sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen) != sc->sc_olen) 336 return EIO; 337 338 /* wait if required */ 339 if (delay > 0) 340 tsleep(&sc->sc_sensortask, 0, "uthum", (delay*hz+999)/1000 + 1); 341 342 /* get answer */ 343 if (uhidev_get_report(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT, 344 sc->sc_hdev.sc_report_id, report, sc->sc_flen) != sc->sc_flen) 345 return EIO; 346 memcpy(buf, report, len); 347 return 0; 348 } 349 350 int 351 uthum_check_device_info(struct uthum_softc *sc) 352 { 353 struct uthum_dev_info { 354 uint16_t dev_type; 355 uint8_t cal[2][2]; /* calibration offsets */ 356 uint8_t footer; 357 uint8_t padding[25]; 358 } dinfo; 359 int val, dev_type; 360 int retry = 3; 361 362 /* issue query to device */ 363 while (retry) { 364 if (uthum_read_data(sc, CMD_DEVTYPE, (void *)&dinfo, 365 sizeof(struct uthum_dev_info), 0) != 0) { 366 DPRINTF(("uthum: device information query fail.\n")); 367 retry--; 368 continue; 369 } 370 if (dinfo.footer != DEVTYPE_EOF) { 371 /* it will be a bogus entry, retry. */ 372 retry--; 373 } else 374 break; 375 } 376 377 if (retry <= 0) 378 return EIO; 379 380 dev_type = betoh16(dinfo.dev_type); 381 /* TEMPerHUM has 2 different device identifiers, unify them */ 382 if (dev_type == UTHUM_TYPE_TEMPERHUM_2) 383 dev_type = UTHUM_TYPE_TEMPERHUM; 384 385 /* check device type and calibration offset*/ 386 switch (dev_type) { 387 case UTHUM_TYPE_TEMPER2: 388 case UTHUM_TYPE_TEMPERHUM: 389 case UTHUM_TYPE_TEMPERNTC: 390 val = (dinfo.cal[1][0] - UTHUM_CAL_OFFSET) * 100; 391 val += dinfo.cal[1][1] * 10; 392 sc->sc_sensor[1].cal_offset = val; 393 /* fall down, don't break */ 394 case UTHUM_TYPE_TEMPER1: 395 val = (dinfo.cal[0][0] - UTHUM_CAL_OFFSET) * 100; 396 val += dinfo.cal[0][1] * 10; 397 sc->sc_sensor[0].cal_offset = val; 398 sc->sc_device_type = dev_type; 399 break; 400 default: 401 sc->sc_device_type = UTHUM_TYPE_UNKNOWN; 402 printf("uthum: unknown device (devtype = 0x%.2x)\n", 403 dev_type); 404 return EIO; 405 } 406 407 /* device specific init process */ 408 switch (dev_type) { 409 case UTHUM_TYPE_TEMPERHUM: 410 sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = 0; 411 break; 412 }; 413 414 uthum_reset_device(sc); 415 416 return 0; 417 }; 418 419 void 420 uthum_reset_device(struct uthum_softc *sc) 421 { 422 switch (sc->sc_device_type) { 423 case UTHUM_TYPE_TEMPER1: 424 case UTHUM_TYPE_TEMPERNTC: 425 uthum_issue_cmd(sc, CMD_RESET0, 200); 426 break; 427 case UTHUM_TYPE_TEMPER2: 428 uthum_issue_cmd(sc, CMD_RESET0, 200); 429 uthum_issue_cmd(sc, CMD_RESET1, 200); 430 break; 431 } 432 } 433 434 void 435 uthum_setup_sensors(struct uthum_softc *sc) 436 { 437 int i; 438 439 for (i = 0; i < UTHUM_MAX_SENSORS; i++) 440 sc->sc_sensor[i].dev_type = UTHUM_SENSOR_UNKNOWN; 441 442 switch (sc->sc_device_type) { 443 case UTHUM_TYPE_TEMPER2: /* 2 temperature sensors */ 444 sc->sc_sensor[UTHUM_TEMPER_OUTER].dev_type = 445 UTHUM_SENSOR_DS75; 446 sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.type = 447 SENSOR_TEMP; 448 strlcpy(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc, 449 "outer", 450 sizeof(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc)); 451 /* fall down */ 452 case UTHUM_TYPE_TEMPER1: /* 1 temperature sensor */ 453 sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type = 454 UTHUM_SENSOR_DS75; 455 sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.type = 456 SENSOR_TEMP; 457 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc, 458 "inner", 459 sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc)); 460 break; 461 case UTHUM_TYPE_TEMPERHUM: 462 /* 1 temperature sensor and 1 humidity sensor */ 463 for (i = 0; i < 2; i++) 464 sc->sc_sensor[i].dev_type = UTHUM_SENSOR_SHT1X; 465 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.type = SENSOR_TEMP; 466 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.type = 467 SENSOR_HUMIDITY; 468 strlcpy(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc, 469 "RH", 470 sizeof(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc)); 471 break; 472 case UTHUM_TYPE_TEMPERNTC: 473 /* 2 temperature sensors */ 474 for (i = 0; i < 2; i++) 475 sc->sc_sensor[i].sensor.type = SENSOR_TEMP; 476 sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type = 477 UTHUM_SENSOR_DS75; 478 sc->sc_sensor[UTHUM_TEMPER_NTC].dev_type = 479 UTHUM_SENSOR_NTC; 480 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc, 481 "inner", 482 sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc)); 483 strlcpy(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc, 484 "outer/ntc", 485 sizeof(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc)); 486 487 /* sensor state tuning */ 488 for (i = 0; i < 4; i++) 489 uthum_issue_cmd(sc, TEMPERNTC_MODE_BASE, 50); 490 sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = TEMPERNTC_MODE_BASE; 491 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, NULL)) 492 DPRINTF(("uthum: NTC sensor tuning failed\n")); 493 uthum_issue_cmd(sc, CMD_TEMPERNTC_MODE_DONE, 100); 494 break; 495 default: 496 /* do nothing */ 497 break; 498 } 499 } 500 501 int 502 uthum_ntc_getdata(struct uthum_softc *sc, int *val) 503 { 504 uint8_t buf[8]; 505 506 if (val == NULL) 507 return EIO; 508 509 /* get sensor value */ 510 if (uthum_read_data(sc, CMD_GETDATA_NTC, buf, sizeof(buf), 10) != 0) { 511 DPRINTF(("uthum: data read fail\n")); 512 return EIO; 513 } 514 515 /* check data integrity */ 516 if (buf[2] != CMD_GETDATA_EOF2) { 517 DPRINTF(("uthum: broken ntc data 0x%.2x 0x%.2x 0x%.2x\n", 518 buf[0], buf[1], buf[2])); 519 return EIO; 520 } 521 522 *val = (buf[0] << 8) + buf[1]; 523 return 0; 524 } 525 526 int 527 uthum_ntc_tuning(struct uthum_softc *sc, int sensor, int *val) 528 { 529 struct uthum_sensor *s; 530 int done, state, ostate, curval; 531 int retry = 3; 532 533 s = &sc->sc_sensor[sensor]; 534 state = s->cur_state; 535 536 /* get current sensor value */ 537 if (val == NULL) { 538 while (retry) { 539 if (uthum_ntc_getdata(sc, &curval)) { 540 retry--; 541 continue; 542 } else 543 break; 544 } 545 if (retry <= 0) 546 return EIO; 547 } else { 548 curval = *val; 549 } 550 551 /* no state change is required */ 552 if ((curval >= UTHUM_NTC_MIN_THRESHOLD) && 553 (curval <= UTHUM_NTC_MAX_THRESHOLD)) { 554 return 0; 555 } 556 557 if (((curval < UTHUM_NTC_MIN_THRESHOLD) && 558 (state == TEMPERNTC_MODE_MAX)) || 559 ((curval > UTHUM_NTC_MAX_THRESHOLD) && 560 (state == TEMPERNTC_MODE_BASE))) 561 return 0; 562 563 DPRINTF(("uthum: ntc tuning start. cur state = 0x%.2x, val = 0x%.4x\n", 564 state, curval)); 565 566 /* tuning loop */ 567 ostate = state; 568 done = 0; 569 while (!done) { 570 if (curval < UTHUM_NTC_MIN_THRESHOLD) { 571 if (state == TEMPERNTC_MODE_MAX) 572 done++; 573 else 574 state++; 575 } else if (curval > UTHUM_NTC_MAX_THRESHOLD) { 576 if (state == TEMPERNTC_MODE_BASE) 577 done++; 578 else 579 state--; 580 } else { 581 uthum_ntc_getdata(sc, &curval); 582 if ((curval >= UTHUM_NTC_MIN_THRESHOLD) && 583 (curval <= UTHUM_NTC_MAX_THRESHOLD)) 584 done++; 585 } 586 587 /* update state */ 588 if (state != ostate) { 589 uthum_issue_cmd(sc, state, 50); 590 uthum_issue_cmd(sc, state, 50); 591 uthum_ntc_getdata(sc, &curval); 592 } 593 ostate = state; 594 } 595 596 DPRINTF(("uthum: ntc tuning done. state change: 0x%.2x->0x%.2x\n", 597 s->cur_state, state)); 598 s->cur_state = state; 599 if (val != NULL) 600 *val = curval; 601 602 return 0; 603 } 604 605 void 606 uthum_refresh(void *arg) 607 { 608 struct uthum_softc *sc = arg; 609 int i; 610 611 switch (sc->sc_device_type) { 612 case UTHUM_TYPE_TEMPER1: 613 case UTHUM_TYPE_TEMPER2: 614 case UTHUM_TYPE_TEMPERNTC: 615 for (i = 0; i < sc->sc_num_sensors; i++) { 616 if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_DS75) 617 uthum_refresh_temper(sc, i); 618 else if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_NTC) 619 uthum_refresh_temperntc(sc, i); 620 } 621 break; 622 case UTHUM_TYPE_TEMPERHUM: 623 uthum_refresh_temperhum(sc); 624 break; 625 default: 626 break; 627 /* never reach */ 628 } 629 } 630 631 void 632 uthum_refresh_temperhum(struct uthum_softc *sc) 633 { 634 uint8_t buf[8]; 635 int temp, rh; 636 637 if (uthum_read_data(sc, CMD_GETDATA, buf, sizeof(buf), 1000) != 0) { 638 DPRINTF(("uthum: data read fail\n")); 639 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags 640 |= SENSOR_FINVALID; 641 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags 642 |= SENSOR_FINVALID; 643 return; 644 } 645 646 temp = uthum_sht1x_temp(buf[0], buf[1]); 647 rh = uthum_sht1x_rh(buf[2], buf[3], temp); 648 649 /* apply calibration offsets */ 650 temp += sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].cal_offset; 651 rh += sc->sc_sensor[UTHUM_TEMPERHUM_HUM].cal_offset; 652 653 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.value = 654 (temp * 10000) + 273150000; 655 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags &= ~SENSOR_FINVALID; 656 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.value = rh; 657 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags &= ~SENSOR_FINVALID; 658 } 659 660 void 661 uthum_refresh_temper(struct uthum_softc *sc, int sensor) 662 { 663 uint8_t buf[8]; 664 uint8_t cmd; 665 int temp; 666 667 if (sensor == UTHUM_TEMPER_INNER) 668 cmd = CMD_GETDATA_INNER; 669 else if (sensor == UTHUM_TEMPER_OUTER) 670 cmd = CMD_GETDATA_OUTER; 671 else 672 return; 673 674 /* get sensor value */ 675 if (uthum_read_data(sc, cmd, buf, sizeof(buf), 1000) != 0) { 676 DPRINTF(("uthum: data read fail\n")); 677 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID; 678 return; 679 } 680 681 /* check integrity */ 682 if (buf[2] != CMD_GETDATA_EOF) { 683 DPRINTF(("uthum: broken ds75 data: 0x%.2x 0x%.2x 0x%.2x\n", 684 buf[0], buf[1], buf[2])); 685 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID; 686 return; 687 } 688 temp = uthum_ds75_temp(buf[0], buf[1]); 689 690 /* apply calibration offset */ 691 temp += sc->sc_sensor[sensor].cal_offset; 692 693 sc->sc_sensor[sensor].sensor.value = (temp * 10000) + 273150000; 694 sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID; 695 } 696 697 void 698 uthum_refresh_temperntc(struct uthum_softc *sc, int sensor) 699 { 700 int val; 701 int64_t temp; 702 703 /* get sensor data */ 704 if (uthum_ntc_getdata(sc, &val)) { 705 DPRINTF(("uthum: ntc data read fail\n")); 706 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID; 707 return; 708 } 709 710 /* adjust sensor state */ 711 if ((val < UTHUM_NTC_MIN_THRESHOLD) || 712 (val > UTHUM_NTC_MAX_THRESHOLD)) { 713 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, &val)) { 714 DPRINTF(("uthum: NTC sensor tuning failed\n")); 715 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID; 716 return; 717 } 718 } 719 720 temp = uthum_ntc_temp(val, sc->sc_sensor[sensor].cur_state); 721 if (temp == 0) { 722 /* XXX: work around. */ 723 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID; 724 } else { 725 /* apply calibration offset */ 726 temp += sc->sc_sensor[sensor].cal_offset * 10000; 727 sc->sc_sensor[sensor].sensor.value = temp; 728 sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID; 729 } 730 } 731 732 /* return C-degree * 100 value */ 733 int 734 uthum_ds75_temp(uint8_t msb, uint8_t lsb) 735 { 736 /* DS75: 12bit precision mode : 0.0625 degrees Celsius ticks */ 737 return (msb * 100) + ((lsb >> 4) * 25 / 4); 738 } 739 740 /* return C-degree * 100 value */ 741 int 742 uthum_sht1x_temp(uint8_t msb, uint8_t lsb) 743 { 744 int nticks; 745 746 /* sensor device VDD-bias value table 747 * ---------------------------------------------- 748 * VDD 2.5V 3.0V 3.5V 4.0V 5.0V 749 * bias -3940 -3960 -3970 -3980 -4010 750 * ---------------------------------------------- 751 * 752 * as the VDD of the SHT10 on my TEMPerHUM is 3.43V +/- 0.05V, 753 * bias -3970 will be best for that device. 754 */ 755 756 nticks = (msb * 256 + lsb) & 0x3fff; 757 return (nticks - 3970); 758 } 759 760 /* return %RH * 1000 */ 761 int 762 uthum_sht1x_rh(uint8_t msb, uint8_t lsb, int temp) 763 { 764 int nticks, rh_l; 765 766 nticks = (msb * 256 + lsb) & 0x0fff; 767 rh_l = (-40000 + 405 * nticks) - ((7 * nticks * nticks) / 250); 768 769 return ((temp - 2500) * (1 + (nticks >> 7)) + rh_l) / 10; 770 } 771 772 /* return muK */ 773 int64_t 774 uthum_ntc_temp(int64_t val, int state) 775 { 776 int64_t temp = 0; 777 778 switch (state) { 779 case TEMPERNTC_MODE_BASE: /* 0x61 */ 780 case TEMPERNTC_MODE_BASE+1: /* 0x62 */ 781 case TEMPERNTC_MODE_BASE+2: /* 0x63 */ 782 case TEMPERNTC_MODE_BASE+3: /* 0x64 */ 783 /* XXX, no data */ 784 temp = -273150000; 785 break; 786 case TEMPERNTC_MODE_BASE+4: /* 0x65 */ 787 temp = ((val * val * 2977) / 100000) - (val * 4300) + 152450000; 788 break; 789 case TEMPERNTC_MODE_BASE+5: /* 0x66 */ 790 temp = ((val * val * 3887) / 100000) - (val * 5300) + 197590000; 791 break; 792 case TEMPERNTC_MODE_BASE+6: /* 0x67 */ 793 temp = ((val * val * 3495) / 100000) - (val * 5000) + 210590000; 794 break; 795 case TEMPERNTC_MODE_BASE+7: /* 0x68 */ 796 if (val < UTHUM_NTC_MIN_THRESHOLD) 797 temp = (val * -1700) + 149630000; 798 else 799 temp = ((val * val * 3257) / 100000) - (val * 4900) + 800 230470000; 801 break; 802 default: 803 DPRINTF(("NTC state error, unknown state 0x%.2x\n", state)); 804 break; 805 } 806 807 /* convert muC->muK value */ 808 return temp + 273150000; 809 } 810 811 void 812 uthum_print_sensorinfo(struct uthum_softc *sc, int num) 813 { 814 struct uthum_sensor *s; 815 s = &sc->sc_sensor[num]; 816 817 printf("%s: ", sc->sc_hdev.sc_dev.dv_xname); 818 switch (s->sensor.type) { 819 case SENSOR_TEMP: 820 printf("type %s (temperature)", 821 uthum_sensor_type_s[s->dev_type]); 822 if (s->cal_offset) 823 printf(", calibration offset %c%d.%d degC", 824 (s->cal_offset < 0) ? '-' : '+', 825 abs(s->cal_offset / 100), 826 abs(s->cal_offset % 100)); 827 break; 828 case SENSOR_HUMIDITY: 829 printf("type %s (humidity)", 830 uthum_sensor_type_s[s->dev_type]); 831 if (s->cal_offset) 832 printf("calibration offset %c%d.%d %%RH", 833 (s->cal_offset < 0) ? '-' : '+', 834 abs(s->cal_offset / 100), 835 abs(s->cal_offset % 100)); 836 break; 837 default: 838 printf("unknown"); 839 } 840 printf("\n"); 841 } 842