cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sunrise_co2.c (13583B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Senseair Sunrise 006-0-0007 CO2 sensor driver.
      4 *
      5 * Copyright (C) 2021 Jacopo Mondi
      6 *
      7 * List of features not yet supported by the driver:
      8 * - controllable EN pin
      9 * - single-shot operations using the nDRY pin.
     10 * - ABC/target calibration
     11 */
     12
     13#include <linux/bitops.h>
     14#include <linux/i2c.h>
     15#include <linux/kernel.h>
     16#include <linux/mod_devicetable.h>
     17#include <linux/module.h>
     18#include <linux/mutex.h>
     19#include <linux/regmap.h>
     20#include <linux/time64.h>
     21
     22#include <linux/iio/iio.h>
     23
     24#define DRIVER_NAME "sunrise_co2"
     25
     26#define SUNRISE_ERROR_STATUS_REG		0x00
     27#define SUNRISE_CO2_FILTERED_COMP_REG		0x06
     28#define SUNRISE_CHIP_TEMPERATURE_REG		0x08
     29#define SUNRISE_CALIBRATION_STATUS_REG		0x81
     30#define SUNRISE_CALIBRATION_COMMAND_REG		0x82
     31#define SUNRISE_CALIBRATION_FACTORY_CMD		0x7c02
     32#define SUNRISE_CALIBRATION_BACKGROUND_CMD	0x7c06
     33/*
     34 * The calibration timeout is not characterized in the datasheet.
     35 * Use 30 seconds as a reasonable upper limit.
     36 */
     37#define SUNRISE_CALIBRATION_TIMEOUT_US		(30 * USEC_PER_SEC)
     38
     39struct sunrise_dev {
     40	struct i2c_client *client;
     41	struct regmap *regmap;
     42	/* Protects access to IIO attributes. */
     43	struct mutex lock;
     44	bool ignore_nak;
     45};
     46
     47/* Custom regmap read/write operations: perform unlocked access to the i2c bus. */
     48
     49static int sunrise_regmap_read(void *context, const void *reg_buf,
     50			       size_t reg_size, void *val_buf, size_t val_size)
     51{
     52	struct i2c_client *client = context;
     53	struct sunrise_dev *sunrise = i2c_get_clientdata(client);
     54	union i2c_smbus_data data;
     55	int ret;
     56
     57	if (reg_size != 1 || !val_size)
     58		return -EINVAL;
     59
     60	memset(&data, 0, sizeof(data));
     61	data.block[0] = val_size;
     62
     63	/*
     64	 * Wake up sensor by sending sensor address: START, sensor address,
     65	 * STOP. Sensor will not ACK this byte.
     66	 *
     67	 * The chip enters a low power state after 15ms without
     68	 * communications or after a complete read/write sequence.
     69	 */
     70	__i2c_smbus_xfer(client->adapter, client->addr,
     71			 sunrise->ignore_nak ? I2C_M_IGNORE_NAK : 0,
     72			 I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE_DATA, &data);
     73
     74	usleep_range(500, 1500);
     75
     76	ret = __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
     77			       I2C_SMBUS_READ, ((u8 *)reg_buf)[0],
     78			       I2C_SMBUS_I2C_BLOCK_DATA, &data);
     79	if (ret < 0)
     80		return ret;
     81
     82	memcpy(val_buf, &data.block[1], data.block[0]);
     83
     84	return 0;
     85}
     86
     87static int sunrise_regmap_write(void *context, const void *val_buf, size_t count)
     88{
     89	struct i2c_client *client = context;
     90	struct sunrise_dev *sunrise = i2c_get_clientdata(client);
     91	union i2c_smbus_data data;
     92
     93	/* Discard reg address from values count. */
     94	if (!count)
     95		return -EINVAL;
     96	count--;
     97
     98	memset(&data, 0, sizeof(data));
     99	data.block[0] = count;
    100	memcpy(&data.block[1], (u8 *)val_buf + 1, count);
    101
    102	__i2c_smbus_xfer(client->adapter, client->addr,
    103			 sunrise->ignore_nak ? I2C_M_IGNORE_NAK : 0,
    104			 I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE_DATA, &data);
    105
    106	usleep_range(500, 1500);
    107
    108	return __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
    109				I2C_SMBUS_WRITE, ((u8 *)val_buf)[0],
    110				I2C_SMBUS_I2C_BLOCK_DATA, &data);
    111}
    112
    113/*
    114 * Sunrise i2c read/write operations: lock the i2c segment to avoid losing the
    115 * wake up session. Use custom regmap operations that perform unlocked access to
    116 * the i2c bus.
    117 */
    118static int sunrise_read_byte(struct sunrise_dev *sunrise, u8 reg)
    119{
    120	const struct i2c_client *client = sunrise->client;
    121	const struct device *dev = &client->dev;
    122	unsigned int val;
    123	int ret;
    124
    125	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
    126	ret = regmap_read(sunrise->regmap, reg, &val);
    127	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
    128	if (ret) {
    129		dev_err(dev, "Read byte failed: reg 0x%02x (%d)\n", reg, ret);
    130		return ret;
    131	}
    132
    133	return val;
    134}
    135
    136static int sunrise_read_word(struct sunrise_dev *sunrise, u8 reg, u16 *val)
    137{
    138	const struct i2c_client *client = sunrise->client;
    139	const struct device *dev = &client->dev;
    140	__be16 be_val;
    141	int ret;
    142
    143	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
    144	ret = regmap_bulk_read(sunrise->regmap, reg, &be_val, sizeof(be_val));
    145	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
    146	if (ret) {
    147		dev_err(dev, "Read word failed: reg 0x%02x (%d)\n", reg, ret);
    148		return ret;
    149	}
    150
    151	*val = be16_to_cpu(be_val);
    152
    153	return 0;
    154}
    155
    156static int sunrise_write_byte(struct sunrise_dev *sunrise, u8 reg, u8 val)
    157{
    158	const struct i2c_client *client = sunrise->client;
    159	const struct device *dev = &client->dev;
    160	int ret;
    161
    162	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
    163	ret = regmap_write(sunrise->regmap, reg, val);
    164	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
    165	if (ret)
    166		dev_err(dev, "Write byte failed: reg 0x%02x (%d)\n", reg, ret);
    167
    168	return ret;
    169}
    170
    171static int sunrise_write_word(struct sunrise_dev *sunrise, u8 reg, u16 data)
    172{
    173	const struct i2c_client *client = sunrise->client;
    174	const struct device *dev = &client->dev;
    175	__be16 be_data = cpu_to_be16(data);
    176	int ret;
    177
    178	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
    179	ret = regmap_bulk_write(sunrise->regmap, reg, &be_data, sizeof(be_data));
    180	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
    181	if (ret)
    182		dev_err(dev, "Write word failed: reg 0x%02x (%d)\n", reg, ret);
    183
    184	return ret;
    185}
    186
    187/* Trigger a calibration cycle. */
    188
    189enum {
    190	SUNRISE_CALIBRATION_FACTORY,
    191	SUNRISE_CALIBRATION_BACKGROUND,
    192};
    193
    194static const struct sunrise_calib_data {
    195	u16 cmd;
    196	u8 bit;
    197	const char * const name;
    198} calib_data[] = {
    199	[SUNRISE_CALIBRATION_FACTORY] = {
    200		SUNRISE_CALIBRATION_FACTORY_CMD,
    201		BIT(2),
    202		"factory_calibration",
    203	},
    204	[SUNRISE_CALIBRATION_BACKGROUND] = {
    205		SUNRISE_CALIBRATION_BACKGROUND_CMD,
    206		BIT(5),
    207		"background_calibration",
    208	},
    209};
    210
    211static int sunrise_calibrate(struct sunrise_dev *sunrise,
    212			     const struct sunrise_calib_data *data)
    213{
    214	unsigned int status;
    215	int ret;
    216
    217	/* Reset the calibration status reg. */
    218	ret = sunrise_write_byte(sunrise, SUNRISE_CALIBRATION_STATUS_REG, 0x00);
    219	if (ret)
    220		return ret;
    221
    222	/* Write a calibration command and poll the calibration status bit. */
    223	ret = sunrise_write_word(sunrise, SUNRISE_CALIBRATION_COMMAND_REG, data->cmd);
    224	if (ret)
    225		return ret;
    226
    227	dev_dbg(&sunrise->client->dev, "%s in progress\n", data->name);
    228
    229	/*
    230	 * Calibration takes several seconds, so the sleep time between reads
    231	 * can be pretty relaxed.
    232	 */
    233	return read_poll_timeout(sunrise_read_byte, status, status & data->bit,
    234				 200000, SUNRISE_CALIBRATION_TIMEOUT_US, false,
    235				 sunrise, SUNRISE_CALIBRATION_STATUS_REG);
    236}
    237
    238static ssize_t sunrise_cal_factory_write(struct iio_dev *iiodev,
    239					 uintptr_t private,
    240					 const struct iio_chan_spec *chan,
    241					 const char *buf, size_t len)
    242{
    243	struct sunrise_dev *sunrise = iio_priv(iiodev);
    244	bool enable;
    245	int ret;
    246
    247	ret = kstrtobool(buf, &enable);
    248	if (ret)
    249		return ret;
    250
    251	if (!enable)
    252		return len;
    253
    254	mutex_lock(&sunrise->lock);
    255	ret = sunrise_calibrate(sunrise, &calib_data[SUNRISE_CALIBRATION_FACTORY]);
    256	mutex_unlock(&sunrise->lock);
    257	if (ret)
    258		return ret;
    259
    260	return len;
    261}
    262
    263static ssize_t sunrise_cal_background_write(struct iio_dev *iiodev,
    264					    uintptr_t private,
    265					    const struct iio_chan_spec *chan,
    266					    const char *buf, size_t len)
    267{
    268	struct sunrise_dev *sunrise = iio_priv(iiodev);
    269	bool enable;
    270	int ret;
    271
    272	ret = kstrtobool(buf, &enable);
    273	if (ret)
    274		return ret;
    275
    276	if (!enable)
    277		return len;
    278
    279	mutex_lock(&sunrise->lock);
    280	ret = sunrise_calibrate(sunrise, &calib_data[SUNRISE_CALIBRATION_BACKGROUND]);
    281	mutex_unlock(&sunrise->lock);
    282	if (ret)
    283		return ret;
    284
    285	return len;
    286}
    287
    288 /* Enumerate and retrieve the chip error status. */
    289enum {
    290	SUNRISE_ERROR_FATAL,
    291	SUNRISE_ERROR_I2C,
    292	SUNRISE_ERROR_ALGORITHM,
    293	SUNRISE_ERROR_CALIBRATION,
    294	SUNRISE_ERROR_SELF_DIAGNOSTIC,
    295	SUNRISE_ERROR_OUT_OF_RANGE,
    296	SUNRISE_ERROR_MEMORY,
    297	SUNRISE_ERROR_NO_MEASUREMENT,
    298	SUNRISE_ERROR_LOW_VOLTAGE,
    299	SUNRISE_ERROR_MEASUREMENT_TIMEOUT,
    300};
    301
    302static const char * const sunrise_error_statuses[] = {
    303	[SUNRISE_ERROR_FATAL] = "error_fatal",
    304	[SUNRISE_ERROR_I2C] = "error_i2c",
    305	[SUNRISE_ERROR_ALGORITHM] = "error_algorithm",
    306	[SUNRISE_ERROR_CALIBRATION] = "error_calibration",
    307	[SUNRISE_ERROR_SELF_DIAGNOSTIC] = "error_self_diagnostic",
    308	[SUNRISE_ERROR_OUT_OF_RANGE] = "error_out_of_range",
    309	[SUNRISE_ERROR_MEMORY] = "error_memory",
    310	[SUNRISE_ERROR_NO_MEASUREMENT] = "error_no_measurement",
    311	[SUNRISE_ERROR_LOW_VOLTAGE] = "error_low_voltage",
    312	[SUNRISE_ERROR_MEASUREMENT_TIMEOUT] = "error_measurement_timeout",
    313};
    314
    315static const struct iio_enum sunrise_error_statuses_enum = {
    316	.items = sunrise_error_statuses,
    317	.num_items = ARRAY_SIZE(sunrise_error_statuses),
    318};
    319
    320static ssize_t sunrise_error_status_read(struct iio_dev *iiodev,
    321					 uintptr_t private,
    322					 const struct iio_chan_spec *chan,
    323					 char *buf)
    324{
    325	struct sunrise_dev *sunrise = iio_priv(iiodev);
    326	unsigned long errors;
    327	ssize_t len = 0;
    328	u16 value;
    329	int ret;
    330	u8 i;
    331
    332	mutex_lock(&sunrise->lock);
    333	ret = sunrise_read_word(sunrise, SUNRISE_ERROR_STATUS_REG, &value);
    334	if (ret) {
    335		mutex_unlock(&sunrise->lock);
    336		return ret;
    337	}
    338
    339	errors = value;
    340	for_each_set_bit(i, &errors, ARRAY_SIZE(sunrise_error_statuses))
    341		len += sysfs_emit_at(buf, len, "%s ", sunrise_error_statuses[i]);
    342
    343	if (len)
    344		buf[len - 1] = '\n';
    345
    346	mutex_unlock(&sunrise->lock);
    347
    348	return len;
    349}
    350
    351static const struct iio_chan_spec_ext_info sunrise_concentration_ext_info[] = {
    352	/* Calibration triggers. */
    353	{
    354		.name = "calibration_factory",
    355		.write = sunrise_cal_factory_write,
    356		.shared = IIO_SEPARATE,
    357	},
    358	{
    359		.name = "calibration_background",
    360		.write = sunrise_cal_background_write,
    361		.shared = IIO_SEPARATE,
    362	},
    363
    364	/* Error statuses. */
    365	{
    366		.name = "error_status",
    367		.read = sunrise_error_status_read,
    368		.shared = IIO_SHARED_BY_ALL,
    369	},
    370	{
    371		.name = "error_status_available",
    372		.shared = IIO_SHARED_BY_ALL,
    373		.read = iio_enum_available_read,
    374		.private = (uintptr_t)&sunrise_error_statuses_enum,
    375	},
    376	{}
    377};
    378
    379static const struct iio_chan_spec sunrise_channels[] = {
    380	{
    381		.type = IIO_CONCENTRATION,
    382		.modified = 1,
    383		.channel2 = IIO_MOD_CO2,
    384		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    385				      BIT(IIO_CHAN_INFO_SCALE),
    386		.ext_info = sunrise_concentration_ext_info,
    387	},
    388	{
    389		.type = IIO_TEMP,
    390		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    391				      BIT(IIO_CHAN_INFO_SCALE),
    392	},
    393};
    394
    395static int sunrise_read_raw(struct iio_dev *iio_dev,
    396			    const struct iio_chan_spec *chan,
    397			    int *val, int *val2, long mask)
    398{
    399	struct sunrise_dev *sunrise = iio_priv(iio_dev);
    400	u16 value;
    401	int ret;
    402
    403	switch (mask) {
    404	case IIO_CHAN_INFO_RAW:
    405		switch (chan->type) {
    406		case IIO_CONCENTRATION:
    407			mutex_lock(&sunrise->lock);
    408			ret = sunrise_read_word(sunrise, SUNRISE_CO2_FILTERED_COMP_REG,
    409						&value);
    410			mutex_unlock(&sunrise->lock);
    411
    412			if (ret)
    413				return ret;
    414
    415			*val = value;
    416			return IIO_VAL_INT;
    417
    418		case IIO_TEMP:
    419			mutex_lock(&sunrise->lock);
    420			ret = sunrise_read_word(sunrise, SUNRISE_CHIP_TEMPERATURE_REG,
    421						&value);
    422			mutex_unlock(&sunrise->lock);
    423
    424			if (ret)
    425				return ret;
    426
    427			*val = value;
    428			return IIO_VAL_INT;
    429
    430		default:
    431			return -EINVAL;
    432		}
    433
    434	case IIO_CHAN_INFO_SCALE:
    435		switch (chan->type) {
    436		case IIO_CONCENTRATION:
    437			/*
    438			 * 1 / 10^4 to comply with IIO scale for CO2
    439			 * (percentage). The chip CO2 reading range is [400 -
    440			 * 5000] ppm which corresponds to [0,004 - 0,5] %.
    441			 */
    442			*val = 1;
    443			*val2 = 10000;
    444			return IIO_VAL_FRACTIONAL;
    445
    446		case IIO_TEMP:
    447			/* x10 to comply with IIO scale (millidegrees celsius). */
    448			*val = 10;
    449			return IIO_VAL_INT;
    450
    451		default:
    452			return -EINVAL;
    453		}
    454
    455	default:
    456		return -EINVAL;
    457	}
    458}
    459
    460static const struct iio_info sunrise_info = {
    461	.read_raw = sunrise_read_raw,
    462};
    463
    464static const struct regmap_bus sunrise_regmap_bus = {
    465	.read = sunrise_regmap_read,
    466	.write = sunrise_regmap_write,
    467};
    468
    469static const struct regmap_config sunrise_regmap_config = {
    470	.reg_bits = 8,
    471	.val_bits = 8,
    472};
    473
    474static int sunrise_probe(struct i2c_client *client)
    475{
    476	struct sunrise_dev *sunrise;
    477	struct iio_dev *iio_dev;
    478
    479	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
    480						      I2C_FUNC_SMBUS_BLOCK_DATA)) {
    481		dev_err(&client->dev,
    482			"Adapter does not support required functionalities\n");
    483		return -EOPNOTSUPP;
    484	}
    485
    486	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*sunrise));
    487	if (!iio_dev)
    488		return -ENOMEM;
    489
    490	sunrise = iio_priv(iio_dev);
    491	sunrise->client = client;
    492	mutex_init(&sunrise->lock);
    493
    494	i2c_set_clientdata(client, sunrise);
    495
    496	sunrise->regmap = devm_regmap_init(&client->dev, &sunrise_regmap_bus,
    497					   client, &sunrise_regmap_config);
    498	if (IS_ERR(sunrise->regmap)) {
    499		dev_err(&client->dev, "Failed to initialize regmap\n");
    500		return PTR_ERR(sunrise->regmap);
    501	}
    502
    503	/*
    504	 * The chip nacks the wake up message. If the adapter does not support
    505	 * protocol mangling do not set the I2C_M_IGNORE_NAK flag at the expense
    506	 * of possible cruft in the logs.
    507	 */
    508	if (i2c_check_functionality(client->adapter, I2C_FUNC_PROTOCOL_MANGLING))
    509		sunrise->ignore_nak = true;
    510
    511	iio_dev->info = &sunrise_info;
    512	iio_dev->name = DRIVER_NAME;
    513	iio_dev->channels = sunrise_channels;
    514	iio_dev->num_channels = ARRAY_SIZE(sunrise_channels);
    515	iio_dev->modes = INDIO_DIRECT_MODE;
    516
    517	return devm_iio_device_register(&client->dev, iio_dev);
    518}
    519
    520static const struct of_device_id sunrise_of_match[] = {
    521	{ .compatible = "senseair,sunrise-006-0-0007" },
    522	{}
    523};
    524MODULE_DEVICE_TABLE(of, sunrise_of_match);
    525
    526static struct i2c_driver sunrise_driver = {
    527	.driver = {
    528		.name = DRIVER_NAME,
    529		.of_match_table = sunrise_of_match,
    530	},
    531	.probe_new = sunrise_probe,
    532};
    533module_i2c_driver(sunrise_driver);
    534
    535MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
    536MODULE_DESCRIPTION("Senseair Sunrise 006-0-0007 CO2 sensor IIO driver");
    537MODULE_LICENSE("GPL v2");