si7005.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * si7005.c - Support for Silabs Si7005 humidity and temperature sensor
  4. *
  5. * Copyright (c) 2014 Peter Meerwald <[email protected]>
  6. *
  7. * (7-bit I2C slave address 0x40)
  8. *
  9. * TODO: heater, fast mode, processed mode (temp. / linearity compensation)
  10. */
  11. #include <linux/err.h>
  12. #include <linux/i2c.h>
  13. #include <linux/delay.h>
  14. #include <linux/module.h>
  15. #include <linux/pm.h>
  16. #include <linux/iio/iio.h>
  17. #include <linux/iio/sysfs.h>
  18. #define SI7005_STATUS 0x00
  19. #define SI7005_DATA 0x01 /* 16-bit, MSB */
  20. #define SI7005_CONFIG 0x03
  21. #define SI7005_ID 0x11
  22. #define SI7005_STATUS_NRDY BIT(0)
  23. #define SI7005_CONFIG_TEMP BIT(4)
  24. #define SI7005_CONFIG_START BIT(0)
  25. #define SI7005_ID_7005 0x50
  26. #define SI7005_ID_7015 0xf0
  27. struct si7005_data {
  28. struct i2c_client *client;
  29. struct mutex lock;
  30. u8 config;
  31. };
  32. static int si7005_read_measurement(struct si7005_data *data, bool temp)
  33. {
  34. int tries = 50;
  35. int ret;
  36. mutex_lock(&data->lock);
  37. ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,
  38. data->config | SI7005_CONFIG_START |
  39. (temp ? SI7005_CONFIG_TEMP : 0));
  40. if (ret < 0)
  41. goto done;
  42. while (tries-- > 0) {
  43. msleep(20);
  44. ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);
  45. if (ret < 0)
  46. goto done;
  47. if (!(ret & SI7005_STATUS_NRDY))
  48. break;
  49. }
  50. if (tries < 0) {
  51. ret = -EIO;
  52. goto done;
  53. }
  54. ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);
  55. done:
  56. mutex_unlock(&data->lock);
  57. return ret;
  58. }
  59. static int si7005_read_raw(struct iio_dev *indio_dev,
  60. struct iio_chan_spec const *chan, int *val,
  61. int *val2, long mask)
  62. {
  63. struct si7005_data *data = iio_priv(indio_dev);
  64. int ret;
  65. switch (mask) {
  66. case IIO_CHAN_INFO_RAW:
  67. ret = si7005_read_measurement(data, chan->type == IIO_TEMP);
  68. if (ret < 0)
  69. return ret;
  70. *val = ret;
  71. return IIO_VAL_INT;
  72. case IIO_CHAN_INFO_SCALE:
  73. if (chan->type == IIO_TEMP) {
  74. *val = 7;
  75. *val2 = 812500;
  76. } else {
  77. *val = 3;
  78. *val2 = 906250;
  79. }
  80. return IIO_VAL_INT_PLUS_MICRO;
  81. case IIO_CHAN_INFO_OFFSET:
  82. if (chan->type == IIO_TEMP)
  83. *val = -50 * 32 * 4;
  84. else
  85. *val = -24 * 16 * 16;
  86. return IIO_VAL_INT;
  87. default:
  88. break;
  89. }
  90. return -EINVAL;
  91. }
  92. static const struct iio_chan_spec si7005_channels[] = {
  93. {
  94. .type = IIO_HUMIDITYRELATIVE,
  95. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  96. BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  97. },
  98. {
  99. .type = IIO_TEMP,
  100. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  101. BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  102. }
  103. };
  104. static const struct iio_info si7005_info = {
  105. .read_raw = si7005_read_raw,
  106. };
  107. static int si7005_probe(struct i2c_client *client,
  108. const struct i2c_device_id *id)
  109. {
  110. struct iio_dev *indio_dev;
  111. struct si7005_data *data;
  112. int ret;
  113. if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
  114. return -EOPNOTSUPP;
  115. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  116. if (!indio_dev)
  117. return -ENOMEM;
  118. data = iio_priv(indio_dev);
  119. i2c_set_clientdata(client, indio_dev);
  120. data->client = client;
  121. mutex_init(&data->lock);
  122. indio_dev->name = dev_name(&client->dev);
  123. indio_dev->modes = INDIO_DIRECT_MODE;
  124. indio_dev->info = &si7005_info;
  125. indio_dev->channels = si7005_channels;
  126. indio_dev->num_channels = ARRAY_SIZE(si7005_channels);
  127. ret = i2c_smbus_read_byte_data(client, SI7005_ID);
  128. if (ret < 0)
  129. return ret;
  130. if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)
  131. return -ENODEV;
  132. ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);
  133. if (ret < 0)
  134. return ret;
  135. data->config = ret;
  136. return devm_iio_device_register(&client->dev, indio_dev);
  137. }
  138. static const struct i2c_device_id si7005_id[] = {
  139. { "si7005", 0 },
  140. { "th02", 0 },
  141. { }
  142. };
  143. MODULE_DEVICE_TABLE(i2c, si7005_id);
  144. static struct i2c_driver si7005_driver = {
  145. .driver = {
  146. .name = "si7005",
  147. },
  148. .probe = si7005_probe,
  149. .id_table = si7005_id,
  150. };
  151. module_i2c_driver(si7005_driver);
  152. MODULE_AUTHOR("Peter Meerwald <[email protected]>");
  153. MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");
  154. MODULE_LICENSE("GPL");