Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: humditiy: hdc3020: fix units for thresholds and hysteresis

According to the ABI the units after application of scale and offset are
milli degree celsius for temperature thresholds and milli percent for
relative humidity thresholds. Currently the resulting units are degree
celsius for temperature thresholds and hysteresis and percent for relative
humidity thresholds and hysteresis. Change scale factor to fix this issue.

Fixes: 3ad0e7e5f0cb ("iio: humidity: hdc3020: add threshold events support")
Reported-by: Chris Lesiak <chris.lesiak@licorbio.com>
Reviewed-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Signed-off-by: Dimitri Fedrau <dimitri.fedrau@liebherr.com>
Cc: <Stable@vger.kernel.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Dimitri Fedrau and committed by
Jonathan Cameron
cb372b4f 7b8dc11c

+41 -28
+41 -28
drivers/iio/humidity/hdc3020.c
··· 72 72 #define HDC3020_MAX_TEMP_HYST_MICRO 164748607 73 73 #define HDC3020_MAX_HUM_MICRO 99220264 74 74 75 + /* Divide 65535 from the datasheet by 5 to avoid overflows */ 76 + #define HDC3020_THRESH_FRACTION (65535 / 5) 77 + 75 78 struct hdc3020_data { 76 79 struct i2c_client *client; 77 80 struct gpio_desc *reset_gpio; ··· 379 376 int temp; 380 377 381 378 /* 382 - * Get the temperature threshold from 9 LSBs, shift them to get 383 - * the truncated temperature threshold representation and 384 - * calculate the threshold according to the formula in the 385 - * datasheet. Result is degree celsius scaled by 65535. 379 + * Get the temperature threshold from 9 LSBs, shift them to get the 380 + * truncated temperature threshold representation and calculate the 381 + * threshold according to the explicit formula in the datasheet: 382 + * T(C) = -45 + (175 * temp) / 65535. 383 + * Additionally scale by HDC3020_THRESH_FRACTION to avoid precision loss 384 + * when calculating threshold and hysteresis values. Result is degree 385 + * celsius scaled by HDC3020_THRESH_FRACTION. 386 386 */ 387 387 temp = FIELD_GET(HDC3020_THRESH_TEMP_MASK, thresh) << 388 388 HDC3020_THRESH_TEMP_TRUNC_SHIFT; 389 389 390 - return -2949075 + (175 * temp); 390 + return -2949075 / 5 + (175 / 5 * temp); 391 391 } 392 392 393 393 static int hdc3020_thresh_get_hum(u16 thresh) ··· 400 394 /* 401 395 * Get the humidity threshold from 7 MSBs, shift them to get the 402 396 * truncated humidity threshold representation and calculate the 403 - * threshold according to the formula in the datasheet. Result is 404 - * percent scaled by 65535. 397 + * threshold according to the explicit formula in the datasheet: 398 + * RH(%) = 100 * hum / 65535. 399 + * Additionally scale by HDC3020_THRESH_FRACTION to avoid precision loss 400 + * when calculating threshold and hysteresis values. Result is percent 401 + * scaled by HDC3020_THRESH_FRACTION. 405 402 */ 406 403 hum = FIELD_GET(HDC3020_THRESH_HUM_MASK, thresh) << 407 404 HDC3020_THRESH_HUM_TRUNC_SHIFT; 408 405 409 - return hum * 100; 406 + return hum * 100 / 5; 410 407 } 411 408 412 409 static u16 hdc3020_thresh_set_temp(int s_temp, u16 curr_thresh) ··· 464 455 else 465 456 s_clr = s_thresh + s_hyst; 466 457 467 - /* Divide by 65535 to get units of micro */ 468 - return div_s64(s_clr, 65535); 458 + /* Divide by HDC3020_THRESH_FRACTION to get units of micro */ 459 + return div_s64(s_clr, HDC3020_THRESH_FRACTION); 469 460 } 470 461 471 462 static int _hdc3020_write_thresh(struct hdc3020_data *data, u16 reg, u16 val) ··· 516 507 517 508 clr = ret; 518 509 /* Scale value to include decimal part into calculations */ 519 - s_val = (val < 0) ? (val * 1000000 - val2) : (val * 1000000 + val2); 510 + s_val = (val < 0) ? (val * 1000 - val2) : (val * 1000 + val2); 520 511 switch (chan->type) { 521 512 case IIO_TEMP: 522 513 switch (info) { ··· 532 523 /* Calculate old hysteresis */ 533 524 s_thresh = (s64)hdc3020_thresh_get_temp(thresh) * 1000000; 534 525 s_clr = (s64)hdc3020_thresh_get_temp(clr) * 1000000; 535 - s_hyst = div_s64(abs(s_thresh - s_clr), 65535); 526 + s_hyst = div_s64(abs(s_thresh - s_clr), 527 + HDC3020_THRESH_FRACTION); 536 528 /* Set new threshold */ 537 529 thresh = reg_val; 538 530 /* Set old hysteresis */ ··· 542 532 case IIO_EV_INFO_HYSTERESIS: 543 533 /* 544 534 * Function hdc3020_thresh_get_temp returns temperature 545 - * in degree celsius scaled by 65535. Scale by 1000000 546 - * to be able to subtract scaled hysteresis value. 535 + * in degree celsius scaled by HDC3020_THRESH_FRACTION. 536 + * Scale by 1000000 to be able to subtract scaled 537 + * hysteresis value. 547 538 */ 548 539 s_thresh = (s64)hdc3020_thresh_get_temp(thresh) * 1000000; 549 540 /* 550 541 * Units of s_val are in micro degree celsius, scale by 551 - * 65535 to get same units as s_thresh. 542 + * HDC3020_THRESH_FRACTION to get same units as s_thresh. 552 543 */ 553 544 s_val = min(abs(s_val), HDC3020_MAX_TEMP_HYST_MICRO); 554 - s_hyst = (s64)s_val * 65535; 545 + s_hyst = (s64)s_val * HDC3020_THRESH_FRACTION; 555 546 s_clr = hdc3020_thresh_clr(s_thresh, s_hyst, dir); 556 547 s_clr = max(s_clr, HDC3020_MIN_TEMP_MICRO); 557 548 s_clr = min(s_clr, HDC3020_MAX_TEMP_MICRO); ··· 576 565 /* Calculate old hysteresis */ 577 566 s_thresh = (s64)hdc3020_thresh_get_hum(thresh) * 1000000; 578 567 s_clr = (s64)hdc3020_thresh_get_hum(clr) * 1000000; 579 - s_hyst = div_s64(abs(s_thresh - s_clr), 65535); 568 + s_hyst = div_s64(abs(s_thresh - s_clr), 569 + HDC3020_THRESH_FRACTION); 580 570 /* Set new threshold */ 581 571 thresh = reg_val; 582 572 /* Try to set old hysteresis */ ··· 586 574 case IIO_EV_INFO_HYSTERESIS: 587 575 /* 588 576 * Function hdc3020_thresh_get_hum returns relative 589 - * humidity in percent scaled by 65535. Scale by 1000000 590 - * to be able to subtract scaled hysteresis value. 577 + * humidity in percent scaled by HDC3020_THRESH_FRACTION. 578 + * Scale by 1000000 to be able to subtract scaled 579 + * hysteresis value. 591 580 */ 592 581 s_thresh = (s64)hdc3020_thresh_get_hum(thresh) * 1000000; 593 582 /* 594 - * Units of s_val are in micro percent, scale by 65535 595 - * to get same units as s_thresh. 583 + * Units of s_val are in micro percent, scale by 584 + * HDC3020_THRESH_FRACTION to get same units as s_thresh. 596 585 */ 597 - s_hyst = (s64)s_val * 65535; 586 + s_hyst = (s64)s_val * HDC3020_THRESH_FRACTION; 598 587 s_clr = hdc3020_thresh_clr(s_thresh, s_hyst, dir); 599 588 s_clr = max(s_clr, 0); 600 589 s_clr = min(s_clr, HDC3020_MAX_HUM_MICRO); ··· 643 630 thresh = hdc3020_thresh_get_temp(ret); 644 631 switch (info) { 645 632 case IIO_EV_INFO_VALUE: 646 - *val = thresh; 633 + *val = thresh * MILLI; 647 634 break; 648 635 case IIO_EV_INFO_HYSTERESIS: 649 636 ret = hdc3020_read_be16(data, reg_clr); ··· 651 638 return ret; 652 639 653 640 clr = hdc3020_thresh_get_temp(ret); 654 - *val = abs(thresh - clr); 641 + *val = abs(thresh - clr) * MILLI; 655 642 break; 656 643 default: 657 644 return -EOPNOTSUPP; 658 645 } 659 - *val2 = 65535; 646 + *val2 = HDC3020_THRESH_FRACTION; 660 647 return IIO_VAL_FRACTIONAL; 661 648 case IIO_HUMIDITYRELATIVE: 662 649 thresh = hdc3020_thresh_get_hum(ret); 663 650 switch (info) { 664 651 case IIO_EV_INFO_VALUE: 665 - *val = thresh; 652 + *val = thresh * MILLI; 666 653 break; 667 654 case IIO_EV_INFO_HYSTERESIS: 668 655 ret = hdc3020_read_be16(data, reg_clr); ··· 670 657 return ret; 671 658 672 659 clr = hdc3020_thresh_get_hum(ret); 673 - *val = abs(thresh - clr); 660 + *val = abs(thresh - clr) * MILLI; 674 661 break; 675 662 default: 676 663 return -EOPNOTSUPP; 677 664 } 678 - *val2 = 65535; 665 + *val2 = HDC3020_THRESH_FRACTION; 679 666 return IIO_VAL_FRACTIONAL; 680 667 default: 681 668 return -EOPNOTSUPP;