Merge tag 'usb-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[sfrench/cifs-2.6.git] / drivers / iio / chemical / sps30_serial.c
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
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
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
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
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
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
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
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
213 static ssize_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
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
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
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
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
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
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
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
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
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);