scd30_serial.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Sensirion SCD30 carbon dioxide sensor serial driver
  4. *
  5. * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
  6. */
  7. #include <linux/crc16.h>
  8. #include <linux/device.h>
  9. #include <linux/errno.h>
  10. #include <linux/iio/iio.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/mod_devicetable.h>
  13. #include <linux/module.h>
  14. #include <linux/property.h>
  15. #include <linux/serdev.h>
  16. #include <linux/string.h>
  17. #include <linux/types.h>
  18. #include <asm/unaligned.h>
  19. #include "scd30.h"
  20. #define SCD30_SERDEV_ADDR 0x61
  21. #define SCD30_SERDEV_WRITE 0x06
  22. #define SCD30_SERDEV_READ 0x03
  23. #define SCD30_SERDEV_MAX_BUF_SIZE 17
  24. #define SCD30_SERDEV_RX_HEADER_SIZE 3
  25. #define SCD30_SERDEV_CRC_SIZE 2
  26. #define SCD30_SERDEV_TIMEOUT msecs_to_jiffies(200)
  27. struct scd30_serdev_priv {
  28. struct completion meas_ready;
  29. char *buf;
  30. int num_expected;
  31. int num;
  32. };
  33. static u16 scd30_serdev_cmd_lookup_tbl[] = {
  34. [CMD_START_MEAS] = 0x0036,
  35. [CMD_STOP_MEAS] = 0x0037,
  36. [CMD_MEAS_INTERVAL] = 0x0025,
  37. [CMD_MEAS_READY] = 0x0027,
  38. [CMD_READ_MEAS] = 0x0028,
  39. [CMD_ASC] = 0x003a,
  40. [CMD_FRC] = 0x0039,
  41. [CMD_TEMP_OFFSET] = 0x003b,
  42. [CMD_FW_VERSION] = 0x0020,
  43. [CMD_RESET] = 0x0034,
  44. };
  45. static u16 scd30_serdev_calc_crc(const char *buf, int size)
  46. {
  47. return crc16(0xffff, buf, size);
  48. }
  49. static int scd30_serdev_xfer(struct scd30_state *state, char *txbuf, int txsize,
  50. char *rxbuf, int rxsize)
  51. {
  52. struct serdev_device *serdev = to_serdev_device(state->dev);
  53. struct scd30_serdev_priv *priv = state->priv;
  54. int ret;
  55. priv->buf = rxbuf;
  56. priv->num_expected = rxsize;
  57. priv->num = 0;
  58. ret = serdev_device_write(serdev, txbuf, txsize, SCD30_SERDEV_TIMEOUT);
  59. if (ret < 0)
  60. return ret;
  61. if (ret != txsize)
  62. return -EIO;
  63. ret = wait_for_completion_interruptible_timeout(&priv->meas_ready, SCD30_SERDEV_TIMEOUT);
  64. if (ret < 0)
  65. return ret;
  66. if (!ret)
  67. return -ETIMEDOUT;
  68. return 0;
  69. }
  70. static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u16 arg,
  71. void *response, int size)
  72. {
  73. /*
  74. * Communication over serial line is based on modbus protocol (or rather
  75. * its variation called modbus over serial to be precise). Upon
  76. * receiving a request device should reply with response.
  77. *
  78. * Frame below represents a request message. Each field takes
  79. * exactly one byte.
  80. *
  81. * +------+------+-----+-----+-------+-------+-----+-----+
  82. * | dev | op | reg | reg | byte1 | byte0 | crc | crc |
  83. * | addr | code | msb | lsb | | | lsb | msb |
  84. * +------+------+-----+-----+-------+-------+-----+-----+
  85. *
  86. * The message device replies with depends on the 'op code' field from
  87. * the request. In case it was set to SCD30_SERDEV_WRITE sensor should
  88. * reply with unchanged request. Otherwise 'op code' was set to
  89. * SCD30_SERDEV_READ and response looks like the one below. As with
  90. * request, each field takes one byte.
  91. *
  92. * +------+------+--------+-------+-----+-------+-----+-----+
  93. * | dev | op | num of | byte0 | ... | byteN | crc | crc |
  94. * | addr | code | bytes | | | | lsb | msb |
  95. * +------+------+--------+-------+-----+-------+-----+-----+
  96. */
  97. char txbuf[SCD30_SERDEV_MAX_BUF_SIZE] = { SCD30_SERDEV_ADDR },
  98. rxbuf[SCD30_SERDEV_MAX_BUF_SIZE];
  99. int ret, rxsize, txsize = 2;
  100. char *rsp = response;
  101. u16 crc;
  102. put_unaligned_be16(scd30_serdev_cmd_lookup_tbl[cmd], txbuf + txsize);
  103. txsize += 2;
  104. if (rsp) {
  105. txbuf[1] = SCD30_SERDEV_READ;
  106. if (cmd == CMD_READ_MEAS)
  107. /* number of u16 words to read */
  108. put_unaligned_be16(size / 2, txbuf + txsize);
  109. else
  110. put_unaligned_be16(0x0001, txbuf + txsize);
  111. txsize += 2;
  112. crc = scd30_serdev_calc_crc(txbuf, txsize);
  113. put_unaligned_le16(crc, txbuf + txsize);
  114. txsize += 2;
  115. rxsize = SCD30_SERDEV_RX_HEADER_SIZE + size + SCD30_SERDEV_CRC_SIZE;
  116. } else {
  117. if ((cmd == CMD_STOP_MEAS) || (cmd == CMD_RESET))
  118. arg = 0x0001;
  119. txbuf[1] = SCD30_SERDEV_WRITE;
  120. put_unaligned_be16(arg, txbuf + txsize);
  121. txsize += 2;
  122. crc = scd30_serdev_calc_crc(txbuf, txsize);
  123. put_unaligned_le16(crc, txbuf + txsize);
  124. txsize += 2;
  125. rxsize = txsize;
  126. }
  127. ret = scd30_serdev_xfer(state, txbuf, txsize, rxbuf, rxsize);
  128. if (ret)
  129. return ret;
  130. switch (txbuf[1]) {
  131. case SCD30_SERDEV_WRITE:
  132. if (memcmp(txbuf, rxbuf, txsize)) {
  133. dev_err(state->dev, "wrong message received\n");
  134. return -EIO;
  135. }
  136. break;
  137. case SCD30_SERDEV_READ:
  138. if (rxbuf[2] != (rxsize - SCD30_SERDEV_RX_HEADER_SIZE - SCD30_SERDEV_CRC_SIZE)) {
  139. dev_err(state->dev, "received data size does not match header\n");
  140. return -EIO;
  141. }
  142. rxsize -= SCD30_SERDEV_CRC_SIZE;
  143. crc = get_unaligned_le16(rxbuf + rxsize);
  144. if (crc != scd30_serdev_calc_crc(rxbuf, rxsize)) {
  145. dev_err(state->dev, "data integrity check failed\n");
  146. return -EIO;
  147. }
  148. rxsize -= SCD30_SERDEV_RX_HEADER_SIZE;
  149. memcpy(rsp, rxbuf + SCD30_SERDEV_RX_HEADER_SIZE, rxsize);
  150. break;
  151. default:
  152. dev_err(state->dev, "received unknown op code\n");
  153. return -EIO;
  154. }
  155. return 0;
  156. }
  157. static int scd30_serdev_receive_buf(struct serdev_device *serdev,
  158. const unsigned char *buf, size_t size)
  159. {
  160. struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
  161. struct scd30_serdev_priv *priv;
  162. struct scd30_state *state;
  163. int num;
  164. if (!indio_dev)
  165. return 0;
  166. state = iio_priv(indio_dev);
  167. priv = state->priv;
  168. /* just in case sensor puts some unexpected bytes on the bus */
  169. if (!priv->buf)
  170. return 0;
  171. if (priv->num + size >= priv->num_expected)
  172. num = priv->num_expected - priv->num;
  173. else
  174. num = size;
  175. memcpy(priv->buf + priv->num, buf, num);
  176. priv->num += num;
  177. if (priv->num == priv->num_expected) {
  178. priv->buf = NULL;
  179. complete(&priv->meas_ready);
  180. }
  181. return num;
  182. }
  183. static const struct serdev_device_ops scd30_serdev_ops = {
  184. .receive_buf = scd30_serdev_receive_buf,
  185. .write_wakeup = serdev_device_write_wakeup,
  186. };
  187. static int scd30_serdev_probe(struct serdev_device *serdev)
  188. {
  189. struct device *dev = &serdev->dev;
  190. struct scd30_serdev_priv *priv;
  191. int irq, ret;
  192. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  193. if (!priv)
  194. return -ENOMEM;
  195. init_completion(&priv->meas_ready);
  196. serdev_device_set_client_ops(serdev, &scd30_serdev_ops);
  197. ret = devm_serdev_device_open(dev, serdev);
  198. if (ret)
  199. return ret;
  200. serdev_device_set_baudrate(serdev, 19200);
  201. serdev_device_set_flow_control(serdev, false);
  202. ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
  203. if (ret)
  204. return ret;
  205. irq = fwnode_irq_get(dev_fwnode(dev), 0);
  206. return scd30_probe(dev, irq, KBUILD_MODNAME, priv, scd30_serdev_command);
  207. }
  208. static const struct of_device_id scd30_serdev_of_match[] = {
  209. { .compatible = "sensirion,scd30" },
  210. { }
  211. };
  212. MODULE_DEVICE_TABLE(of, scd30_serdev_of_match);
  213. static struct serdev_device_driver scd30_serdev_driver = {
  214. .driver = {
  215. .name = KBUILD_MODNAME,
  216. .of_match_table = scd30_serdev_of_match,
  217. .pm = &scd30_pm_ops,
  218. },
  219. .probe = scd30_serdev_probe,
  220. };
  221. module_serdev_device_driver(scd30_serdev_driver);
  222. MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
  223. MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver");
  224. MODULE_LICENSE("GPL v2");