si7020.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
  4. * Copyright (c) 2013,2014 Uplogix, Inc.
  5. * David Barksdale <[email protected]>
  6. */
  7. /*
  8. * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
  9. * are i2c devices which have an identical programming interface for
  10. * measuring relative humidity and temperature. The Si7013 has an additional
  11. * temperature input which this driver does not support.
  12. *
  13. * Data Sheets:
  14. * Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
  15. * Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
  16. * Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
  17. */
  18. #include <linux/delay.h>
  19. #include <linux/i2c.h>
  20. #include <linux/module.h>
  21. #include <linux/mod_devicetable.h>
  22. #include <linux/slab.h>
  23. #include <linux/sysfs.h>
  24. #include <linux/iio/iio.h>
  25. #include <linux/iio/sysfs.h>
  26. /* Measure Relative Humidity, Hold Master Mode */
  27. #define SI7020CMD_RH_HOLD 0xE5
  28. /* Measure Temperature, Hold Master Mode */
  29. #define SI7020CMD_TEMP_HOLD 0xE3
  30. /* Software Reset */
  31. #define SI7020CMD_RESET 0xFE
  32. static int si7020_read_raw(struct iio_dev *indio_dev,
  33. struct iio_chan_spec const *chan, int *val,
  34. int *val2, long mask)
  35. {
  36. struct i2c_client **client = iio_priv(indio_dev);
  37. int ret;
  38. switch (mask) {
  39. case IIO_CHAN_INFO_RAW:
  40. ret = i2c_smbus_read_word_swapped(*client,
  41. chan->type == IIO_TEMP ?
  42. SI7020CMD_TEMP_HOLD :
  43. SI7020CMD_RH_HOLD);
  44. if (ret < 0)
  45. return ret;
  46. *val = ret >> 2;
  47. /*
  48. * Humidity values can slightly exceed the 0-100%RH
  49. * range and should be corrected by software
  50. */
  51. if (chan->type == IIO_HUMIDITYRELATIVE)
  52. *val = clamp_val(*val, 786, 13893);
  53. return IIO_VAL_INT;
  54. case IIO_CHAN_INFO_SCALE:
  55. if (chan->type == IIO_TEMP)
  56. *val = 175720; /* = 175.72 * 1000 */
  57. else
  58. *val = 125 * 1000;
  59. *val2 = 65536 >> 2;
  60. return IIO_VAL_FRACTIONAL;
  61. case IIO_CHAN_INFO_OFFSET:
  62. /*
  63. * Since iio_convert_raw_to_processed_unlocked assumes offset
  64. * is an integer we have to round these values and lose
  65. * accuracy.
  66. * Relative humidity will be 0.0032959% too high and
  67. * temperature will be 0.00277344 degrees too high.
  68. * This is no big deal because it's within the accuracy of the
  69. * sensor.
  70. */
  71. if (chan->type == IIO_TEMP)
  72. *val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
  73. else
  74. *val = -786; /* = -6 * (65536 >> 2) / 125 */
  75. return IIO_VAL_INT;
  76. default:
  77. break;
  78. }
  79. return -EINVAL;
  80. }
  81. static const struct iio_chan_spec si7020_channels[] = {
  82. {
  83. .type = IIO_HUMIDITYRELATIVE,
  84. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  85. BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  86. },
  87. {
  88. .type = IIO_TEMP,
  89. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  90. BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  91. }
  92. };
  93. static const struct iio_info si7020_info = {
  94. .read_raw = si7020_read_raw,
  95. };
  96. static int si7020_probe(struct i2c_client *client,
  97. const struct i2c_device_id *id)
  98. {
  99. struct iio_dev *indio_dev;
  100. struct i2c_client **data;
  101. int ret;
  102. if (!i2c_check_functionality(client->adapter,
  103. I2C_FUNC_SMBUS_WRITE_BYTE |
  104. I2C_FUNC_SMBUS_READ_WORD_DATA))
  105. return -EOPNOTSUPP;
  106. /* Reset device, loads default settings. */
  107. ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
  108. if (ret < 0)
  109. return ret;
  110. /* Wait the maximum power-up time after software reset. */
  111. msleep(15);
  112. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  113. if (!indio_dev)
  114. return -ENOMEM;
  115. data = iio_priv(indio_dev);
  116. *data = client;
  117. indio_dev->name = dev_name(&client->dev);
  118. indio_dev->modes = INDIO_DIRECT_MODE;
  119. indio_dev->info = &si7020_info;
  120. indio_dev->channels = si7020_channels;
  121. indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
  122. return devm_iio_device_register(&client->dev, indio_dev);
  123. }
  124. static const struct i2c_device_id si7020_id[] = {
  125. { "si7020", 0 },
  126. { "th06", 0 },
  127. { }
  128. };
  129. MODULE_DEVICE_TABLE(i2c, si7020_id);
  130. static const struct of_device_id si7020_dt_ids[] = {
  131. { .compatible = "silabs,si7020" },
  132. { }
  133. };
  134. MODULE_DEVICE_TABLE(of, si7020_dt_ids);
  135. static struct i2c_driver si7020_driver = {
  136. .driver = {
  137. .name = "si7020",
  138. .of_match_table = si7020_dt_ids,
  139. },
  140. .probe = si7020_probe,
  141. .id_table = si7020_id,
  142. };
  143. module_i2c_driver(si7020_driver);
  144. MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
  145. MODULE_AUTHOR("David Barksdale <[email protected]>");
  146. MODULE_LICENSE("GPL");