0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <asm/unaligned.h>
0010 #include <linux/crc8.h>
0011 #include <linux/delay.h>
0012 #include <linux/device.h>
0013 #include <linux/errno.h>
0014 #include <linux/i2c.h>
0015 #include <linux/mod_devicetable.h>
0016 #include <linux/module.h>
0017 #include <linux/types.h>
0018
0019 #include "sps30.h"
0020
0021 #define SPS30_I2C_CRC8_POLYNOMIAL 0x31
0022
0023 #define SPS30_I2C_MAX_BUF_SIZE 48
0024
0025 DECLARE_CRC8_TABLE(sps30_i2c_crc8_table);
0026
0027 #define SPS30_I2C_START_MEAS 0x0010
0028 #define SPS30_I2C_STOP_MEAS 0x0104
0029 #define SPS30_I2C_READ_MEAS 0x0300
0030 #define SPS30_I2C_MEAS_READY 0x0202
0031 #define SPS30_I2C_RESET 0xd304
0032 #define SPS30_I2C_CLEAN_FAN 0x5607
0033 #define SPS30_I2C_PERIOD 0x8004
0034 #define SPS30_I2C_READ_SERIAL 0xd033
0035 #define SPS30_I2C_READ_VERSION 0xd100
0036
0037 static int sps30_i2c_xfer(struct sps30_state *state, unsigned char *txbuf, size_t txsize,
0038 unsigned char *rxbuf, size_t rxsize)
0039 {
0040 struct i2c_client *client = to_i2c_client(state->dev);
0041 int ret;
0042
0043
0044
0045
0046
0047 ret = i2c_master_send(client, txbuf, txsize);
0048 if (ret < 0)
0049 return ret;
0050 if (ret != txsize)
0051 return -EIO;
0052
0053 if (!rxsize)
0054 return 0;
0055
0056 ret = i2c_master_recv(client, rxbuf, rxsize);
0057 if (ret < 0)
0058 return ret;
0059 if (ret != rxsize)
0060 return -EIO;
0061
0062 return 0;
0063 }
0064
0065 static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size_t arg_size,
0066 void *rsp, size_t rsp_size)
0067 {
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 unsigned char buf[SPS30_I2C_MAX_BUF_SIZE];
0080 unsigned char *tmp;
0081 unsigned char crc;
0082 size_t i;
0083 int ret;
0084
0085 put_unaligned_be16(cmd, buf);
0086 i = 2;
0087
0088 if (rsp) {
0089
0090 rsp_size += rsp_size / 2;
0091 } else {
0092 tmp = arg;
0093
0094 while (arg_size) {
0095 buf[i] = *tmp++;
0096 buf[i + 1] = *tmp++;
0097 buf[i + 2] = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
0098 arg_size -= 2;
0099 i += 3;
0100 }
0101 }
0102
0103 ret = sps30_i2c_xfer(state, buf, i, buf, rsp_size);
0104 if (ret)
0105 return ret;
0106
0107
0108 tmp = rsp;
0109 for (i = 0; i < rsp_size; i += 3) {
0110 crc = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
0111 if (crc != buf[i + 2]) {
0112 dev_err(state->dev, "data integrity check failed\n");
0113 return -EIO;
0114 }
0115
0116 *tmp++ = buf[i];
0117 *tmp++ = buf[i + 1];
0118 }
0119
0120 return 0;
0121 }
0122
0123 static int sps30_i2c_start_meas(struct sps30_state *state)
0124 {
0125
0126 unsigned char buf[] = { 0x03, 0x00 };
0127
0128 return sps30_i2c_command(state, SPS30_I2C_START_MEAS, buf, sizeof(buf), NULL, 0);
0129 }
0130
0131 static int sps30_i2c_stop_meas(struct sps30_state *state)
0132 {
0133 return sps30_i2c_command(state, SPS30_I2C_STOP_MEAS, NULL, 0, NULL, 0);
0134 }
0135
0136 static int sps30_i2c_reset(struct sps30_state *state)
0137 {
0138 int ret;
0139
0140 ret = sps30_i2c_command(state, SPS30_I2C_RESET, NULL, 0, NULL, 0);
0141 msleep(500);
0142
0143
0144
0145
0146
0147
0148 sps30_i2c_stop_meas(state);
0149
0150 return ret;
0151 }
0152
0153 static bool sps30_i2c_meas_ready(struct sps30_state *state)
0154 {
0155 unsigned char buf[2];
0156 int ret;
0157
0158 ret = sps30_i2c_command(state, SPS30_I2C_MEAS_READY, NULL, 0, buf, sizeof(buf));
0159 if (ret)
0160 return false;
0161
0162 return buf[1];
0163 }
0164
0165 static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
0166 {
0167
0168 if (msleep_interruptible(1000))
0169 return -EINTR;
0170
0171 if (!sps30_i2c_meas_ready(state))
0172 return -ETIMEDOUT;
0173
0174 return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num);
0175 }
0176
0177 static int sps30_i2c_clean_fan(struct sps30_state *state)
0178 {
0179 return sps30_i2c_command(state, SPS30_I2C_CLEAN_FAN, NULL, 0, NULL, 0);
0180 }
0181
0182 static int sps30_i2c_read_cleaning_period(struct sps30_state *state, __be32 *period)
0183 {
0184 return sps30_i2c_command(state, SPS30_I2C_PERIOD, NULL, 0, period, sizeof(*period));
0185 }
0186
0187 static int sps30_i2c_write_cleaning_period(struct sps30_state *state, __be32 period)
0188 {
0189 return sps30_i2c_command(state, SPS30_I2C_PERIOD, &period, sizeof(period), NULL, 0);
0190 }
0191
0192 static int sps30_i2c_show_info(struct sps30_state *state)
0193 {
0194
0195 unsigned char buf[32 + 1] = { 0x00 };
0196 int ret;
0197
0198 ret = sps30_i2c_command(state, SPS30_I2C_READ_SERIAL, NULL, 0, buf, sizeof(buf) - 1);
0199 if (ret)
0200 return ret;
0201
0202 dev_info(state->dev, "serial number: %s\n", buf);
0203
0204 ret = sps30_i2c_command(state, SPS30_I2C_READ_VERSION, NULL, 0, buf, 2);
0205 if (ret)
0206 return ret;
0207
0208 dev_info(state->dev, "fw version: %u.%u\n", buf[0], buf[1]);
0209
0210 return 0;
0211 }
0212
0213 static const struct sps30_ops sps30_i2c_ops = {
0214 .start_meas = sps30_i2c_start_meas,
0215 .stop_meas = sps30_i2c_stop_meas,
0216 .read_meas = sps30_i2c_read_meas,
0217 .reset = sps30_i2c_reset,
0218 .clean_fan = sps30_i2c_clean_fan,
0219 .read_cleaning_period = sps30_i2c_read_cleaning_period,
0220 .write_cleaning_period = sps30_i2c_write_cleaning_period,
0221 .show_info = sps30_i2c_show_info,
0222 };
0223
0224 static int sps30_i2c_probe(struct i2c_client *client)
0225 {
0226 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
0227 return -EOPNOTSUPP;
0228
0229 crc8_populate_msb(sps30_i2c_crc8_table, SPS30_I2C_CRC8_POLYNOMIAL);
0230
0231 return sps30_probe(&client->dev, client->name, NULL, &sps30_i2c_ops);
0232 }
0233
0234 static const struct i2c_device_id sps30_i2c_id[] = {
0235 { "sps30" },
0236 { }
0237 };
0238 MODULE_DEVICE_TABLE(i2c, sps30_i2c_id);
0239
0240 static const struct of_device_id sps30_i2c_of_match[] = {
0241 { .compatible = "sensirion,sps30" },
0242 { }
0243 };
0244 MODULE_DEVICE_TABLE(of, sps30_i2c_of_match);
0245
0246 static struct i2c_driver sps30_i2c_driver = {
0247 .driver = {
0248 .name = KBUILD_MODNAME,
0249 .of_match_table = sps30_i2c_of_match,
0250 },
0251 .id_table = sps30_i2c_id,
0252 .probe_new = sps30_i2c_probe,
0253 };
0254 module_i2c_driver(sps30_i2c_driver);
0255
0256 MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
0257 MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver");
0258 MODULE_LICENSE("GPL v2");
0259 MODULE_IMPORT_NS(IIO_SPS30);