si7005.c 4.2 KB

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