1 // SPDX-License-Identifier: GPL-2.0
3 * Sensirion SPS30 particulate matter sensor serial driver
5 * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
7 #include <linux/completion.h>
8 #include <linux/device.h>
9 #include <linux/errno.h>
10 #include <linux/iio/iio.h>
11 #include <linux/minmax.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/serdev.h>
15 #include <linux/types.h>
19 #define SPS30_SERIAL_DEV_NAME "sps30"
21 #define SPS30_SERIAL_SOF_EOF 0x7e
22 #define SPS30_SERIAL_TIMEOUT msecs_to_jiffies(20)
23 #define SPS30_SERIAL_MAX_BUF_SIZE 263
24 #define SPS30_SERIAL_ESCAPE_CHAR 0x7d
26 #define SPS30_SERIAL_FRAME_MIN_SIZE 7
27 #define SPS30_SERIAL_FRAME_ADR_OFFSET 1
28 #define SPS30_SERIAL_FRAME_CMD_OFFSET 2
29 #define SPS30_SERIAL_FRAME_MOSI_LEN_OFFSET 3
30 #define SPS30_SERIAL_FRAME_MISO_STATE_OFFSET 3
31 #define SPS30_SERIAL_FRAME_MISO_LEN_OFFSET 4
32 #define SPS30_SERIAL_FRAME_MISO_DATA_OFFSET 5
34 #define SPS30_SERIAL_START_MEAS 0x00
35 #define SPS30_SERIAL_STOP_MEAS 0x01
36 #define SPS30_SERIAL_READ_MEAS 0x03
37 #define SPS30_SERIAL_RESET 0xd3
38 #define SPS30_SERIAL_CLEAN_FAN 0x56
39 #define SPS30_SERIAL_PERIOD 0x80
40 #define SPS30_SERIAL_DEV_INFO 0xd0
41 #define SPS30_SERIAL_READ_VERSION 0xd1
43 struct sps30_serial_priv {
44 struct completion new_frame;
45 unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
51 static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size)
53 struct serdev_device *serdev = to_serdev_device(state->dev);
54 struct sps30_serial_priv *priv = state->priv;
58 priv->escaped = false;
61 ret = serdev_device_write(serdev, buf, size, SPS30_SERIAL_TIMEOUT);
67 ret = wait_for_completion_interruptible_timeout(&priv->new_frame, SPS30_SERIAL_TIMEOUT);
79 } sps30_serial_bytes[] = {
86 static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte)
90 for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
91 if (sps30_serial_bytes[i].byte != byte)
94 buf[0] = SPS30_SERIAL_ESCAPE_CHAR;
95 buf[1] = sps30_serial_bytes[i].byte2;
105 static char sps30_serial_get_byte(bool escaped, unsigned char byte2)
112 for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
113 if (sps30_serial_bytes[i].byte2 != byte2)
116 return sps30_serial_bytes[i].byte;
122 static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t num)
124 unsigned int chksum = 0;
127 for (i = 0; i < num; i++)
133 static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd,
134 const unsigned char *arg, size_t arg_size)
136 unsigned char chksum;
140 buf[num++] = SPS30_SERIAL_SOF_EOF;
142 num += sps30_serial_put_byte(buf + num, cmd);
143 num += sps30_serial_put_byte(buf + num, arg_size);
145 for (i = 0; i < arg_size; i++)
146 num += sps30_serial_put_byte(buf + num, arg[i]);
148 /* SOF isn't checksummed */
149 chksum = sps30_serial_calc_chksum(buf + 1, num - 1);
150 num += sps30_serial_put_byte(buf + num, chksum);
151 buf[num++] = SPS30_SERIAL_SOF_EOF;
156 static bool sps30_serial_frame_valid(struct sps30_state *state, const unsigned char *buf)
158 struct sps30_serial_priv *priv = state->priv;
159 unsigned char chksum;
161 if ((priv->num < SPS30_SERIAL_FRAME_MIN_SIZE) ||
162 (priv->num != SPS30_SERIAL_FRAME_MIN_SIZE +
163 priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET])) {
164 dev_err(state->dev, "frame has invalid number of bytes\n");
168 if ((priv->buf[SPS30_SERIAL_FRAME_ADR_OFFSET] != buf[SPS30_SERIAL_FRAME_ADR_OFFSET]) ||
169 (priv->buf[SPS30_SERIAL_FRAME_CMD_OFFSET] != buf[SPS30_SERIAL_FRAME_CMD_OFFSET])) {
170 dev_err(state->dev, "frame has wrong ADR and CMD bytes\n");
174 if (priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]) {
175 dev_err(state->dev, "frame with non-zero state received (0x%02x)\n",
176 priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]);
180 /* SOF, checksum and EOF are not checksummed */
181 chksum = sps30_serial_calc_chksum(priv->buf + 1, priv->num - 3);
182 if (priv->buf[priv->num - 2] != chksum) {
183 dev_err(state->dev, "frame integrity check failed\n");
190 static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
191 const void *arg, size_t arg_size, void *rsp, size_t rsp_size)
193 struct sps30_serial_priv *priv = state->priv;
194 unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
197 size = sps30_serial_prep_frame(buf, cmd, arg, arg_size);
198 ret = sps30_serial_xfer(state, buf, size);
202 if (!sps30_serial_frame_valid(state, buf))
206 rsp_size = min_t(size_t, priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET], rsp_size);
207 memcpy(rsp, &priv->buf[SPS30_SERIAL_FRAME_MISO_DATA_OFFSET], rsp_size);
213 static int sps30_serial_receive_buf(struct serdev_device *serdev,
214 const unsigned char *buf, size_t size)
216 struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
217 struct sps30_serial_priv *priv;
218 struct sps30_state *state;
225 state = iio_priv(indio_dev);
228 /* just in case device put some unexpected data on the bus */
232 /* wait for the start of frame */
233 if (!priv->num && size && buf[0] != SPS30_SERIAL_SOF_EOF)
236 if (priv->num + size >= ARRAY_SIZE(priv->buf))
237 size = ARRAY_SIZE(priv->buf) - priv->num;
239 for (i = 0; i < size; i++) {
241 /* remove stuffed bytes on-the-fly */
242 if (byte == SPS30_SERIAL_ESCAPE_CHAR) {
243 priv->escaped = true;
247 byte = sps30_serial_get_byte(priv->escaped, byte);
248 if (priv->escaped && !byte)
249 dev_warn(state->dev, "unrecognized escaped char (0x%02x)\n", byte);
251 priv->buf[priv->num++] = byte;
254 if (!priv->escaped && byte == SPS30_SERIAL_SOF_EOF) {
255 if (priv->num < SPS30_SERIAL_FRAME_MIN_SIZE)
259 complete(&priv->new_frame);
264 priv->escaped = false;
270 static const struct serdev_device_ops sps30_serial_device_ops = {
271 .receive_buf = sps30_serial_receive_buf,
272 .write_wakeup = serdev_device_write_wakeup,
275 static int sps30_serial_start_meas(struct sps30_state *state)
277 /* request BE IEEE754 formatted data */
278 unsigned char buf[] = { 0x01, 0x03 };
280 return sps30_serial_command(state, SPS30_SERIAL_START_MEAS, buf, sizeof(buf), NULL, 0);
283 static int sps30_serial_stop_meas(struct sps30_state *state)
285 return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, 0, NULL, 0);
288 static int sps30_serial_reset(struct sps30_state *state)
292 ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, 0, NULL, 0);
298 static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
302 /* measurements are ready within a second */
303 if (msleep_interruptible(1000))
306 ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num));
309 /* if measurements aren't ready sensor returns empty frame */
310 if (ret == SPS30_SERIAL_FRAME_MIN_SIZE)
312 if (ret != num * sizeof(*meas))
318 static int sps30_serial_clean_fan(struct sps30_state *state)
320 return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, 0, NULL, 0);
323 static int sps30_serial_read_cleaning_period(struct sps30_state *state, __be32 *period)
325 unsigned char buf[] = { 0x00 };
328 ret = sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf),
329 period, sizeof(*period));
332 if (ret != sizeof(*period))
338 static int sps30_serial_write_cleaning_period(struct sps30_state *state, __be32 period)
340 unsigned char buf[5] = { 0x00 };
342 memcpy(buf + 1, &period, sizeof(period));
344 return sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf), NULL, 0);
347 static int sps30_serial_show_info(struct sps30_state *state)
350 * tell device do return serial number and add extra nul byte just in case
351 * serial number isn't a valid string
353 unsigned char buf[32 + 1] = { 0x03 };
354 struct device *dev = state->dev;
357 ret = sps30_serial_command(state, SPS30_SERIAL_DEV_INFO, buf, 1, buf, sizeof(buf) - 1);
360 if (ret != sizeof(buf) - 1)
363 dev_info(dev, "serial number: %s\n", buf);
365 ret = sps30_serial_command(state, SPS30_SERIAL_READ_VERSION, NULL, 0, buf, sizeof(buf) - 1);
371 dev_info(dev, "fw version: %u.%u\n", buf[0], buf[1]);
376 static const struct sps30_ops sps30_serial_ops = {
377 .start_meas = sps30_serial_start_meas,
378 .stop_meas = sps30_serial_stop_meas,
379 .read_meas = sps30_serial_read_meas,
380 .reset = sps30_serial_reset,
381 .clean_fan = sps30_serial_clean_fan,
382 .read_cleaning_period = sps30_serial_read_cleaning_period,
383 .write_cleaning_period = sps30_serial_write_cleaning_period,
384 .show_info = sps30_serial_show_info,
387 static int sps30_serial_probe(struct serdev_device *serdev)
389 struct device *dev = &serdev->dev;
390 struct sps30_serial_priv *priv;
393 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
397 init_completion(&priv->new_frame);
398 serdev_device_set_client_ops(serdev, &sps30_serial_device_ops);
400 ret = devm_serdev_device_open(dev, serdev);
404 serdev_device_set_baudrate(serdev, 115200);
405 serdev_device_set_flow_control(serdev, false);
407 ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
411 return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, &sps30_serial_ops);
414 static const struct of_device_id sps30_serial_of_match[] = {
415 { .compatible = "sensirion,sps30" },
418 MODULE_DEVICE_TABLE(of, sps30_serial_of_match);
420 static struct serdev_device_driver sps30_serial_driver = {
422 .name = KBUILD_MODNAME,
423 .of_match_table = sps30_serial_of_match,
425 .probe = sps30_serial_probe,
427 module_serdev_device_driver(sps30_serial_driver);
429 MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
430 MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
431 MODULE_LICENSE("GPL v2");