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