sht4x.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) Linumiz 2021
  4. *
  5. * sht4x.c - Linux hwmon driver for SHT4x Temperature and Humidity sensor
  6. *
  7. * Author: Navin Sankar Velliangiri <[email protected]>
  8. */
  9. #include <linux/crc8.h>
  10. #include <linux/delay.h>
  11. #include <linux/hwmon.h>
  12. #include <linux/i2c.h>
  13. #include <linux/jiffies.h>
  14. #include <linux/module.h>
  15. /*
  16. * Poll intervals (in milliseconds)
  17. */
  18. #define SHT4X_MIN_POLL_INTERVAL 2000
  19. /*
  20. * I2C command delays (in microseconds)
  21. */
  22. #define SHT4X_MEAS_DELAY_HPM 8200 /* see t_MEAS,h in datasheet */
  23. #define SHT4X_DELAY_EXTRA 10000
  24. /*
  25. * Command Bytes
  26. */
  27. #define SHT4X_CMD_MEASURE_HPM 0b11111101
  28. #define SHT4X_CMD_RESET 0b10010100
  29. #define SHT4X_CMD_LEN 1
  30. #define SHT4X_CRC8_LEN 1
  31. #define SHT4X_WORD_LEN 2
  32. #define SHT4X_RESPONSE_LENGTH 6
  33. #define SHT4X_CRC8_POLYNOMIAL 0x31
  34. #define SHT4X_CRC8_INIT 0xff
  35. #define SHT4X_MIN_TEMPERATURE -45000
  36. #define SHT4X_MAX_TEMPERATURE 125000
  37. #define SHT4X_MIN_HUMIDITY 0
  38. #define SHT4X_MAX_HUMIDITY 100000
  39. DECLARE_CRC8_TABLE(sht4x_crc8_table);
  40. /**
  41. * struct sht4x_data - All the data required to operate an SHT4X chip
  42. * @client: the i2c client associated with the SHT4X
  43. * @lock: a mutex that is used to prevent parallel access to the i2c client
  44. * @update_interval: the minimum poll interval
  45. * @last_updated: the previous time that the SHT4X was polled
  46. * @temperature: the latest temperature value received from the SHT4X
  47. * @humidity: the latest humidity value received from the SHT4X
  48. */
  49. struct sht4x_data {
  50. struct i2c_client *client;
  51. struct mutex lock; /* atomic read data updates */
  52. bool valid; /* validity of fields below */
  53. long update_interval; /* in milli-seconds */
  54. long last_updated; /* in jiffies */
  55. s32 temperature;
  56. s32 humidity;
  57. };
  58. /**
  59. * sht4x_read_values() - read and parse the raw data from the SHT4X
  60. * @sht4x_data: the struct sht4x_data to use for the lock
  61. * Return: 0 if successful, -ERRNO if not
  62. */
  63. static int sht4x_read_values(struct sht4x_data *data)
  64. {
  65. int ret = 0;
  66. u16 t_ticks, rh_ticks;
  67. unsigned long next_update;
  68. struct i2c_client *client = data->client;
  69. u8 crc;
  70. u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM};
  71. u8 raw_data[SHT4X_RESPONSE_LENGTH];
  72. mutex_lock(&data->lock);
  73. next_update = data->last_updated +
  74. msecs_to_jiffies(data->update_interval);
  75. if (data->valid && time_before_eq(jiffies, next_update))
  76. goto unlock;
  77. ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
  78. if (ret < 0)
  79. goto unlock;
  80. usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA);
  81. ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH);
  82. if (ret != SHT4X_RESPONSE_LENGTH) {
  83. if (ret >= 0)
  84. ret = -ENODATA;
  85. goto unlock;
  86. }
  87. t_ticks = raw_data[0] << 8 | raw_data[1];
  88. rh_ticks = raw_data[3] << 8 | raw_data[4];
  89. crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
  90. if (crc != raw_data[2]) {
  91. dev_err(&client->dev, "data integrity check failed\n");
  92. ret = -EIO;
  93. goto unlock;
  94. }
  95. crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
  96. if (crc != raw_data[5]) {
  97. dev_err(&client->dev, "data integrity check failed\n");
  98. ret = -EIO;
  99. goto unlock;
  100. }
  101. data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000;
  102. data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000;
  103. data->last_updated = jiffies;
  104. data->valid = true;
  105. ret = 0;
  106. unlock:
  107. mutex_unlock(&data->lock);
  108. return ret;
  109. }
  110. static ssize_t sht4x_interval_write(struct sht4x_data *data, long val)
  111. {
  112. data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, INT_MAX);
  113. return 0;
  114. }
  115. /* sht4x_interval_read() - read the minimum poll interval in milliseconds */
  116. static size_t sht4x_interval_read(struct sht4x_data *data, long *val)
  117. {
  118. *val = data->update_interval;
  119. return 0;
  120. }
  121. /* sht4x_temperature1_read() - read the temperature in millidegrees */
  122. static int sht4x_temperature1_read(struct sht4x_data *data, long *val)
  123. {
  124. int ret;
  125. ret = sht4x_read_values(data);
  126. if (ret < 0)
  127. return ret;
  128. *val = data->temperature;
  129. return 0;
  130. }
  131. /* sht4x_humidity1_read() - read a relative humidity in millipercent */
  132. static int sht4x_humidity1_read(struct sht4x_data *data, long *val)
  133. {
  134. int ret;
  135. ret = sht4x_read_values(data);
  136. if (ret < 0)
  137. return ret;
  138. *val = data->humidity;
  139. return 0;
  140. }
  141. static umode_t sht4x_hwmon_visible(const void *data,
  142. enum hwmon_sensor_types type,
  143. u32 attr, int channel)
  144. {
  145. switch (type) {
  146. case hwmon_temp:
  147. case hwmon_humidity:
  148. return 0444;
  149. case hwmon_chip:
  150. return 0644;
  151. default:
  152. return 0;
  153. }
  154. }
  155. static int sht4x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  156. u32 attr, int channel, long *val)
  157. {
  158. struct sht4x_data *data = dev_get_drvdata(dev);
  159. switch (type) {
  160. case hwmon_temp:
  161. return sht4x_temperature1_read(data, val);
  162. case hwmon_humidity:
  163. return sht4x_humidity1_read(data, val);
  164. case hwmon_chip:
  165. return sht4x_interval_read(data, val);
  166. default:
  167. return -EOPNOTSUPP;
  168. }
  169. }
  170. static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
  171. u32 attr, int channel, long val)
  172. {
  173. struct sht4x_data *data = dev_get_drvdata(dev);
  174. switch (type) {
  175. case hwmon_chip:
  176. return sht4x_interval_write(data, val);
  177. default:
  178. return -EOPNOTSUPP;
  179. }
  180. }
  181. static const struct hwmon_channel_info *sht4x_info[] = {
  182. HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
  183. HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
  184. HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
  185. NULL,
  186. };
  187. static const struct hwmon_ops sht4x_hwmon_ops = {
  188. .is_visible = sht4x_hwmon_visible,
  189. .read = sht4x_hwmon_read,
  190. .write = sht4x_hwmon_write,
  191. };
  192. static const struct hwmon_chip_info sht4x_chip_info = {
  193. .ops = &sht4x_hwmon_ops,
  194. .info = sht4x_info,
  195. };
  196. static int sht4x_probe(struct i2c_client *client,
  197. const struct i2c_device_id *sht4x_id)
  198. {
  199. struct device *device = &client->dev;
  200. struct device *hwmon_dev;
  201. struct sht4x_data *data;
  202. u8 cmd[] = {SHT4X_CMD_RESET};
  203. int ret;
  204. /*
  205. * we require full i2c support since the sht4x uses multi-byte read and
  206. * writes as well as multi-byte commands which are not supported by
  207. * the smbus protocol
  208. */
  209. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  210. return -EOPNOTSUPP;
  211. data = devm_kzalloc(device, sizeof(*data), GFP_KERNEL);
  212. if (!data)
  213. return -ENOMEM;
  214. data->update_interval = SHT4X_MIN_POLL_INTERVAL;
  215. data->client = client;
  216. mutex_init(&data->lock);
  217. crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL);
  218. ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
  219. if (ret < 0)
  220. return ret;
  221. if (ret != SHT4X_CMD_LEN)
  222. return -EIO;
  223. hwmon_dev = devm_hwmon_device_register_with_info(device,
  224. client->name,
  225. data,
  226. &sht4x_chip_info,
  227. NULL);
  228. return PTR_ERR_OR_ZERO(hwmon_dev);
  229. }
  230. static const struct i2c_device_id sht4x_id[] = {
  231. { "sht4x", 0 },
  232. { },
  233. };
  234. MODULE_DEVICE_TABLE(i2c, sht4x_id);
  235. static const struct of_device_id sht4x_of_match[] = {
  236. { .compatible = "sensirion,sht4x" },
  237. { }
  238. };
  239. MODULE_DEVICE_TABLE(of, sht4x_of_match);
  240. static struct i2c_driver sht4x_driver = {
  241. .driver = {
  242. .name = "sht4x",
  243. .of_match_table = sht4x_of_match,
  244. },
  245. .probe = sht4x_probe,
  246. .id_table = sht4x_id,
  247. };
  248. module_i2c_driver(sht4x_driver);
  249. MODULE_AUTHOR("Navin Sankar Velliangiri <[email protected]>");
  250. MODULE_DESCRIPTION("Sensirion SHT4x humidity and temperature sensor driver");
  251. MODULE_LICENSE("GPL v2");