sps30_serial.c (10789B)
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(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 76static const struct { 77 unsigned char byte; 78 unsigned char 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(unsigned char *buf, unsigned char 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 char sps30_serial_get_byte(bool escaped, unsigned char 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(unsigned char *buf, unsigned char cmd, 134 const unsigned char *arg, 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 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(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 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 int sps30_serial_receive_buf(struct serdev_device *serdev, 214 const unsigned char *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 unsigned char byte; 220 size_t i; 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 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, buf, sizeof(buf), NULL, 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, 0, NULL, 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, 0, NULL, 0); 293 msleep(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(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 318static 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 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, 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 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, buf, sizeof(buf), NULL, 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, 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 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, 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 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");