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");