1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Sensirion SPS30 particulate matter sensor serial driver
4 *
5 * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
6 */
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>
16
17#include "sps30.h"
18
19#define SPS30_SERIAL_DEV_NAME "sps30"
20
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
25
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
33
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
42
43struct sps30_serial_priv {
44 struct completion new_frame;
45 unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
46 size_t num;
47 bool escaped;
48 bool done;
49};
50
51static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size)
52{
53 struct serdev_device *serdev = to_serdev_device(d: state->dev);
54 struct sps30_serial_priv *priv = state->priv;
55 int ret;
56
57 priv->num = 0;
58 priv->escaped = false;
59 priv->done = false;
60
61 ret = serdev_device_write(serdev, buf, size, SPS30_SERIAL_TIMEOUT);
62 if (ret < 0)
63 return ret;
64 if (ret != size)
65 return -EIO;
66
67 ret = wait_for_completion_interruptible_timeout(x: &priv->new_frame, SPS30_SERIAL_TIMEOUT);
68 if (ret < 0)
69 return ret;
70 if (!ret)
71 return -ETIMEDOUT;
72
73 return 0;
74}
75
76static const struct {
77 u8 byte;
78 u8 byte2;
79} sps30_serial_bytes[] = {
80 { 0x11, 0x31 },
81 { 0x13, 0x33 },
82 { 0x7e, 0x5e },
83 { 0x7d, 0x5d },
84};
85
86static int sps30_serial_put_byte(u8 *buf, u8 byte)
87{
88 int i;
89
90 for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
91 if (sps30_serial_bytes[i].byte != byte)
92 continue;
93
94 buf[0] = SPS30_SERIAL_ESCAPE_CHAR;
95 buf[1] = sps30_serial_bytes[i].byte2;
96
97 return 2;
98 }
99
100 buf[0] = byte;
101
102 return 1;
103}
104
105static u8 sps30_serial_get_byte(bool escaped, u8 byte2)
106{
107 int i;
108
109 if (!escaped)
110 return byte2;
111
112 for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
113 if (sps30_serial_bytes[i].byte2 != byte2)
114 continue;
115
116 return sps30_serial_bytes[i].byte;
117 }
118
119 return 0;
120}
121
122static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t num)
123{
124 unsigned int chksum = 0;
125 size_t i;
126
127 for (i = 0; i < num; i++)
128 chksum += buf[i];
129
130 return ~chksum;
131}
132
133static int sps30_serial_prep_frame(u8 *buf, u8 cmd, const u8 *arg,
134 size_t arg_size)
135{
136 unsigned char chksum;
137 int num = 0;
138 size_t i;
139
140 buf[num++] = SPS30_SERIAL_SOF_EOF;
141 buf[num++] = 0;
142 num += sps30_serial_put_byte(buf: buf + num, byte: cmd);
143 num += sps30_serial_put_byte(buf: buf + num, byte: arg_size);
144
145 for (i = 0; i < arg_size; i++)
146 num += sps30_serial_put_byte(buf: buf + num, byte: arg[i]);
147
148 /* SOF isn't checksummed */
149 chksum = sps30_serial_calc_chksum(buf: buf + 1, num: num - 1);
150 num += sps30_serial_put_byte(buf: buf + num, byte: chksum);
151 buf[num++] = SPS30_SERIAL_SOF_EOF;
152
153 return num;
154}
155
156static bool sps30_serial_frame_valid(struct sps30_state *state, const unsigned char *buf)
157{
158 struct sps30_serial_priv *priv = state->priv;
159 unsigned char chksum;
160
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");
165 return false;
166 }
167
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");
171 return false;
172 }
173
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]);
177 return false;
178 }
179
180 /* SOF, checksum and EOF are not checksummed */
181 chksum = sps30_serial_calc_chksum(buf: priv->buf + 1, num: priv->num - 3);
182 if (priv->buf[priv->num - 2] != chksum) {
183 dev_err(state->dev, "frame integrity check failed\n");
184 return false;
185 }
186
187 return true;
188}
189
190static 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)
192{
193 struct sps30_serial_priv *priv = state->priv;
194 unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
195 int ret, size;
196
197 size = sps30_serial_prep_frame(buf, cmd, arg, arg_size);
198 ret = sps30_serial_xfer(state, buf, size);
199 if (ret)
200 return ret;
201
202 if (!sps30_serial_frame_valid(state, buf))
203 return -EIO;
204
205 if (rsp) {
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);
208 }
209
210 return rsp_size;
211}
212
213static size_t sps30_serial_receive_buf(struct serdev_device *serdev,
214 const u8 *buf, size_t size)
215{
216 struct iio_dev *indio_dev = dev_get_drvdata(dev: &serdev->dev);
217 struct sps30_serial_priv *priv;
218 struct sps30_state *state;
219 size_t i;
220 u8 byte;
221
222 if (!indio_dev)
223 return 0;
224
225 state = iio_priv(indio_dev);
226 priv = state->priv;
227
228 /* just in case device put some unexpected data on the bus */
229 if (priv->done)
230 return size;
231
232 /* wait for the start of frame */
233 if (!priv->num && size && buf[0] != SPS30_SERIAL_SOF_EOF)
234 return 1;
235
236 if (priv->num + size >= ARRAY_SIZE(priv->buf))
237 size = ARRAY_SIZE(priv->buf) - priv->num;
238
239 for (i = 0; i < size; i++) {
240 byte = buf[i];
241 /* remove stuffed bytes on-the-fly */
242 if (byte == SPS30_SERIAL_ESCAPE_CHAR) {
243 priv->escaped = true;
244 continue;
245 }
246
247 byte = sps30_serial_get_byte(escaped: priv->escaped, byte2: byte);
248 if (priv->escaped && !byte)
249 dev_warn(state->dev, "unrecognized escaped char (0x%02x)\n", byte);
250
251 priv->buf[priv->num++] = byte;
252
253 /* EOF received */
254 if (!priv->escaped && byte == SPS30_SERIAL_SOF_EOF) {
255 if (priv->num < SPS30_SERIAL_FRAME_MIN_SIZE)
256 continue;
257
258 priv->done = true;
259 complete(&priv->new_frame);
260 i++;
261 break;
262 }
263
264 priv->escaped = false;
265 }
266
267 return i;
268}
269
270static const struct serdev_device_ops sps30_serial_device_ops = {
271 .receive_buf = sps30_serial_receive_buf,
272 .write_wakeup = serdev_device_write_wakeup,
273};
274
275static int sps30_serial_start_meas(struct sps30_state *state)
276{
277 /* request BE IEEE754 formatted data */
278 unsigned char buf[] = { 0x01, 0x03 };
279
280 return sps30_serial_command(state, SPS30_SERIAL_START_MEAS, arg: buf, arg_size: sizeof(buf), NULL, rsp_size: 0);
281}
282
283static int sps30_serial_stop_meas(struct sps30_state *state)
284{
285 return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, arg_size: 0, NULL, rsp_size: 0);
286}
287
288static int sps30_serial_reset(struct sps30_state *state)
289{
290 int ret;
291
292 ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, arg_size: 0, NULL, rsp_size: 0);
293 msleep(msecs: 500);
294
295 return ret;
296}
297
298static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
299{
300 int ret;
301
302 /* measurements are ready within a second */
303 if (msleep_interruptible(msecs: 1000))
304 return -EINTR;
305
306 ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, arg_size: 0, rsp: meas, rsp_size: num * sizeof(num));
307 if (ret < 0)
308 return ret;
309 /* if measurements aren't ready sensor returns empty frame */
310 if (ret == SPS30_SERIAL_FRAME_MIN_SIZE)
311 return -ETIMEDOUT;
312 if (ret != num * sizeof(*meas))
313 return -EIO;
314
315 return 0;
316}
317
318static int sps30_serial_clean_fan(struct sps30_state *state)
319{
320 return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, arg_size: 0, NULL, rsp_size: 0);
321}
322
323static int sps30_serial_read_cleaning_period(struct sps30_state *state, __be32 *period)
324{
325 unsigned char buf[] = { 0x00 };
326 int ret;
327
328 ret = sps30_serial_command(state, SPS30_SERIAL_PERIOD, arg: buf, arg_size: sizeof(buf),
329 rsp: period, rsp_size: sizeof(*period));
330 if (ret < 0)
331 return ret;
332 if (ret != sizeof(*period))
333 return -EIO;
334
335 return 0;
336}
337
338static int sps30_serial_write_cleaning_period(struct sps30_state *state, __be32 period)
339{
340 unsigned char buf[5] = { 0x00 };
341
342 memcpy(buf + 1, &period, sizeof(period));
343
344 return sps30_serial_command(state, SPS30_SERIAL_PERIOD, arg: buf, arg_size: sizeof(buf), NULL, rsp_size: 0);
345}
346
347static int sps30_serial_show_info(struct sps30_state *state)
348{
349 /*
350 * tell device do return serial number and add extra nul byte just in case
351 * serial number isn't a valid string
352 */
353 unsigned char buf[32 + 1] = { 0x03 };
354 struct device *dev = state->dev;
355 int ret;
356
357 ret = sps30_serial_command(state, SPS30_SERIAL_DEV_INFO, arg: buf, arg_size: 1, rsp: buf, rsp_size: sizeof(buf) - 1);
358 if (ret < 0)
359 return ret;
360 if (ret != sizeof(buf) - 1)
361 return -EIO;
362
363 dev_info(dev, "serial number: %s\n", buf);
364
365 ret = sps30_serial_command(state, SPS30_SERIAL_READ_VERSION, NULL, arg_size: 0, rsp: buf, rsp_size: sizeof(buf) - 1);
366 if (ret < 0)
367 return ret;
368 if (ret < 2)
369 return -EIO;
370
371 dev_info(dev, "fw version: %u.%u\n", buf[0], buf[1]);
372
373 return 0;
374}
375
376static 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,
385};
386
387static int sps30_serial_probe(struct serdev_device *serdev)
388{
389 struct device *dev = &serdev->dev;
390 struct sps30_serial_priv *priv;
391 int ret;
392
393 priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL);
394 if (!priv)
395 return -ENOMEM;
396
397 init_completion(x: &priv->new_frame);
398 serdev_device_set_client_ops(serdev, ops: &sps30_serial_device_ops);
399
400 ret = devm_serdev_device_open(dev, serdev);
401 if (ret)
402 return ret;
403
404 serdev_device_set_baudrate(serdev, 115200);
405 serdev_device_set_flow_control(serdev, false);
406
407 ret = serdev_device_set_parity(serdev, parity: SERDEV_PARITY_NONE);
408 if (ret)
409 return ret;
410
411 return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, ops: &sps30_serial_ops);
412}
413
414static const struct of_device_id sps30_serial_of_match[] = {
415 { .compatible = "sensirion,sps30" },
416 { }
417};
418MODULE_DEVICE_TABLE(of, sps30_serial_of_match);
419
420static struct serdev_device_driver sps30_serial_driver = {
421 .driver = {
422 .name = KBUILD_MODNAME,
423 .of_match_table = sps30_serial_of_match,
424 },
425 .probe = sps30_serial_probe,
426};
427module_serdev_device_driver(sps30_serial_driver);
428
429MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
430MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
431MODULE_LICENSE("GPL v2");
432MODULE_IMPORT_NS(IIO_SPS30);
433

source code of linux/drivers/iio/chemical/sps30_serial.c