• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
39 struct 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 
sunrise_regmap_read(void * context,const void * reg_buf,size_t reg_size,void * val_buf,size_t val_size)49 static 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 
sunrise_regmap_write(void * context,const void * val_buf,size_t count)87 static 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  */
sunrise_read_byte(struct sunrise_dev * sunrise,u8 reg)118 static 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 
sunrise_read_word(struct sunrise_dev * sunrise,u8 reg,u16 * val)136 static 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 
sunrise_write_byte(struct sunrise_dev * sunrise,u8 reg,u8 val)156 static 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 
sunrise_write_word(struct sunrise_dev * sunrise,u8 reg,u16 data)171 static 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 
189 enum {
190 	SUNRISE_CALIBRATION_FACTORY,
191 	SUNRISE_CALIBRATION_BACKGROUND,
192 };
193 
194 static 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 
sunrise_calibrate(struct sunrise_dev * sunrise,const struct sunrise_calib_data * data)211 static 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 
sunrise_cal_factory_write(struct iio_dev * iiodev,uintptr_t private,const struct iio_chan_spec * chan,const char * buf,size_t len)238 static 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 
sunrise_cal_background_write(struct iio_dev * iiodev,uintptr_t private,const struct iio_chan_spec * chan,const char * buf,size_t len)263 static 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. */
289 enum {
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 
302 static 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 
315 static const struct iio_enum sunrise_error_statuses_enum = {
316 	.items = sunrise_error_statuses,
317 	.num_items = ARRAY_SIZE(sunrise_error_statuses),
318 };
319 
sunrise_error_status_read(struct iio_dev * iiodev,uintptr_t private,const struct iio_chan_spec * chan,char * buf)320 static 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 
351 static 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 
379 static 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 
sunrise_read_raw(struct iio_dev * iio_dev,const struct iio_chan_spec * chan,int * val,int * val2,long mask)395 static 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 
460 static const struct iio_info sunrise_info = {
461 	.read_raw = sunrise_read_raw,
462 };
463 
464 static const struct regmap_bus sunrise_regmap_bus = {
465 	.read = sunrise_regmap_read,
466 	.write = sunrise_regmap_write,
467 };
468 
469 static const struct regmap_config sunrise_regmap_config = {
470 	.reg_bits = 8,
471 	.val_bits = 8,
472 };
473 
sunrise_probe(struct i2c_client * client)474 static 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 
520 static const struct of_device_id sunrise_of_match[] = {
521 	{ .compatible = "senseair,sunrise-006-0-0007" },
522 	{}
523 };
524 MODULE_DEVICE_TABLE(of, sunrise_of_match);
525 
526 static struct i2c_driver sunrise_driver = {
527 	.driver = {
528 		.name = DRIVER_NAME,
529 		.of_match_table = sunrise_of_match,
530 	},
531 	.probe = sunrise_probe,
532 };
533 module_i2c_driver(sunrise_driver);
534 
535 MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
536 MODULE_DESCRIPTION("Senseair Sunrise 006-0-0007 CO2 sensor IIO driver");
537 MODULE_LICENSE("GPL v2");
538