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