sps30_i2c.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Sensirion SPS30 particulate matter sensor i2c driver
  4. *
  5. * Copyright (c) 2020 Tomasz Duszynski <[email protected]>
  6. *
  7. * I2C slave address: 0x69
  8. */
  9. #include <asm/unaligned.h>
  10. #include <linux/crc8.h>
  11. #include <linux/delay.h>
  12. #include <linux/device.h>
  13. #include <linux/errno.h>
  14. #include <linux/i2c.h>
  15. #include <linux/mod_devicetable.h>
  16. #include <linux/module.h>
  17. #include <linux/types.h>
  18. #include "sps30.h"
  19. #define SPS30_I2C_CRC8_POLYNOMIAL 0x31
  20. /* max number of bytes needed to store PM measurements or serial string */
  21. #define SPS30_I2C_MAX_BUF_SIZE 48
  22. DECLARE_CRC8_TABLE(sps30_i2c_crc8_table);
  23. #define SPS30_I2C_START_MEAS 0x0010
  24. #define SPS30_I2C_STOP_MEAS 0x0104
  25. #define SPS30_I2C_READ_MEAS 0x0300
  26. #define SPS30_I2C_MEAS_READY 0x0202
  27. #define SPS30_I2C_RESET 0xd304
  28. #define SPS30_I2C_CLEAN_FAN 0x5607
  29. #define SPS30_I2C_PERIOD 0x8004
  30. #define SPS30_I2C_READ_SERIAL 0xd033
  31. #define SPS30_I2C_READ_VERSION 0xd100
  32. static int sps30_i2c_xfer(struct sps30_state *state, unsigned char *txbuf, size_t txsize,
  33. unsigned char *rxbuf, size_t rxsize)
  34. {
  35. struct i2c_client *client = to_i2c_client(state->dev);
  36. int ret;
  37. /*
  38. * Sensor does not support repeated start so instead of
  39. * sending two i2c messages in a row we just send one by one.
  40. */
  41. ret = i2c_master_send(client, txbuf, txsize);
  42. if (ret < 0)
  43. return ret;
  44. if (ret != txsize)
  45. return -EIO;
  46. if (!rxsize)
  47. return 0;
  48. ret = i2c_master_recv(client, rxbuf, rxsize);
  49. if (ret < 0)
  50. return ret;
  51. if (ret != rxsize)
  52. return -EIO;
  53. return 0;
  54. }
  55. static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size_t arg_size,
  56. void *rsp, size_t rsp_size)
  57. {
  58. /*
  59. * Internally sensor stores measurements in a following manner:
  60. *
  61. * PM1: upper two bytes, crc8, lower two bytes, crc8
  62. * PM2P5: upper two bytes, crc8, lower two bytes, crc8
  63. * PM4: upper two bytes, crc8, lower two bytes, crc8
  64. * PM10: upper two bytes, crc8, lower two bytes, crc8
  65. *
  66. * What follows next are number concentration measurements and
  67. * typical particle size measurement which we omit.
  68. */
  69. unsigned char buf[SPS30_I2C_MAX_BUF_SIZE];
  70. unsigned char *tmp;
  71. unsigned char crc;
  72. size_t i;
  73. int ret;
  74. put_unaligned_be16(cmd, buf);
  75. i = 2;
  76. if (rsp) {
  77. /* each two bytes are followed by a crc8 */
  78. rsp_size += rsp_size / 2;
  79. } else {
  80. tmp = arg;
  81. while (arg_size) {
  82. buf[i] = *tmp++;
  83. buf[i + 1] = *tmp++;
  84. buf[i + 2] = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
  85. arg_size -= 2;
  86. i += 3;
  87. }
  88. }
  89. ret = sps30_i2c_xfer(state, buf, i, buf, rsp_size);
  90. if (ret)
  91. return ret;
  92. /* validate received data and strip off crc bytes */
  93. tmp = rsp;
  94. for (i = 0; i < rsp_size; i += 3) {
  95. crc = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
  96. if (crc != buf[i + 2]) {
  97. dev_err(state->dev, "data integrity check failed\n");
  98. return -EIO;
  99. }
  100. *tmp++ = buf[i];
  101. *tmp++ = buf[i + 1];
  102. }
  103. return 0;
  104. }
  105. static int sps30_i2c_start_meas(struct sps30_state *state)
  106. {
  107. /* request BE IEEE754 formatted data */
  108. unsigned char buf[] = { 0x03, 0x00 };
  109. return sps30_i2c_command(state, SPS30_I2C_START_MEAS, buf, sizeof(buf), NULL, 0);
  110. }
  111. static int sps30_i2c_stop_meas(struct sps30_state *state)
  112. {
  113. return sps30_i2c_command(state, SPS30_I2C_STOP_MEAS, NULL, 0, NULL, 0);
  114. }
  115. static int sps30_i2c_reset(struct sps30_state *state)
  116. {
  117. int ret;
  118. ret = sps30_i2c_command(state, SPS30_I2C_RESET, NULL, 0, NULL, 0);
  119. msleep(500);
  120. /*
  121. * Power-on-reset causes sensor to produce some glitch on i2c bus and
  122. * some controllers end up in error state. Recover simply by placing
  123. * some data on the bus, for example STOP_MEAS command, which
  124. * is NOP in this case.
  125. */
  126. sps30_i2c_stop_meas(state);
  127. return ret;
  128. }
  129. static bool sps30_i2c_meas_ready(struct sps30_state *state)
  130. {
  131. unsigned char buf[2];
  132. int ret;
  133. ret = sps30_i2c_command(state, SPS30_I2C_MEAS_READY, NULL, 0, buf, sizeof(buf));
  134. if (ret)
  135. return false;
  136. return buf[1];
  137. }
  138. static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
  139. {
  140. /* measurements are ready within a second */
  141. if (msleep_interruptible(1000))
  142. return -EINTR;
  143. if (!sps30_i2c_meas_ready(state))
  144. return -ETIMEDOUT;
  145. return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num);
  146. }
  147. static int sps30_i2c_clean_fan(struct sps30_state *state)
  148. {
  149. return sps30_i2c_command(state, SPS30_I2C_CLEAN_FAN, NULL, 0, NULL, 0);
  150. }
  151. static int sps30_i2c_read_cleaning_period(struct sps30_state *state, __be32 *period)
  152. {
  153. return sps30_i2c_command(state, SPS30_I2C_PERIOD, NULL, 0, period, sizeof(*period));
  154. }
  155. static int sps30_i2c_write_cleaning_period(struct sps30_state *state, __be32 period)
  156. {
  157. return sps30_i2c_command(state, SPS30_I2C_PERIOD, &period, sizeof(period), NULL, 0);
  158. }
  159. static int sps30_i2c_show_info(struct sps30_state *state)
  160. {
  161. /* extra nul just in case */
  162. unsigned char buf[32 + 1] = { 0x00 };
  163. int ret;
  164. ret = sps30_i2c_command(state, SPS30_I2C_READ_SERIAL, NULL, 0, buf, sizeof(buf) - 1);
  165. if (ret)
  166. return ret;
  167. dev_info(state->dev, "serial number: %s\n", buf);
  168. ret = sps30_i2c_command(state, SPS30_I2C_READ_VERSION, NULL, 0, buf, 2);
  169. if (ret)
  170. return ret;
  171. dev_info(state->dev, "fw version: %u.%u\n", buf[0], buf[1]);
  172. return 0;
  173. }
  174. static const struct sps30_ops sps30_i2c_ops = {
  175. .start_meas = sps30_i2c_start_meas,
  176. .stop_meas = sps30_i2c_stop_meas,
  177. .read_meas = sps30_i2c_read_meas,
  178. .reset = sps30_i2c_reset,
  179. .clean_fan = sps30_i2c_clean_fan,
  180. .read_cleaning_period = sps30_i2c_read_cleaning_period,
  181. .write_cleaning_period = sps30_i2c_write_cleaning_period,
  182. .show_info = sps30_i2c_show_info,
  183. };
  184. static int sps30_i2c_probe(struct i2c_client *client)
  185. {
  186. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  187. return -EOPNOTSUPP;
  188. crc8_populate_msb(sps30_i2c_crc8_table, SPS30_I2C_CRC8_POLYNOMIAL);
  189. return sps30_probe(&client->dev, client->name, NULL, &sps30_i2c_ops);
  190. }
  191. static const struct i2c_device_id sps30_i2c_id[] = {
  192. { "sps30" },
  193. { }
  194. };
  195. MODULE_DEVICE_TABLE(i2c, sps30_i2c_id);
  196. static const struct of_device_id sps30_i2c_of_match[] = {
  197. { .compatible = "sensirion,sps30" },
  198. { }
  199. };
  200. MODULE_DEVICE_TABLE(of, sps30_i2c_of_match);
  201. static struct i2c_driver sps30_i2c_driver = {
  202. .driver = {
  203. .name = KBUILD_MODNAME,
  204. .of_match_table = sps30_i2c_of_match,
  205. },
  206. .id_table = sps30_i2c_id,
  207. .probe_new = sps30_i2c_probe,
  208. };
  209. module_i2c_driver(sps30_i2c_driver);
  210. MODULE_AUTHOR("Tomasz Duszynski <[email protected]>");
  211. MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver");
  212. MODULE_LICENSE("GPL v2");
  213. MODULE_IMPORT_NS(IIO_SPS30);