// SPDX-License-Identifier: GPL-2.0 /* * Senseair Sunrise 006-0-0007 CO2 sensor driver. * * Copyright (C) 2021 Jacopo Mondi * * List of features not yet supported by the driver: * - controllable EN pin * - single-shot operations using the nDRY pin. * - ABC/target calibration
*/
/* Custom regmap read/write operations: perform unlocked access to the i2c bus. */
staticint sunrise_regmap_read(void *context, constvoid *reg_buf,
size_t reg_size, void *val_buf, size_t val_size)
{ struct i2c_client *client = context; struct sunrise_dev *sunrise = i2c_get_clientdata(client); union i2c_smbus_data data = { }; int ret;
if (reg_size != 1 || !val_size) return -EINVAL;
data.block[0] = val_size;
/* * Wake up sensor by sending sensor address: START, sensor address, * STOP. Sensor will not ACK this byte. * * The chip enters a low power state after 15ms without * communications or after a complete read/write sequence.
*/
__i2c_smbus_xfer(client->adapter, client->addr,
sunrise->ignore_nak ? I2C_M_IGNORE_NAK : 0,
I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE_DATA, &data);
usleep_range(500, 1500);
ret = __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
I2C_SMBUS_READ, ((u8 *)reg_buf)[0],
I2C_SMBUS_I2C_BLOCK_DATA, &data); if (ret < 0) return ret;
/* Reset the calibration status reg. */
ret = sunrise_write_byte(sunrise, SUNRISE_CALIBRATION_STATUS_REG, 0x00); if (ret) return ret;
/* Write a calibration command and poll the calibration status bit. */
ret = sunrise_write_word(sunrise, SUNRISE_CALIBRATION_COMMAND_REG, data->cmd); if (ret) return ret;
dev_dbg(&sunrise->client->dev, "%s in progress\n", data->name);
/* * Calibration takes several seconds, so the sleep time between reads * can be pretty relaxed.
*/ return read_poll_timeout(sunrise_read_byte, status, status & data->bit,
200000, SUNRISE_CALIBRATION_TIMEOUT_US, false,
sunrise, SUNRISE_CALIBRATION_STATUS_REG);
}
ret = kstrtobool(buf, &enable); if (ret) return ret;
if (!enable) return len;
mutex_lock(&sunrise->lock);
ret = sunrise_calibrate(sunrise, &calib_data[SUNRISE_CALIBRATION_FACTORY]);
mutex_unlock(&sunrise->lock); if (ret) return ret;
ret = kstrtobool(buf, &enable); if (ret) return ret;
if (!enable) return len;
mutex_lock(&sunrise->lock);
ret = sunrise_calibrate(sunrise, &calib_data[SUNRISE_CALIBRATION_BACKGROUND]);
mutex_unlock(&sunrise->lock); if (ret) return ret;
staticint sunrise_read_raw(struct iio_dev *iio_dev, conststruct iio_chan_spec *chan, int *val, int *val2, long mask)
{ struct sunrise_dev *sunrise = iio_priv(iio_dev);
u16 value; int ret;
switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_CONCENTRATION:
mutex_lock(&sunrise->lock);
ret = sunrise_read_word(sunrise, SUNRISE_CO2_FILTERED_COMP_REG,
&value);
mutex_unlock(&sunrise->lock);
if (ret) return ret;
*val = value; return IIO_VAL_INT;
case IIO_TEMP:
mutex_lock(&sunrise->lock);
ret = sunrise_read_word(sunrise, SUNRISE_CHIP_TEMPERATURE_REG,
&value);
mutex_unlock(&sunrise->lock);
if (ret) return ret;
*val = value; return IIO_VAL_INT;
default: return -EINVAL;
}
case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_CONCENTRATION: /* * 1 / 10^4 to comply with IIO scale for CO2 * (percentage). The chip CO2 reading range is [400 - * 5000] ppm which corresponds to [0,004 - 0,5] %.
*/
*val = 1;
*val2 = 10000; return IIO_VAL_FRACTIONAL;
case IIO_TEMP: /* x10 to comply with IIO scale (millidegrees celsius). */
*val = 10; return IIO_VAL_INT;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA)) {
dev_err(&client->dev, "Adapter does not support required functionalities\n"); return -EOPNOTSUPP;
}
iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*sunrise)); if (!iio_dev) return -ENOMEM;
sunrise->regmap = devm_regmap_init(&client->dev, &sunrise_regmap_bus,
client, &sunrise_regmap_config); if (IS_ERR(sunrise->regmap)) {
dev_err(&client->dev, "Failed to initialize regmap\n"); return PTR_ERR(sunrise->regmap);
}
/* * The chip nacks the wake up message. If the adapter does not support * protocol mangling do not set the I2C_M_IGNORE_NAK flag at the expense * of possible cruft in the logs.
*/ if (i2c_check_functionality(client->adapter, I2C_FUNC_PROTOCOL_MANGLING))
sunrise->ignore_nak = true;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.