max30208.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
  4. *
  5. * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy
  6. * (7-bit I2C slave address (0x50 - 0x53))
  7. */
  8. #include <linux/bitops.h>
  9. #include <linux/delay.h>
  10. #include <linux/iio/iio.h>
  11. #include <linux/i2c.h>
  12. #include <linux/module.h>
  13. #include <linux/types.h>
  14. #define MAX30208_STATUS 0x00
  15. #define MAX30208_STATUS_TEMP_RDY BIT(0)
  16. #define MAX30208_INT_ENABLE 0x01
  17. #define MAX30208_INT_ENABLE_TEMP_RDY BIT(0)
  18. #define MAX30208_FIFO_OVF_CNTR 0x06
  19. #define MAX30208_FIFO_DATA_CNTR 0x07
  20. #define MAX30208_FIFO_DATA 0x08
  21. #define MAX30208_FIFO_CONFIG 0x0a
  22. #define MAX30208_FIFO_CONFIG_RO BIT(1)
  23. #define MAX30208_SYSTEM_CTRL 0x0c
  24. #define MAX30208_SYSTEM_CTRL_RESET 0x01
  25. #define MAX30208_TEMP_SENSOR_SETUP 0x14
  26. #define MAX30208_TEMP_SENSOR_SETUP_CONV BIT(0)
  27. struct max30208_data {
  28. struct i2c_client *client;
  29. struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
  30. };
  31. static const struct iio_chan_spec max30208_channels[] = {
  32. {
  33. .type = IIO_TEMP,
  34. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
  35. },
  36. };
  37. /**
  38. * max30208_request() - Request a reading
  39. * @data: Struct comprising member elements of the device
  40. *
  41. * Requests a reading from the device and waits until the conversion is ready.
  42. */
  43. static int max30208_request(struct max30208_data *data)
  44. {
  45. /*
  46. * Sensor can take up to 500 ms to respond so execute a total of
  47. * 10 retries to give the device sufficient time.
  48. */
  49. int retries = 10;
  50. u8 regval;
  51. int ret;
  52. ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP);
  53. if (ret < 0)
  54. return ret;
  55. regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV;
  56. ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval);
  57. if (ret)
  58. return ret;
  59. while (retries--) {
  60. ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS);
  61. if (ret < 0)
  62. return ret;
  63. if (ret & MAX30208_STATUS_TEMP_RDY)
  64. return 0;
  65. msleep(50);
  66. }
  67. dev_err(&data->client->dev, "Temperature conversion failed\n");
  68. return -ETIMEDOUT;
  69. }
  70. static int max30208_update_temp(struct max30208_data *data)
  71. {
  72. u8 data_count;
  73. int ret;
  74. mutex_lock(&data->lock);
  75. ret = max30208_request(data);
  76. if (ret)
  77. goto unlock;
  78. ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR);
  79. if (ret < 0)
  80. goto unlock;
  81. else if (!ret) {
  82. ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR);
  83. if (ret < 0)
  84. goto unlock;
  85. data_count = ret;
  86. } else
  87. data_count = 1;
  88. while (data_count) {
  89. ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA);
  90. if (ret < 0)
  91. goto unlock;
  92. data_count--;
  93. }
  94. unlock:
  95. mutex_unlock(&data->lock);
  96. return ret;
  97. }
  98. /**
  99. * max30208_config_setup() - Set up FIFO configuration register
  100. * @data: Struct comprising member elements of the device
  101. *
  102. * Sets the rollover bit to '1' to enable overwriting FIFO during overflow.
  103. */
  104. static int max30208_config_setup(struct max30208_data *data)
  105. {
  106. u8 regval;
  107. int ret;
  108. ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG);
  109. if (ret < 0)
  110. return ret;
  111. regval = ret | MAX30208_FIFO_CONFIG_RO;
  112. ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval);
  113. if (ret)
  114. return ret;
  115. return 0;
  116. }
  117. static int max30208_read(struct iio_dev *indio_dev,
  118. struct iio_chan_spec const *chan,
  119. int *val, int *val2, long mask)
  120. {
  121. struct max30208_data *data = iio_priv(indio_dev);
  122. int ret;
  123. switch (mask) {
  124. case IIO_CHAN_INFO_RAW:
  125. ret = max30208_update_temp(data);
  126. if (ret < 0)
  127. return ret;
  128. *val = sign_extend32(ret, 15);
  129. return IIO_VAL_INT;
  130. case IIO_CHAN_INFO_SCALE:
  131. *val = 5;
  132. return IIO_VAL_INT;
  133. default:
  134. return -EINVAL;
  135. }
  136. }
  137. static const struct iio_info max30208_info = {
  138. .read_raw = max30208_read,
  139. };
  140. static int max30208_probe(struct i2c_client *i2c)
  141. {
  142. struct device *dev = &i2c->dev;
  143. struct max30208_data *data;
  144. struct iio_dev *indio_dev;
  145. int ret;
  146. indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
  147. if (!indio_dev)
  148. return -ENOMEM;
  149. data = iio_priv(indio_dev);
  150. data->client = i2c;
  151. mutex_init(&data->lock);
  152. indio_dev->name = "max30208";
  153. indio_dev->channels = max30208_channels;
  154. indio_dev->num_channels = ARRAY_SIZE(max30208_channels);
  155. indio_dev->info = &max30208_info;
  156. indio_dev->modes = INDIO_DIRECT_MODE;
  157. ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL,
  158. MAX30208_SYSTEM_CTRL_RESET);
  159. if (ret) {
  160. dev_err(dev, "Failure in performing reset\n");
  161. return ret;
  162. }
  163. msleep(50);
  164. ret = max30208_config_setup(data);
  165. if (ret)
  166. return ret;
  167. ret = devm_iio_device_register(dev, indio_dev);
  168. if (ret) {
  169. dev_err(dev, "Failed to register IIO device\n");
  170. return ret;
  171. }
  172. return 0;
  173. }
  174. static const struct i2c_device_id max30208_id_table[] = {
  175. { "max30208" },
  176. { }
  177. };
  178. MODULE_DEVICE_TABLE(i2c, max30208_id_table);
  179. static const struct acpi_device_id max30208_acpi_match[] = {
  180. { "MAX30208" },
  181. { }
  182. };
  183. MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
  184. static const struct of_device_id max30208_of_match[] = {
  185. { .compatible = "maxim,max30208" },
  186. { }
  187. };
  188. MODULE_DEVICE_TABLE(of, max30208_of_match);
  189. static struct i2c_driver max30208_driver = {
  190. .driver = {
  191. .name = "max30208",
  192. .of_match_table = max30208_of_match,
  193. .acpi_match_table = max30208_acpi_match,
  194. },
  195. .probe = max30208_probe,
  196. .id_table = max30208_id_table,
  197. };
  198. module_i2c_driver(max30208_driver);
  199. MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
  200. MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
  201. MODULE_LICENSE("GPL");