1ce514124SAndreas Brauchli // SPDX-License-Identifier: GPL-2.0 2ce514124SAndreas Brauchli /* 3ce514124SAndreas Brauchli * sgp30.c - Support for Sensirion SGP Gas Sensors 4ce514124SAndreas Brauchli * 5ce514124SAndreas Brauchli * Copyright (C) 2018 Andreas Brauchli <andreas.brauchli@sensirion.com> 6ce514124SAndreas Brauchli * 7ce514124SAndreas Brauchli * I2C slave address: 0x58 8ce514124SAndreas Brauchli * 9ce514124SAndreas Brauchli * Datasheets: 10ce514124SAndreas Brauchli * https://www.sensirion.com/file/datasheet_sgp30 11ce514124SAndreas Brauchli * https://www.sensirion.com/file/datasheet_sgpc3 12ce514124SAndreas Brauchli * 13ce514124SAndreas Brauchli * TODO: 14ce514124SAndreas Brauchli * - baseline support 15ce514124SAndreas Brauchli * - humidity compensation 16ce514124SAndreas Brauchli * - power mode switching (SGPC3) 17ce514124SAndreas Brauchli */ 18ce514124SAndreas Brauchli 19ce514124SAndreas Brauchli #include <linux/crc8.h> 20ce514124SAndreas Brauchli #include <linux/delay.h> 21ce514124SAndreas Brauchli #include <linux/kthread.h> 22ce514124SAndreas Brauchli #include <linux/module.h> 236ac282edSJonathan Cameron #include <linux/mod_devicetable.h> 24ce514124SAndreas Brauchli #include <linux/mutex.h> 25ce514124SAndreas Brauchli #include <linux/i2c.h> 26ce514124SAndreas Brauchli #include <linux/iio/iio.h> 27ce514124SAndreas Brauchli #include <linux/iio/sysfs.h> 28ce514124SAndreas Brauchli 29ce514124SAndreas Brauchli #define SGP_WORD_LEN 2 30ce514124SAndreas Brauchli #define SGP_CRC8_POLYNOMIAL 0x31 31ce514124SAndreas Brauchli #define SGP_CRC8_INIT 0xff 32ce514124SAndreas Brauchli #define SGP_CRC8_LEN 1 33ce514124SAndreas Brauchli #define SGP_CMD(cmd_word) cpu_to_be16(cmd_word) 34ce514124SAndreas Brauchli #define SGP_CMD_DURATION_US 12000 35ce514124SAndreas Brauchli #define SGP_MEASUREMENT_DURATION_US 50000 36ce514124SAndreas Brauchli #define SGP_CMD_LEN SGP_WORD_LEN 37ce514124SAndreas Brauchli #define SGP_CMD_MAX_BUF_SIZE (SGP_CMD_LEN + 2 * SGP_WORD_LEN) 38ce514124SAndreas Brauchli #define SGP_MEASUREMENT_LEN 2 39ce514124SAndreas Brauchli #define SGP30_MEASURE_INTERVAL_HZ 1 40ce514124SAndreas Brauchli #define SGPC3_MEASURE_INTERVAL_HZ 2 41ce514124SAndreas Brauchli #define SGP_VERS_PRODUCT(data) ((((data)->feature_set) & 0xf000) >> 12) 42ce514124SAndreas Brauchli #define SGP_VERS_RESERVED(data) ((((data)->feature_set) & 0x0800) >> 11) 43ce514124SAndreas Brauchli #define SGP_VERS_GEN(data) ((((data)->feature_set) & 0x0600) >> 9) 44ce514124SAndreas Brauchli #define SGP_VERS_ENG_BIT(data) ((((data)->feature_set) & 0x0100) >> 8) 45ce514124SAndreas Brauchli #define SGP_VERS_MAJOR(data) ((((data)->feature_set) & 0x00e0) >> 5) 46ce514124SAndreas Brauchli #define SGP_VERS_MINOR(data) (((data)->feature_set) & 0x001f) 47ce514124SAndreas Brauchli 48ce514124SAndreas Brauchli DECLARE_CRC8_TABLE(sgp_crc8_table); 49ce514124SAndreas Brauchli 50ce514124SAndreas Brauchli enum sgp_product_id { 51ce514124SAndreas Brauchli SGP30 = 0, 52ce514124SAndreas Brauchli SGPC3, 53ce514124SAndreas Brauchli }; 54ce514124SAndreas Brauchli 55ce514124SAndreas Brauchli enum sgp30_channel_idx { 56ce514124SAndreas Brauchli SGP30_IAQ_TVOC_IDX = 0, 57ce514124SAndreas Brauchli SGP30_IAQ_CO2EQ_IDX, 58ce514124SAndreas Brauchli SGP30_SIG_ETOH_IDX, 59ce514124SAndreas Brauchli SGP30_SIG_H2_IDX, 60ce514124SAndreas Brauchli }; 61ce514124SAndreas Brauchli 62ce514124SAndreas Brauchli enum sgpc3_channel_idx { 63ce514124SAndreas Brauchli SGPC3_IAQ_TVOC_IDX = 10, 64ce514124SAndreas Brauchli SGPC3_SIG_ETOH_IDX, 65ce514124SAndreas Brauchli }; 66ce514124SAndreas Brauchli 67ce514124SAndreas Brauchli enum sgp_cmd { 68ce514124SAndreas Brauchli SGP_CMD_IAQ_INIT = SGP_CMD(0x2003), 69ce514124SAndreas Brauchli SGP_CMD_IAQ_MEASURE = SGP_CMD(0x2008), 70ce514124SAndreas Brauchli SGP_CMD_GET_FEATURE_SET = SGP_CMD(0x202f), 71ce514124SAndreas Brauchli SGP_CMD_GET_SERIAL_ID = SGP_CMD(0x3682), 72ce514124SAndreas Brauchli 73ce514124SAndreas Brauchli SGP30_CMD_MEASURE_SIGNAL = SGP_CMD(0x2050), 74ce514124SAndreas Brauchli 75ce514124SAndreas Brauchli SGPC3_CMD_MEASURE_RAW = SGP_CMD(0x2046), 76ce514124SAndreas Brauchli }; 77ce514124SAndreas Brauchli 78ce514124SAndreas Brauchli struct sgp_version { 79ce514124SAndreas Brauchli u8 major; 80ce514124SAndreas Brauchli u8 minor; 81ce514124SAndreas Brauchli }; 82ce514124SAndreas Brauchli 83ce514124SAndreas Brauchli struct sgp_crc_word { 84ce514124SAndreas Brauchli __be16 value; 85ce514124SAndreas Brauchli u8 crc8; 86ce514124SAndreas Brauchli } __attribute__((__packed__)); 87ce514124SAndreas Brauchli 88ce514124SAndreas Brauchli union sgp_reading { 89ce514124SAndreas Brauchli u8 start; 90ce514124SAndreas Brauchli struct sgp_crc_word raw_words[4]; 91ce514124SAndreas Brauchli }; 92ce514124SAndreas Brauchli 93ce514124SAndreas Brauchli enum _iaq_buffer_state { 94ce514124SAndreas Brauchli IAQ_BUFFER_EMPTY = 0, 95ce514124SAndreas Brauchli IAQ_BUFFER_DEFAULT_VALS, 96ce514124SAndreas Brauchli IAQ_BUFFER_VALID, 97ce514124SAndreas Brauchli }; 98ce514124SAndreas Brauchli 99ce514124SAndreas Brauchli struct sgp_data { 100ce514124SAndreas Brauchli struct i2c_client *client; 101ce514124SAndreas Brauchli struct task_struct *iaq_thread; 102ce514124SAndreas Brauchli struct mutex data_lock; 103ce514124SAndreas Brauchli unsigned long iaq_init_start_jiffies; 104ce514124SAndreas Brauchli unsigned long iaq_defval_skip_jiffies; 105ce514124SAndreas Brauchli u16 product_id; 106ce514124SAndreas Brauchli u16 feature_set; 107ce514124SAndreas Brauchli unsigned long measure_interval_jiffies; 108ce514124SAndreas Brauchli enum sgp_cmd iaq_init_cmd; 109ce514124SAndreas Brauchli enum sgp_cmd measure_iaq_cmd; 110ce514124SAndreas Brauchli enum sgp_cmd measure_gas_signals_cmd; 111ce514124SAndreas Brauchli union sgp_reading buffer; 112ce514124SAndreas Brauchli union sgp_reading iaq_buffer; 113ce514124SAndreas Brauchli enum _iaq_buffer_state iaq_buffer_state; 114ce514124SAndreas Brauchli }; 115ce514124SAndreas Brauchli 116ce514124SAndreas Brauchli struct sgp_device { 117ce514124SAndreas Brauchli const struct iio_chan_spec *channels; 118ce514124SAndreas Brauchli int num_channels; 119ce514124SAndreas Brauchli }; 120ce514124SAndreas Brauchli 121ce514124SAndreas Brauchli static const struct sgp_version supported_versions_sgp30[] = { 122ce514124SAndreas Brauchli { 123ce514124SAndreas Brauchli .major = 1, 124ce514124SAndreas Brauchli .minor = 0, 125ce514124SAndreas Brauchli }, 126ce514124SAndreas Brauchli }; 127ce514124SAndreas Brauchli 128ce514124SAndreas Brauchli static const struct sgp_version supported_versions_sgpc3[] = { 129ce514124SAndreas Brauchli { 130ce514124SAndreas Brauchli .major = 0, 131ce514124SAndreas Brauchli .minor = 4, 132ce514124SAndreas Brauchli }, 133ce514124SAndreas Brauchli }; 134ce514124SAndreas Brauchli 135ce514124SAndreas Brauchli static const struct iio_chan_spec sgp30_channels[] = { 136ce514124SAndreas Brauchli { 137ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 138ce514124SAndreas Brauchli .channel2 = IIO_MOD_VOC, 139ce514124SAndreas Brauchli .modified = 1, 140ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 141ce514124SAndreas Brauchli .address = SGP30_IAQ_TVOC_IDX, 142ce514124SAndreas Brauchli }, 143ce514124SAndreas Brauchli { 144ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 145ce514124SAndreas Brauchli .channel2 = IIO_MOD_CO2, 146ce514124SAndreas Brauchli .modified = 1, 147ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 148ce514124SAndreas Brauchli .address = SGP30_IAQ_CO2EQ_IDX, 149ce514124SAndreas Brauchli }, 150ce514124SAndreas Brauchli { 151ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 152ce514124SAndreas Brauchli .channel2 = IIO_MOD_ETHANOL, 153ce514124SAndreas Brauchli .modified = 1, 154ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 155ce514124SAndreas Brauchli .address = SGP30_SIG_ETOH_IDX, 156ce514124SAndreas Brauchli }, 157ce514124SAndreas Brauchli { 158ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 159ce514124SAndreas Brauchli .channel2 = IIO_MOD_H2, 160ce514124SAndreas Brauchli .modified = 1, 161ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 162ce514124SAndreas Brauchli .address = SGP30_SIG_H2_IDX, 163ce514124SAndreas Brauchli }, 164ce514124SAndreas Brauchli }; 165ce514124SAndreas Brauchli 166ce514124SAndreas Brauchli static const struct iio_chan_spec sgpc3_channels[] = { 167ce514124SAndreas Brauchli { 168ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 169ce514124SAndreas Brauchli .channel2 = IIO_MOD_VOC, 170ce514124SAndreas Brauchli .modified = 1, 171ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 172ce514124SAndreas Brauchli .address = SGPC3_IAQ_TVOC_IDX, 173ce514124SAndreas Brauchli }, 174ce514124SAndreas Brauchli { 175ce514124SAndreas Brauchli .type = IIO_CONCENTRATION, 176ce514124SAndreas Brauchli .channel2 = IIO_MOD_ETHANOL, 177ce514124SAndreas Brauchli .modified = 1, 178ce514124SAndreas Brauchli .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 179ce514124SAndreas Brauchli .address = SGPC3_SIG_ETOH_IDX, 180ce514124SAndreas Brauchli }, 181ce514124SAndreas Brauchli }; 182ce514124SAndreas Brauchli 183ce514124SAndreas Brauchli static const struct sgp_device sgp_devices[] = { 184ce514124SAndreas Brauchli [SGP30] = { 185ce514124SAndreas Brauchli .channels = sgp30_channels, 186ce514124SAndreas Brauchli .num_channels = ARRAY_SIZE(sgp30_channels), 187ce514124SAndreas Brauchli }, 188ce514124SAndreas Brauchli [SGPC3] = { 189ce514124SAndreas Brauchli .channels = sgpc3_channels, 190ce514124SAndreas Brauchli .num_channels = ARRAY_SIZE(sgpc3_channels), 191ce514124SAndreas Brauchli }, 192ce514124SAndreas Brauchli }; 193ce514124SAndreas Brauchli 194ce514124SAndreas Brauchli /** 195ce514124SAndreas Brauchli * sgp_verify_buffer() - verify the checksums of the data buffer words 196ce514124SAndreas Brauchli * 197ce514124SAndreas Brauchli * @data: SGP data 198ce514124SAndreas Brauchli * @buf: Raw data buffer 199ce514124SAndreas Brauchli * @word_count: Num data words stored in the buffer, excluding CRC bytes 200ce514124SAndreas Brauchli * 201ce514124SAndreas Brauchli * Return: 0 on success, negative error otherwise. 202ce514124SAndreas Brauchli */ 203ce514124SAndreas Brauchli static int sgp_verify_buffer(const struct sgp_data *data, 204ce514124SAndreas Brauchli union sgp_reading *buf, size_t word_count) 205ce514124SAndreas Brauchli { 206ce514124SAndreas Brauchli size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN); 207ce514124SAndreas Brauchli int i; 208ce514124SAndreas Brauchli u8 crc; 209ce514124SAndreas Brauchli u8 *data_buf = &buf->start; 210ce514124SAndreas Brauchli 211ce514124SAndreas Brauchli for (i = 0; i < size; i += SGP_WORD_LEN + SGP_CRC8_LEN) { 212ce514124SAndreas Brauchli crc = crc8(sgp_crc8_table, &data_buf[i], SGP_WORD_LEN, 213ce514124SAndreas Brauchli SGP_CRC8_INIT); 214ce514124SAndreas Brauchli if (crc != data_buf[i + SGP_WORD_LEN]) { 215ce514124SAndreas Brauchli dev_err(&data->client->dev, "CRC error\n"); 216ce514124SAndreas Brauchli return -EIO; 217ce514124SAndreas Brauchli } 218ce514124SAndreas Brauchli } 219ce514124SAndreas Brauchli 220ce514124SAndreas Brauchli return 0; 221ce514124SAndreas Brauchli } 222ce514124SAndreas Brauchli 223ce514124SAndreas Brauchli /** 224ce514124SAndreas Brauchli * sgp_read_cmd() - reads data from sensor after issuing a command 225ce514124SAndreas Brauchli * The caller must hold data->data_lock for the duration of the call. 226ce514124SAndreas Brauchli * @data: SGP data 227ce514124SAndreas Brauchli * @cmd: SGP Command to issue 228ce514124SAndreas Brauchli * @buf: Raw data buffer to use 229ce514124SAndreas Brauchli * @word_count: Num words to read, excluding CRC bytes 230ed33833eSLee Jones * @duration_us: Time taken to sensor to take a reading and data to be ready. 231ce514124SAndreas Brauchli * 232ce514124SAndreas Brauchli * Return: 0 on success, negative error otherwise. 233ce514124SAndreas Brauchli */ 234ce514124SAndreas Brauchli static int sgp_read_cmd(struct sgp_data *data, enum sgp_cmd cmd, 235ce514124SAndreas Brauchli union sgp_reading *buf, size_t word_count, 236ce514124SAndreas Brauchli unsigned long duration_us) 237ce514124SAndreas Brauchli { 238ce514124SAndreas Brauchli int ret; 239ce514124SAndreas Brauchli struct i2c_client *client = data->client; 240ce514124SAndreas Brauchli size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN); 241ce514124SAndreas Brauchli u8 *data_buf; 242ce514124SAndreas Brauchli 243ce514124SAndreas Brauchli ret = i2c_master_send(client, (const char *)&cmd, SGP_CMD_LEN); 244ce514124SAndreas Brauchli if (ret != SGP_CMD_LEN) 245ce514124SAndreas Brauchli return -EIO; 246ce514124SAndreas Brauchli usleep_range(duration_us, duration_us + 1000); 247ce514124SAndreas Brauchli 248ce514124SAndreas Brauchli if (word_count == 0) 249ce514124SAndreas Brauchli return 0; 250ce514124SAndreas Brauchli 251ce514124SAndreas Brauchli data_buf = &buf->start; 252ce514124SAndreas Brauchli ret = i2c_master_recv(client, data_buf, size); 253ce514124SAndreas Brauchli if (ret < 0) 254ce514124SAndreas Brauchli return ret; 255ce514124SAndreas Brauchli if (ret != size) 256ce514124SAndreas Brauchli return -EIO; 257ce514124SAndreas Brauchli 258ce514124SAndreas Brauchli return sgp_verify_buffer(data, buf, word_count); 259ce514124SAndreas Brauchli } 260ce514124SAndreas Brauchli 261ce514124SAndreas Brauchli /** 262ce514124SAndreas Brauchli * sgp_measure_iaq() - measure and retrieve IAQ values from sensor 263ce514124SAndreas Brauchli * The caller must hold data->data_lock for the duration of the call. 264ce514124SAndreas Brauchli * @data: SGP data 265ce514124SAndreas Brauchli * 266ce514124SAndreas Brauchli * Return: 0 on success, -EBUSY on default values, negative error 267ce514124SAndreas Brauchli * otherwise. 268ce514124SAndreas Brauchli */ 269ce514124SAndreas Brauchli 270ce514124SAndreas Brauchli static int sgp_measure_iaq(struct sgp_data *data) 271ce514124SAndreas Brauchli { 272ce514124SAndreas Brauchli int ret; 273ce514124SAndreas Brauchli /* data contains default values */ 274ce514124SAndreas Brauchli bool default_vals = !time_after(jiffies, data->iaq_init_start_jiffies + 275ce514124SAndreas Brauchli data->iaq_defval_skip_jiffies); 276ce514124SAndreas Brauchli 277ce514124SAndreas Brauchli ret = sgp_read_cmd(data, data->measure_iaq_cmd, &data->iaq_buffer, 278ce514124SAndreas Brauchli SGP_MEASUREMENT_LEN, SGP_MEASUREMENT_DURATION_US); 279ce514124SAndreas Brauchli if (ret < 0) 280ce514124SAndreas Brauchli return ret; 281ce514124SAndreas Brauchli 282ce514124SAndreas Brauchli data->iaq_buffer_state = IAQ_BUFFER_DEFAULT_VALS; 283ce514124SAndreas Brauchli 284ce514124SAndreas Brauchli if (default_vals) 285ce514124SAndreas Brauchli return -EBUSY; 286ce514124SAndreas Brauchli 287ce514124SAndreas Brauchli data->iaq_buffer_state = IAQ_BUFFER_VALID; 288ce514124SAndreas Brauchli 289ce514124SAndreas Brauchli return 0; 290ce514124SAndreas Brauchli } 291ce514124SAndreas Brauchli 292ce514124SAndreas Brauchli static void sgp_iaq_thread_sleep_until(const struct sgp_data *data, 293ce514124SAndreas Brauchli unsigned long sleep_jiffies) 294ce514124SAndreas Brauchli { 295ce514124SAndreas Brauchli const long IAQ_POLL = 50000; 296ce514124SAndreas Brauchli 297ce514124SAndreas Brauchli while (!time_after(jiffies, sleep_jiffies)) { 298ce514124SAndreas Brauchli usleep_range(IAQ_POLL, IAQ_POLL + 10000); 299ce514124SAndreas Brauchli if (kthread_should_stop() || data->iaq_init_start_jiffies == 0) 300ce514124SAndreas Brauchli return; 301ce514124SAndreas Brauchli } 302ce514124SAndreas Brauchli } 303ce514124SAndreas Brauchli 304ce514124SAndreas Brauchli static int sgp_iaq_threadfn(void *p) 305ce514124SAndreas Brauchli { 306ce514124SAndreas Brauchli struct sgp_data *data = (struct sgp_data *)p; 307ce514124SAndreas Brauchli unsigned long next_update_jiffies; 308ce514124SAndreas Brauchli int ret; 309ce514124SAndreas Brauchli 310ce514124SAndreas Brauchli while (!kthread_should_stop()) { 311ce514124SAndreas Brauchli mutex_lock(&data->data_lock); 312ce514124SAndreas Brauchli if (data->iaq_init_start_jiffies == 0) { 313ce514124SAndreas Brauchli ret = sgp_read_cmd(data, data->iaq_init_cmd, NULL, 0, 314ce514124SAndreas Brauchli SGP_CMD_DURATION_US); 315ce514124SAndreas Brauchli if (ret < 0) 316ce514124SAndreas Brauchli goto unlock_sleep_continue; 317ce514124SAndreas Brauchli data->iaq_init_start_jiffies = jiffies; 318ce514124SAndreas Brauchli } 319ce514124SAndreas Brauchli 320ce514124SAndreas Brauchli ret = sgp_measure_iaq(data); 321ce514124SAndreas Brauchli if (ret && ret != -EBUSY) { 322ce514124SAndreas Brauchli dev_warn(&data->client->dev, 323ce514124SAndreas Brauchli "IAQ measurement error [%d]\n", ret); 324ce514124SAndreas Brauchli } 325ce514124SAndreas Brauchli unlock_sleep_continue: 326ce514124SAndreas Brauchli next_update_jiffies = jiffies + data->measure_interval_jiffies; 327ce514124SAndreas Brauchli mutex_unlock(&data->data_lock); 328ce514124SAndreas Brauchli sgp_iaq_thread_sleep_until(data, next_update_jiffies); 329ce514124SAndreas Brauchli } 330ce514124SAndreas Brauchli 331ce514124SAndreas Brauchli return 0; 332ce514124SAndreas Brauchli } 333ce514124SAndreas Brauchli 334ce514124SAndreas Brauchli static int sgp_read_raw(struct iio_dev *indio_dev, 335ce514124SAndreas Brauchli struct iio_chan_spec const *chan, int *val, 336ce514124SAndreas Brauchli int *val2, long mask) 337ce514124SAndreas Brauchli { 338ce514124SAndreas Brauchli struct sgp_data *data = iio_priv(indio_dev); 339ce514124SAndreas Brauchli struct sgp_crc_word *words; 340ce514124SAndreas Brauchli int ret; 341ce514124SAndreas Brauchli 342ce514124SAndreas Brauchli switch (mask) { 343ce514124SAndreas Brauchli case IIO_CHAN_INFO_PROCESSED: 344ce514124SAndreas Brauchli mutex_lock(&data->data_lock); 345ce514124SAndreas Brauchli if (data->iaq_buffer_state != IAQ_BUFFER_VALID) { 346ce514124SAndreas Brauchli mutex_unlock(&data->data_lock); 347ce514124SAndreas Brauchli return -EBUSY; 348ce514124SAndreas Brauchli } 349ce514124SAndreas Brauchli words = data->iaq_buffer.raw_words; 350ce514124SAndreas Brauchli switch (chan->address) { 351ce514124SAndreas Brauchli case SGP30_IAQ_TVOC_IDX: 352ce514124SAndreas Brauchli case SGPC3_IAQ_TVOC_IDX: 353ce514124SAndreas Brauchli *val = 0; 354ce514124SAndreas Brauchli *val2 = be16_to_cpu(words[1].value); 355ce514124SAndreas Brauchli ret = IIO_VAL_INT_PLUS_NANO; 356ce514124SAndreas Brauchli break; 357ce514124SAndreas Brauchli case SGP30_IAQ_CO2EQ_IDX: 358ce514124SAndreas Brauchli *val = 0; 359ce514124SAndreas Brauchli *val2 = be16_to_cpu(words[0].value); 360ce514124SAndreas Brauchli ret = IIO_VAL_INT_PLUS_MICRO; 361ce514124SAndreas Brauchli break; 362ce514124SAndreas Brauchli default: 363ce514124SAndreas Brauchli ret = -EINVAL; 364ce514124SAndreas Brauchli break; 365ce514124SAndreas Brauchli } 366ce514124SAndreas Brauchli mutex_unlock(&data->data_lock); 367ce514124SAndreas Brauchli break; 368ce514124SAndreas Brauchli case IIO_CHAN_INFO_RAW: 369ce514124SAndreas Brauchli mutex_lock(&data->data_lock); 370ce514124SAndreas Brauchli if (chan->address == SGPC3_SIG_ETOH_IDX) { 371ce514124SAndreas Brauchli if (data->iaq_buffer_state == IAQ_BUFFER_EMPTY) 372ce514124SAndreas Brauchli ret = -EBUSY; 373ce514124SAndreas Brauchli else 374ce514124SAndreas Brauchli ret = 0; 375ce514124SAndreas Brauchli words = data->iaq_buffer.raw_words; 376ce514124SAndreas Brauchli } else { 377ce514124SAndreas Brauchli ret = sgp_read_cmd(data, data->measure_gas_signals_cmd, 378ce514124SAndreas Brauchli &data->buffer, SGP_MEASUREMENT_LEN, 379ce514124SAndreas Brauchli SGP_MEASUREMENT_DURATION_US); 380ce514124SAndreas Brauchli words = data->buffer.raw_words; 381ce514124SAndreas Brauchli } 382ce514124SAndreas Brauchli if (ret) { 383ce514124SAndreas Brauchli mutex_unlock(&data->data_lock); 384ce514124SAndreas Brauchli return ret; 385ce514124SAndreas Brauchli } 386ce514124SAndreas Brauchli 387ce514124SAndreas Brauchli switch (chan->address) { 388ce514124SAndreas Brauchli case SGP30_SIG_ETOH_IDX: 389ce514124SAndreas Brauchli *val = be16_to_cpu(words[1].value); 390ce514124SAndreas Brauchli ret = IIO_VAL_INT; 391ce514124SAndreas Brauchli break; 392ce514124SAndreas Brauchli case SGPC3_SIG_ETOH_IDX: 393ce514124SAndreas Brauchli case SGP30_SIG_H2_IDX: 394ce514124SAndreas Brauchli *val = be16_to_cpu(words[0].value); 395ce514124SAndreas Brauchli ret = IIO_VAL_INT; 396ce514124SAndreas Brauchli break; 397ce514124SAndreas Brauchli default: 398ce514124SAndreas Brauchli ret = -EINVAL; 399ce514124SAndreas Brauchli break; 400ce514124SAndreas Brauchli } 401ce514124SAndreas Brauchli mutex_unlock(&data->data_lock); 402ce514124SAndreas Brauchli break; 403ce514124SAndreas Brauchli default: 404ce514124SAndreas Brauchli return -EINVAL; 405ce514124SAndreas Brauchli } 406ce514124SAndreas Brauchli 407ce514124SAndreas Brauchli return ret; 408ce514124SAndreas Brauchli } 409ce514124SAndreas Brauchli 410ce514124SAndreas Brauchli static int sgp_check_compat(struct sgp_data *data, 411ce514124SAndreas Brauchli unsigned int product_id) 412ce514124SAndreas Brauchli { 413cb26d236SJonathan Cameron struct device *dev = &data->client->dev; 414ce514124SAndreas Brauchli const struct sgp_version *supported_versions; 415ce514124SAndreas Brauchli u16 ix, num_fs; 416ce514124SAndreas Brauchli u16 product, generation, major, minor; 417ce514124SAndreas Brauchli 418ce514124SAndreas Brauchli /* driver does not match product */ 419ce514124SAndreas Brauchli generation = SGP_VERS_GEN(data); 420ce514124SAndreas Brauchli if (generation != 0) { 421cb26d236SJonathan Cameron dev_err(dev, 422ce514124SAndreas Brauchli "incompatible product generation %d != 0", generation); 423ce514124SAndreas Brauchli return -ENODEV; 424ce514124SAndreas Brauchli } 425ce514124SAndreas Brauchli 426ce514124SAndreas Brauchli product = SGP_VERS_PRODUCT(data); 427ce514124SAndreas Brauchli if (product != product_id) { 428*38e9d5caSJonathan Cameron dev_err(dev, "sensor reports a different product: 0x%04x\n", 429ce514124SAndreas Brauchli product); 430ce514124SAndreas Brauchli return -ENODEV; 431ce514124SAndreas Brauchli } 432ce514124SAndreas Brauchli 433ce514124SAndreas Brauchli if (SGP_VERS_RESERVED(data)) 434cb26d236SJonathan Cameron dev_warn(dev, "reserved bit is set\n"); 435ce514124SAndreas Brauchli 436ce514124SAndreas Brauchli /* engineering samples are not supported: no interface guarantees */ 437ce514124SAndreas Brauchli if (SGP_VERS_ENG_BIT(data)) 438ce514124SAndreas Brauchli return -ENODEV; 439ce514124SAndreas Brauchli 440ce514124SAndreas Brauchli switch (product) { 441ce514124SAndreas Brauchli case SGP30: 442ce514124SAndreas Brauchli supported_versions = supported_versions_sgp30; 443ce514124SAndreas Brauchli num_fs = ARRAY_SIZE(supported_versions_sgp30); 444ce514124SAndreas Brauchli break; 445ce514124SAndreas Brauchli case SGPC3: 446ce514124SAndreas Brauchli supported_versions = supported_versions_sgpc3; 447ce514124SAndreas Brauchli num_fs = ARRAY_SIZE(supported_versions_sgpc3); 448ce514124SAndreas Brauchli break; 449ce514124SAndreas Brauchli default: 450ce514124SAndreas Brauchli return -ENODEV; 451ce514124SAndreas Brauchli } 452ce514124SAndreas Brauchli 453ce514124SAndreas Brauchli major = SGP_VERS_MAJOR(data); 454ce514124SAndreas Brauchli minor = SGP_VERS_MINOR(data); 455ce514124SAndreas Brauchli for (ix = 0; ix < num_fs; ix++) { 456ce514124SAndreas Brauchli if (major == supported_versions[ix].major && 457ce514124SAndreas Brauchli minor >= supported_versions[ix].minor) 458ce514124SAndreas Brauchli return 0; 459ce514124SAndreas Brauchli } 460cb26d236SJonathan Cameron dev_err(dev, "unsupported sgp version: %d.%d\n", major, minor); 461ce514124SAndreas Brauchli 462ce514124SAndreas Brauchli return -ENODEV; 463ce514124SAndreas Brauchli } 464ce514124SAndreas Brauchli 465ce514124SAndreas Brauchli static void sgp_init(struct sgp_data *data) 466ce514124SAndreas Brauchli { 467ce514124SAndreas Brauchli data->iaq_init_cmd = SGP_CMD_IAQ_INIT; 468ce514124SAndreas Brauchli data->iaq_init_start_jiffies = 0; 469ce514124SAndreas Brauchli data->iaq_buffer_state = IAQ_BUFFER_EMPTY; 470ce514124SAndreas Brauchli switch (SGP_VERS_PRODUCT(data)) { 471ce514124SAndreas Brauchli case SGP30: 472ce514124SAndreas Brauchli data->measure_interval_jiffies = SGP30_MEASURE_INTERVAL_HZ * HZ; 473ce514124SAndreas Brauchli data->measure_iaq_cmd = SGP_CMD_IAQ_MEASURE; 474ce514124SAndreas Brauchli data->measure_gas_signals_cmd = SGP30_CMD_MEASURE_SIGNAL; 475ce514124SAndreas Brauchli data->product_id = SGP30; 476ce514124SAndreas Brauchli data->iaq_defval_skip_jiffies = 15 * HZ; 477ce514124SAndreas Brauchli break; 478ce514124SAndreas Brauchli case SGPC3: 479ce514124SAndreas Brauchli data->measure_interval_jiffies = SGPC3_MEASURE_INTERVAL_HZ * HZ; 480ce514124SAndreas Brauchli data->measure_iaq_cmd = SGPC3_CMD_MEASURE_RAW; 481ce514124SAndreas Brauchli data->measure_gas_signals_cmd = SGPC3_CMD_MEASURE_RAW; 482ce514124SAndreas Brauchli data->product_id = SGPC3; 483ce514124SAndreas Brauchli data->iaq_defval_skip_jiffies = 484ce514124SAndreas Brauchli 43 * data->measure_interval_jiffies; 485ce514124SAndreas Brauchli break; 48697d62c34SJonathan Cameron } 487ce514124SAndreas Brauchli } 488ce514124SAndreas Brauchli 489ce514124SAndreas Brauchli static const struct iio_info sgp_info = { 490ce514124SAndreas Brauchli .read_raw = sgp_read_raw, 491ce514124SAndreas Brauchli }; 492ce514124SAndreas Brauchli 493ce514124SAndreas Brauchli static const struct of_device_id sgp_dt_ids[] = { 494ce514124SAndreas Brauchli { .compatible = "sensirion,sgp30", .data = (void *)SGP30 }, 495ce514124SAndreas Brauchli { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 }, 496ce514124SAndreas Brauchli { } 497ce514124SAndreas Brauchli }; 498ce514124SAndreas Brauchli 499ce514124SAndreas Brauchli static int sgp_probe(struct i2c_client *client, 500ce514124SAndreas Brauchli const struct i2c_device_id *id) 501ce514124SAndreas Brauchli { 502cb26d236SJonathan Cameron struct device *dev = &client->dev; 503ce514124SAndreas Brauchli struct iio_dev *indio_dev; 504ce514124SAndreas Brauchli struct sgp_data *data; 505ce514124SAndreas Brauchli unsigned long product_id; 506ce514124SAndreas Brauchli int ret; 507ce514124SAndreas Brauchli 508cb26d236SJonathan Cameron indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 509ce514124SAndreas Brauchli if (!indio_dev) 510ce514124SAndreas Brauchli return -ENOMEM; 511ce514124SAndreas Brauchli 5126ac282edSJonathan Cameron if (dev_fwnode(dev)) 5136ac282edSJonathan Cameron product_id = (unsigned long)device_get_match_data(dev); 514ce514124SAndreas Brauchli else 515ce514124SAndreas Brauchli product_id = id->driver_data; 516ce514124SAndreas Brauchli 517ce514124SAndreas Brauchli data = iio_priv(indio_dev); 518ce514124SAndreas Brauchli i2c_set_clientdata(client, indio_dev); 519ce514124SAndreas Brauchli data->client = client; 520ce514124SAndreas Brauchli crc8_populate_msb(sgp_crc8_table, SGP_CRC8_POLYNOMIAL); 521ce514124SAndreas Brauchli mutex_init(&data->data_lock); 522ce514124SAndreas Brauchli 523ce514124SAndreas Brauchli /* get feature set version and write it to client data */ 524ce514124SAndreas Brauchli ret = sgp_read_cmd(data, SGP_CMD_GET_FEATURE_SET, &data->buffer, 1, 525ce514124SAndreas Brauchli SGP_CMD_DURATION_US); 526ce514124SAndreas Brauchli if (ret < 0) 527ce514124SAndreas Brauchli return ret; 528ce514124SAndreas Brauchli 529ce514124SAndreas Brauchli data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value); 530ce514124SAndreas Brauchli 531ce514124SAndreas Brauchli ret = sgp_check_compat(data, product_id); 532ce514124SAndreas Brauchli if (ret) 533ce514124SAndreas Brauchli return ret; 534ce514124SAndreas Brauchli 535ce514124SAndreas Brauchli indio_dev->info = &sgp_info; 536ce514124SAndreas Brauchli indio_dev->name = id->name; 537ce514124SAndreas Brauchli indio_dev->modes = INDIO_DIRECT_MODE; 538ce514124SAndreas Brauchli indio_dev->channels = sgp_devices[product_id].channels; 539ce514124SAndreas Brauchli indio_dev->num_channels = sgp_devices[product_id].num_channels; 540ce514124SAndreas Brauchli 541ce514124SAndreas Brauchli sgp_init(data); 542ce514124SAndreas Brauchli 543cb26d236SJonathan Cameron ret = devm_iio_device_register(dev, indio_dev); 544ce514124SAndreas Brauchli if (ret) { 545cb26d236SJonathan Cameron dev_err(dev, "failed to register iio device\n"); 546ce514124SAndreas Brauchli return ret; 547ce514124SAndreas Brauchli } 548ce514124SAndreas Brauchli 549ce514124SAndreas Brauchli data->iaq_thread = kthread_run(sgp_iaq_threadfn, data, 550ce514124SAndreas Brauchli "%s-iaq", data->client->name); 551ce514124SAndreas Brauchli 552ce514124SAndreas Brauchli return 0; 553ce514124SAndreas Brauchli } 554ce514124SAndreas Brauchli 555ce514124SAndreas Brauchli static int sgp_remove(struct i2c_client *client) 556ce514124SAndreas Brauchli { 557ce514124SAndreas Brauchli struct iio_dev *indio_dev = i2c_get_clientdata(client); 558ce514124SAndreas Brauchli struct sgp_data *data = iio_priv(indio_dev); 559ce514124SAndreas Brauchli 560ce514124SAndreas Brauchli if (data->iaq_thread) 561ce514124SAndreas Brauchli kthread_stop(data->iaq_thread); 562ce514124SAndreas Brauchli 563ce514124SAndreas Brauchli return 0; 564ce514124SAndreas Brauchli } 565ce514124SAndreas Brauchli 566ce514124SAndreas Brauchli static const struct i2c_device_id sgp_id[] = { 567ce514124SAndreas Brauchli { "sgp30", SGP30 }, 568ce514124SAndreas Brauchli { "sgpc3", SGPC3 }, 569ce514124SAndreas Brauchli { } 570ce514124SAndreas Brauchli }; 571ce514124SAndreas Brauchli 572ce514124SAndreas Brauchli MODULE_DEVICE_TABLE(i2c, sgp_id); 573ce514124SAndreas Brauchli MODULE_DEVICE_TABLE(of, sgp_dt_ids); 574ce514124SAndreas Brauchli 575ce514124SAndreas Brauchli static struct i2c_driver sgp_driver = { 576ce514124SAndreas Brauchli .driver = { 577ce514124SAndreas Brauchli .name = "sgp30", 5786ac282edSJonathan Cameron .of_match_table = sgp_dt_ids, 579ce514124SAndreas Brauchli }, 580ce514124SAndreas Brauchli .probe = sgp_probe, 581ce514124SAndreas Brauchli .remove = sgp_remove, 582ce514124SAndreas Brauchli .id_table = sgp_id, 583ce514124SAndreas Brauchli }; 584ce514124SAndreas Brauchli module_i2c_driver(sgp_driver); 585ce514124SAndreas Brauchli 586ce514124SAndreas Brauchli MODULE_AUTHOR("Andreas Brauchli <andreas.brauchli@sensirion.com>"); 587ce514124SAndreas Brauchli MODULE_AUTHOR("Pascal Sachs <pascal.sachs@sensirion.com>"); 588ce514124SAndreas Brauchli MODULE_DESCRIPTION("Sensirion SGP gas sensors"); 589ce514124SAndreas Brauchli MODULE_LICENSE("GPL v2"); 590