1*8f3f1308STomasz Duszynski // SPDX-License-Identifier: GPL-2.0 2*8f3f1308STomasz Duszynski /* 3*8f3f1308STomasz Duszynski * Sensirion SPS30 particulate matter sensor i2c driver 4*8f3f1308STomasz Duszynski * 5*8f3f1308STomasz Duszynski * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> 6*8f3f1308STomasz Duszynski * 7*8f3f1308STomasz Duszynski * I2C slave address: 0x69 8*8f3f1308STomasz Duszynski */ 9*8f3f1308STomasz Duszynski #include <asm/unaligned.h> 10*8f3f1308STomasz Duszynski #include <linux/crc8.h> 11*8f3f1308STomasz Duszynski #include <linux/delay.h> 12*8f3f1308STomasz Duszynski #include <linux/device.h> 13*8f3f1308STomasz Duszynski #include <linux/errno.h> 14*8f3f1308STomasz Duszynski #include <linux/i2c.h> 15*8f3f1308STomasz Duszynski #include <linux/mod_devicetable.h> 16*8f3f1308STomasz Duszynski #include <linux/module.h> 17*8f3f1308STomasz Duszynski #include <linux/types.h> 18*8f3f1308STomasz Duszynski 19*8f3f1308STomasz Duszynski #include "sps30.h" 20*8f3f1308STomasz Duszynski 21*8f3f1308STomasz Duszynski #define SPS30_I2C_CRC8_POLYNOMIAL 0x31 22*8f3f1308STomasz Duszynski /* max number of bytes needed to store PM measurements or serial string */ 23*8f3f1308STomasz Duszynski #define SPS30_I2C_MAX_BUF_SIZE 48 24*8f3f1308STomasz Duszynski 25*8f3f1308STomasz Duszynski DECLARE_CRC8_TABLE(sps30_i2c_crc8_table); 26*8f3f1308STomasz Duszynski 27*8f3f1308STomasz Duszynski #define SPS30_I2C_START_MEAS 0x0010 28*8f3f1308STomasz Duszynski #define SPS30_I2C_STOP_MEAS 0x0104 29*8f3f1308STomasz Duszynski #define SPS30_I2C_READ_MEAS 0x0300 30*8f3f1308STomasz Duszynski #define SPS30_I2C_MEAS_READY 0x0202 31*8f3f1308STomasz Duszynski #define SPS30_I2C_RESET 0xd304 32*8f3f1308STomasz Duszynski #define SPS30_I2C_CLEAN_FAN 0x5607 33*8f3f1308STomasz Duszynski #define SPS30_I2C_PERIOD 0x8004 34*8f3f1308STomasz Duszynski #define SPS30_I2C_READ_SERIAL 0xd033 35*8f3f1308STomasz Duszynski #define SPS30_I2C_READ_VERSION 0xd100 36*8f3f1308STomasz Duszynski 37*8f3f1308STomasz Duszynski static int sps30_i2c_xfer(struct sps30_state *state, unsigned char *txbuf, size_t txsize, 38*8f3f1308STomasz Duszynski unsigned char *rxbuf, size_t rxsize) 39*8f3f1308STomasz Duszynski { 40*8f3f1308STomasz Duszynski struct i2c_client *client = to_i2c_client(state->dev); 41*8f3f1308STomasz Duszynski int ret; 42*8f3f1308STomasz Duszynski 43*8f3f1308STomasz Duszynski /* 44*8f3f1308STomasz Duszynski * Sensor does not support repeated start so instead of 45*8f3f1308STomasz Duszynski * sending two i2c messages in a row we just send one by one. 46*8f3f1308STomasz Duszynski */ 47*8f3f1308STomasz Duszynski ret = i2c_master_send(client, txbuf, txsize); 48*8f3f1308STomasz Duszynski if (ret < 0) 49*8f3f1308STomasz Duszynski return ret; 50*8f3f1308STomasz Duszynski if (ret != txsize) 51*8f3f1308STomasz Duszynski return -EIO; 52*8f3f1308STomasz Duszynski 53*8f3f1308STomasz Duszynski if (!rxsize) 54*8f3f1308STomasz Duszynski return 0; 55*8f3f1308STomasz Duszynski 56*8f3f1308STomasz Duszynski ret = i2c_master_recv(client, rxbuf, rxsize); 57*8f3f1308STomasz Duszynski if (ret < 0) 58*8f3f1308STomasz Duszynski return ret; 59*8f3f1308STomasz Duszynski if (ret != rxsize) 60*8f3f1308STomasz Duszynski return -EIO; 61*8f3f1308STomasz Duszynski 62*8f3f1308STomasz Duszynski return 0; 63*8f3f1308STomasz Duszynski } 64*8f3f1308STomasz Duszynski 65*8f3f1308STomasz Duszynski static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size_t arg_size, 66*8f3f1308STomasz Duszynski void *rsp, size_t rsp_size) 67*8f3f1308STomasz Duszynski { 68*8f3f1308STomasz Duszynski /* 69*8f3f1308STomasz Duszynski * Internally sensor stores measurements in a following manner: 70*8f3f1308STomasz Duszynski * 71*8f3f1308STomasz Duszynski * PM1: upper two bytes, crc8, lower two bytes, crc8 72*8f3f1308STomasz Duszynski * PM2P5: upper two bytes, crc8, lower two bytes, crc8 73*8f3f1308STomasz Duszynski * PM4: upper two bytes, crc8, lower two bytes, crc8 74*8f3f1308STomasz Duszynski * PM10: upper two bytes, crc8, lower two bytes, crc8 75*8f3f1308STomasz Duszynski * 76*8f3f1308STomasz Duszynski * What follows next are number concentration measurements and 77*8f3f1308STomasz Duszynski * typical particle size measurement which we omit. 78*8f3f1308STomasz Duszynski */ 79*8f3f1308STomasz Duszynski unsigned char buf[SPS30_I2C_MAX_BUF_SIZE]; 80*8f3f1308STomasz Duszynski unsigned char *tmp; 81*8f3f1308STomasz Duszynski unsigned char crc; 82*8f3f1308STomasz Duszynski size_t i; 83*8f3f1308STomasz Duszynski int ret; 84*8f3f1308STomasz Duszynski 85*8f3f1308STomasz Duszynski put_unaligned_be16(cmd, buf); 86*8f3f1308STomasz Duszynski i = 2; 87*8f3f1308STomasz Duszynski 88*8f3f1308STomasz Duszynski if (rsp) { 89*8f3f1308STomasz Duszynski /* each two bytes are followed by a crc8 */ 90*8f3f1308STomasz Duszynski rsp_size += rsp_size / 2; 91*8f3f1308STomasz Duszynski } else { 92*8f3f1308STomasz Duszynski tmp = arg; 93*8f3f1308STomasz Duszynski 94*8f3f1308STomasz Duszynski while (arg_size) { 95*8f3f1308STomasz Duszynski buf[i] = *tmp++; 96*8f3f1308STomasz Duszynski buf[i + 1] = *tmp++; 97*8f3f1308STomasz Duszynski buf[i + 2] = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE); 98*8f3f1308STomasz Duszynski arg_size -= 2; 99*8f3f1308STomasz Duszynski i += 3; 100*8f3f1308STomasz Duszynski } 101*8f3f1308STomasz Duszynski } 102*8f3f1308STomasz Duszynski 103*8f3f1308STomasz Duszynski ret = sps30_i2c_xfer(state, buf, i, buf, rsp_size); 104*8f3f1308STomasz Duszynski if (ret) 105*8f3f1308STomasz Duszynski return ret; 106*8f3f1308STomasz Duszynski 107*8f3f1308STomasz Duszynski /* validate received data and strip off crc bytes */ 108*8f3f1308STomasz Duszynski tmp = rsp; 109*8f3f1308STomasz Duszynski for (i = 0; i < rsp_size; i += 3) { 110*8f3f1308STomasz Duszynski crc = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE); 111*8f3f1308STomasz Duszynski if (crc != buf[i + 2]) { 112*8f3f1308STomasz Duszynski dev_err(state->dev, "data integrity check failed\n"); 113*8f3f1308STomasz Duszynski return -EIO; 114*8f3f1308STomasz Duszynski } 115*8f3f1308STomasz Duszynski 116*8f3f1308STomasz Duszynski *tmp++ = buf[i]; 117*8f3f1308STomasz Duszynski *tmp++ = buf[i + 1]; 118*8f3f1308STomasz Duszynski } 119*8f3f1308STomasz Duszynski 120*8f3f1308STomasz Duszynski return 0; 121*8f3f1308STomasz Duszynski } 122*8f3f1308STomasz Duszynski 123*8f3f1308STomasz Duszynski static int sps30_i2c_start_meas(struct sps30_state *state) 124*8f3f1308STomasz Duszynski { 125*8f3f1308STomasz Duszynski /* request BE IEEE754 formatted data */ 126*8f3f1308STomasz Duszynski unsigned char buf[] = { 0x03, 0x00 }; 127*8f3f1308STomasz Duszynski 128*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_START_MEAS, buf, sizeof(buf), NULL, 0); 129*8f3f1308STomasz Duszynski } 130*8f3f1308STomasz Duszynski 131*8f3f1308STomasz Duszynski static int sps30_i2c_stop_meas(struct sps30_state *state) 132*8f3f1308STomasz Duszynski { 133*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_STOP_MEAS, NULL, 0, NULL, 0); 134*8f3f1308STomasz Duszynski } 135*8f3f1308STomasz Duszynski 136*8f3f1308STomasz Duszynski static int sps30_i2c_reset(struct sps30_state *state) 137*8f3f1308STomasz Duszynski { 138*8f3f1308STomasz Duszynski int ret; 139*8f3f1308STomasz Duszynski 140*8f3f1308STomasz Duszynski ret = sps30_i2c_command(state, SPS30_I2C_RESET, NULL, 0, NULL, 0); 141*8f3f1308STomasz Duszynski msleep(500); 142*8f3f1308STomasz Duszynski /* 143*8f3f1308STomasz Duszynski * Power-on-reset causes sensor to produce some glitch on i2c bus and 144*8f3f1308STomasz Duszynski * some controllers end up in error state. Recover simply by placing 145*8f3f1308STomasz Duszynski * some data on the bus, for example STOP_MEAS command, which 146*8f3f1308STomasz Duszynski * is NOP in this case. 147*8f3f1308STomasz Duszynski */ 148*8f3f1308STomasz Duszynski sps30_i2c_stop_meas(state); 149*8f3f1308STomasz Duszynski 150*8f3f1308STomasz Duszynski return ret; 151*8f3f1308STomasz Duszynski } 152*8f3f1308STomasz Duszynski 153*8f3f1308STomasz Duszynski static bool sps30_i2c_meas_ready(struct sps30_state *state) 154*8f3f1308STomasz Duszynski { 155*8f3f1308STomasz Duszynski unsigned char buf[2]; 156*8f3f1308STomasz Duszynski int ret; 157*8f3f1308STomasz Duszynski 158*8f3f1308STomasz Duszynski ret = sps30_i2c_command(state, SPS30_I2C_MEAS_READY, NULL, 0, buf, sizeof(buf)); 159*8f3f1308STomasz Duszynski if (ret) 160*8f3f1308STomasz Duszynski return false; 161*8f3f1308STomasz Duszynski 162*8f3f1308STomasz Duszynski return buf[1]; 163*8f3f1308STomasz Duszynski } 164*8f3f1308STomasz Duszynski 165*8f3f1308STomasz Duszynski static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t num) 166*8f3f1308STomasz Duszynski { 167*8f3f1308STomasz Duszynski /* measurements are ready within a second */ 168*8f3f1308STomasz Duszynski if (msleep_interruptible(1000)) 169*8f3f1308STomasz Duszynski return -EINTR; 170*8f3f1308STomasz Duszynski 171*8f3f1308STomasz Duszynski if (!sps30_i2c_meas_ready(state)) 172*8f3f1308STomasz Duszynski return -ETIMEDOUT; 173*8f3f1308STomasz Duszynski 174*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num); 175*8f3f1308STomasz Duszynski } 176*8f3f1308STomasz Duszynski 177*8f3f1308STomasz Duszynski static int sps30_i2c_clean_fan(struct sps30_state *state) 178*8f3f1308STomasz Duszynski { 179*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_CLEAN_FAN, NULL, 0, NULL, 0); 180*8f3f1308STomasz Duszynski } 181*8f3f1308STomasz Duszynski 182*8f3f1308STomasz Duszynski static int sps30_i2c_read_cleaning_period(struct sps30_state *state, __be32 *period) 183*8f3f1308STomasz Duszynski { 184*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_PERIOD, NULL, 0, period, sizeof(*period)); 185*8f3f1308STomasz Duszynski } 186*8f3f1308STomasz Duszynski 187*8f3f1308STomasz Duszynski static int sps30_i2c_write_cleaning_period(struct sps30_state *state, __be32 period) 188*8f3f1308STomasz Duszynski { 189*8f3f1308STomasz Duszynski return sps30_i2c_command(state, SPS30_I2C_PERIOD, &period, sizeof(period), NULL, 0); 190*8f3f1308STomasz Duszynski } 191*8f3f1308STomasz Duszynski 192*8f3f1308STomasz Duszynski static int sps30_i2c_show_info(struct sps30_state *state) 193*8f3f1308STomasz Duszynski { 194*8f3f1308STomasz Duszynski /* extra nul just in case */ 195*8f3f1308STomasz Duszynski unsigned char buf[32 + 1] = { 0x00 }; 196*8f3f1308STomasz Duszynski int ret; 197*8f3f1308STomasz Duszynski 198*8f3f1308STomasz Duszynski ret = sps30_i2c_command(state, SPS30_I2C_READ_SERIAL, NULL, 0, buf, sizeof(buf) - 1); 199*8f3f1308STomasz Duszynski if (ret) 200*8f3f1308STomasz Duszynski return ret; 201*8f3f1308STomasz Duszynski 202*8f3f1308STomasz Duszynski dev_info(state->dev, "serial number: %s\n", buf); 203*8f3f1308STomasz Duszynski 204*8f3f1308STomasz Duszynski ret = sps30_i2c_command(state, SPS30_I2C_READ_VERSION, NULL, 0, buf, 2); 205*8f3f1308STomasz Duszynski if (ret) 206*8f3f1308STomasz Duszynski return ret; 207*8f3f1308STomasz Duszynski 208*8f3f1308STomasz Duszynski dev_info(state->dev, "fw version: %u.%u\n", buf[0], buf[1]); 209*8f3f1308STomasz Duszynski 210*8f3f1308STomasz Duszynski return 0; 211*8f3f1308STomasz Duszynski } 212*8f3f1308STomasz Duszynski 213*8f3f1308STomasz Duszynski static const struct sps30_ops sps30_i2c_ops = { 214*8f3f1308STomasz Duszynski .start_meas = sps30_i2c_start_meas, 215*8f3f1308STomasz Duszynski .stop_meas = sps30_i2c_stop_meas, 216*8f3f1308STomasz Duszynski .read_meas = sps30_i2c_read_meas, 217*8f3f1308STomasz Duszynski .reset = sps30_i2c_reset, 218*8f3f1308STomasz Duszynski .clean_fan = sps30_i2c_clean_fan, 219*8f3f1308STomasz Duszynski .read_cleaning_period = sps30_i2c_read_cleaning_period, 220*8f3f1308STomasz Duszynski .write_cleaning_period = sps30_i2c_write_cleaning_period, 221*8f3f1308STomasz Duszynski .show_info = sps30_i2c_show_info, 222*8f3f1308STomasz Duszynski }; 223*8f3f1308STomasz Duszynski 224*8f3f1308STomasz Duszynski static int sps30_i2c_probe(struct i2c_client *client) 225*8f3f1308STomasz Duszynski { 226*8f3f1308STomasz Duszynski if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 227*8f3f1308STomasz Duszynski return -EOPNOTSUPP; 228*8f3f1308STomasz Duszynski 229*8f3f1308STomasz Duszynski crc8_populate_msb(sps30_i2c_crc8_table, SPS30_I2C_CRC8_POLYNOMIAL); 230*8f3f1308STomasz Duszynski 231*8f3f1308STomasz Duszynski return sps30_probe(&client->dev, client->name, NULL, &sps30_i2c_ops); 232*8f3f1308STomasz Duszynski } 233*8f3f1308STomasz Duszynski 234*8f3f1308STomasz Duszynski static const struct i2c_device_id sps30_i2c_id[] = { 235*8f3f1308STomasz Duszynski { "sps30" }, 236*8f3f1308STomasz Duszynski { } 237*8f3f1308STomasz Duszynski }; 238*8f3f1308STomasz Duszynski MODULE_DEVICE_TABLE(i2c, sps30_i2c_id); 239*8f3f1308STomasz Duszynski 240*8f3f1308STomasz Duszynski static const struct of_device_id sps30_i2c_of_match[] = { 241*8f3f1308STomasz Duszynski { .compatible = "sensirion,sps30" }, 242*8f3f1308STomasz Duszynski { } 243*8f3f1308STomasz Duszynski }; 244*8f3f1308STomasz Duszynski MODULE_DEVICE_TABLE(of, sps30_i2c_of_match); 245*8f3f1308STomasz Duszynski 246*8f3f1308STomasz Duszynski static struct i2c_driver sps30_i2c_driver = { 247*8f3f1308STomasz Duszynski .driver = { 248*8f3f1308STomasz Duszynski .name = KBUILD_MODNAME, 249*8f3f1308STomasz Duszynski .of_match_table = sps30_i2c_of_match, 250*8f3f1308STomasz Duszynski }, 251*8f3f1308STomasz Duszynski .id_table = sps30_i2c_id, 252*8f3f1308STomasz Duszynski .probe_new = sps30_i2c_probe, 253*8f3f1308STomasz Duszynski }; 254*8f3f1308STomasz Duszynski module_i2c_driver(sps30_i2c_driver); 255*8f3f1308STomasz Duszynski 256*8f3f1308STomasz Duszynski MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); 257*8f3f1308STomasz Duszynski MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver"); 258*8f3f1308STomasz Duszynski MODULE_LICENSE("GPL v2"); 259