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
43 struct 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
sps30_serial_xfer(struct sps30_state * state,const unsigned char * buf,size_t size)51 static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size)
52 {
53 struct serdev_device *serdev = to_serdev_device(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(&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
76 static 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
sps30_serial_put_byte(u8 * buf,u8 byte)86 static 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
sps30_serial_get_byte(bool escaped,u8 byte2)105 static 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
sps30_serial_calc_chksum(const unsigned char * buf,size_t num)122 static 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
sps30_serial_prep_frame(u8 * buf,u8 cmd,const u8 * arg,size_t arg_size)133 static 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 + num, cmd);
143 num += sps30_serial_put_byte(buf + num, arg_size);
144
145 for (i = 0; i < arg_size; i++)
146 num += sps30_serial_put_byte(buf + num, arg[i]);
147
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;
152
153 return num;
154 }
155
sps30_serial_frame_valid(struct sps30_state * state,const unsigned char * buf)156 static 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(priv->buf + 1, 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
sps30_serial_command(struct sps30_state * state,unsigned char cmd,const void * arg,size_t arg_size,void * rsp,size_t rsp_size)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)
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
sps30_serial_receive_buf(struct serdev_device * serdev,const u8 * buf,size_t size)213 static 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(&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(priv->escaped, 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
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,
273 };
274
sps30_serial_start_meas(struct sps30_state * state)275 static 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, buf, sizeof(buf), NULL, 0);
281 }
282
sps30_serial_stop_meas(struct sps30_state * state)283 static int sps30_serial_stop_meas(struct sps30_state *state)
284 {
285 return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, 0, NULL, 0);
286 }
287
sps30_serial_reset(struct sps30_state * state)288 static int sps30_serial_reset(struct sps30_state *state)
289 {
290 int ret;
291
292 ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, 0, NULL, 0);
293 msleep(500);
294
295 return ret;
296 }
297
sps30_serial_read_meas(struct sps30_state * state,__be32 * meas,size_t num)298 static 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(1000))
304 return -EINTR;
305
306 ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, 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
sps30_serial_clean_fan(struct sps30_state * state)318 static int sps30_serial_clean_fan(struct sps30_state *state)
319 {
320 return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, 0, NULL, 0);
321 }
322
sps30_serial_read_cleaning_period(struct sps30_state * state,__be32 * period)323 static 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, buf, sizeof(buf),
329 period, sizeof(*period));
330 if (ret < 0)
331 return ret;
332 if (ret != sizeof(*period))
333 return -EIO;
334
335 return 0;
336 }
337
sps30_serial_write_cleaning_period(struct sps30_state * state,__be32 period)338 static 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, buf, sizeof(buf), NULL, 0);
345 }
346
sps30_serial_show_info(struct sps30_state * state)347 static 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, buf, 1, buf, 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, 0, buf, 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
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,
385 };
386
sps30_serial_probe(struct serdev_device * serdev)387 static 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, sizeof(*priv), GFP_KERNEL);
394 if (!priv)
395 return -ENOMEM;
396
397 init_completion(&priv->new_frame);
398 serdev_device_set_client_ops(serdev, &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, SERDEV_PARITY_NONE);
408 if (ret)
409 return ret;
410
411 return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, &sps30_serial_ops);
412 }
413
414 static const struct of_device_id sps30_serial_of_match[] = {
415 { .compatible = "sensirion,sps30" },
416 { }
417 };
418 MODULE_DEVICE_TABLE(of, sps30_serial_of_match);
419
420 static 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 };
427 module_serdev_device_driver(sps30_serial_driver);
428
429 MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
430 MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
431 MODULE_LICENSE("GPL v2");
432 MODULE_IMPORT_NS(IIO_SPS30);
433