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