Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");