File Index
Files and directories
Sign in
FILE

sunrise_co2.c

File preview with syntax highlighting.

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