tsys01.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
  3. *
  4. * Copyright (c) 2015 Measurement-Specialties
  5. *
  6. * Licensed under the GPL-2.
  7. *
  8. * Datasheet:
  9. * http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
  10. */
  11. #include <linux/iio/iio.h>
  12. #include <linux/iio/sysfs.h>
  13. #include <linux/device.h>
  14. #include <linux/mutex.h>
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/kernel.h>
  18. #include <linux/stat.h>
  19. #include "../common/ms_sensors/ms_sensors_i2c.h"
  20. /* TSYS01 Commands */
  21. #define TSYS01_RESET 0x1E
  22. #define TSYS01_CONVERSION_START 0x48
  23. #define TSYS01_ADC_READ 0x00
  24. #define TSYS01_PROM_READ 0xA0
  25. #define TSYS01_PROM_WORDS_NB 8
  26. struct tsys01_dev {
  27. void *client;
  28. struct mutex lock; /* lock during conversion */
  29. int (*reset)(void *cli, u8 cmd, unsigned int delay);
  30. int (*convert_and_read)(void *cli, u8 conv, u8 rd,
  31. unsigned int delay, u32 *adc);
  32. int (*read_prom_word)(void *cli, int cmd, u16 *word);
  33. u16 prom[TSYS01_PROM_WORDS_NB];
  34. };
  35. /* Multiplication coefficients for temperature computation */
  36. static const int coeff_mul[] = { -1500000, 1000000, -2000000,
  37. 4000000, -2000000 };
  38. static int tsys01_read_temperature(struct iio_dev *indio_dev,
  39. s32 *temperature)
  40. {
  41. int ret, i;
  42. u32 adc;
  43. s64 temp = 0;
  44. struct tsys01_dev *dev_data = iio_priv(indio_dev);
  45. mutex_lock(&dev_data->lock);
  46. ret = dev_data->convert_and_read(dev_data->client,
  47. TSYS01_CONVERSION_START,
  48. TSYS01_ADC_READ, 9000, &adc);
  49. mutex_unlock(&dev_data->lock);
  50. if (ret)
  51. return ret;
  52. adc >>= 8;
  53. /* Temperature algorithm */
  54. for (i = 4; i > 0; i--) {
  55. temp += coeff_mul[i] *
  56. (s64)dev_data->prom[5 - i];
  57. temp *= (s64)adc;
  58. temp = div64_s64(temp, 100000);
  59. }
  60. temp *= 10;
  61. temp += coeff_mul[0] * (s64)dev_data->prom[5];
  62. temp = div64_s64(temp, 100000);
  63. *temperature = temp;
  64. return 0;
  65. }
  66. static int tsys01_read_raw(struct iio_dev *indio_dev,
  67. struct iio_chan_spec const *channel, int *val,
  68. int *val2, long mask)
  69. {
  70. int ret;
  71. s32 temperature;
  72. switch (mask) {
  73. case IIO_CHAN_INFO_PROCESSED:
  74. switch (channel->type) {
  75. case IIO_TEMP: /* in milli °C */
  76. ret = tsys01_read_temperature(indio_dev, &temperature);
  77. if (ret)
  78. return ret;
  79. *val = temperature;
  80. return IIO_VAL_INT;
  81. default:
  82. return -EINVAL;
  83. }
  84. default:
  85. return -EINVAL;
  86. }
  87. }
  88. static const struct iio_chan_spec tsys01_channels[] = {
  89. {
  90. .type = IIO_TEMP,
  91. .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
  92. }
  93. };
  94. static const struct iio_info tsys01_info = {
  95. .read_raw = tsys01_read_raw,
  96. };
  97. static bool tsys01_crc_valid(u16 *n_prom)
  98. {
  99. u8 cnt;
  100. u8 sum = 0;
  101. for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
  102. sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
  103. return (sum == 0);
  104. }
  105. static int tsys01_read_prom(struct iio_dev *indio_dev)
  106. {
  107. int i, ret;
  108. struct tsys01_dev *dev_data = iio_priv(indio_dev);
  109. char buf[7 * TSYS01_PROM_WORDS_NB + 1];
  110. char *ptr = buf;
  111. for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
  112. ret = dev_data->read_prom_word(dev_data->client,
  113. TSYS01_PROM_READ + (i << 1),
  114. &dev_data->prom[i]);
  115. if (ret)
  116. return ret;
  117. ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
  118. ptr += ret;
  119. }
  120. if (!tsys01_crc_valid(dev_data->prom)) {
  121. dev_err(&indio_dev->dev, "prom crc check error\n");
  122. return -ENODEV;
  123. }
  124. *ptr = 0;
  125. dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
  126. return 0;
  127. }
  128. static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
  129. {
  130. int ret;
  131. struct tsys01_dev *dev_data = iio_priv(indio_dev);
  132. mutex_init(&dev_data->lock);
  133. indio_dev->info = &tsys01_info;
  134. indio_dev->name = dev->driver->name;
  135. indio_dev->dev.parent = dev;
  136. indio_dev->modes = INDIO_DIRECT_MODE;
  137. indio_dev->channels = tsys01_channels;
  138. indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
  139. ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
  140. if (ret)
  141. return ret;
  142. ret = tsys01_read_prom(indio_dev);
  143. if (ret)
  144. return ret;
  145. return devm_iio_device_register(dev, indio_dev);
  146. }
  147. static int tsys01_i2c_probe(struct i2c_client *client,
  148. const struct i2c_device_id *id)
  149. {
  150. struct tsys01_dev *dev_data;
  151. struct iio_dev *indio_dev;
  152. if (!i2c_check_functionality(client->adapter,
  153. I2C_FUNC_SMBUS_WORD_DATA |
  154. I2C_FUNC_SMBUS_WRITE_BYTE |
  155. I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
  156. dev_err(&client->dev,
  157. "Adapter does not support some i2c transaction\n");
  158. return -EOPNOTSUPP;
  159. }
  160. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
  161. if (!indio_dev)
  162. return -ENOMEM;
  163. dev_data = iio_priv(indio_dev);
  164. dev_data->client = client;
  165. dev_data->reset = ms_sensors_reset;
  166. dev_data->read_prom_word = ms_sensors_read_prom_word;
  167. dev_data->convert_and_read = ms_sensors_convert_and_read;
  168. i2c_set_clientdata(client, indio_dev);
  169. return tsys01_probe(indio_dev, &client->dev);
  170. }
  171. static const struct i2c_device_id tsys01_id[] = {
  172. {"tsys01", 0},
  173. {}
  174. };
  175. MODULE_DEVICE_TABLE(i2c, tsys01_id);
  176. static const struct of_device_id tsys01_of_match[] = {
  177. { .compatible = "meas,tsys01", },
  178. { },
  179. };
  180. MODULE_DEVICE_TABLE(of, tsys01_of_match);
  181. static struct i2c_driver tsys01_driver = {
  182. .probe = tsys01_i2c_probe,
  183. .id_table = tsys01_id,
  184. .driver = {
  185. .name = "tsys01",
  186. .of_match_table = of_match_ptr(tsys01_of_match),
  187. },
  188. };
  189. module_i2c_driver(tsys01_driver);
  190. MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
  191. MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
  192. MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
  193. MODULE_LICENSE("GPL v2");