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(u8
*buf
, u8 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 u8
sps30_serial_get_byte(bool escaped
, u8 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(u8
*buf
, u8 cmd
, const u8
*arg
,
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 size_t sps30_serial_receive_buf(struct serdev_device
*serdev
,
214 const u8
*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");
432 MODULE_IMPORT_NS(IIO_SPS30
);