538 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Senseair Sunrise 006-0-0007 CO2 sensor driver.4 *5 * Copyright (C) 2021 Jacopo Mondi6 *7 * List of features not yet supported by the driver:8 * - controllable EN pin9 * - single-shot operations using the nDRY pin.10 * - ABC/target calibration11 */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 0x0027#define SUNRISE_CO2_FILTERED_COMP_REG 0x0628#define SUNRISE_CHIP_TEMPERATURE_REG 0x0829#define SUNRISE_CALIBRATION_STATUS_REG 0x8130#define SUNRISE_CALIBRATION_COMMAND_REG 0x8231#define SUNRISE_CALIBRATION_FACTORY_CMD 0x7c0232#define SUNRISE_CALIBRATION_BACKGROUND_CMD 0x7c0633/*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 without68 * 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 the115 * wake up session. Use custom regmap operations that perform unlocked access to116 * 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 reads231 * 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 CO2439 * (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 support505 * protocol mangling do not set the I2C_M_IGNORE_NAK flag at the expense506 * 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 = 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");538