Re: [PATCH v2 3/6] iio: chemical: add driver for ENS160 sensor

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 28 May 2024 21:14:20 -0300
Gustavo Silva <gustavograzs@xxxxxxxxx> wrote:

> ScioSense ENS160 is a digital metal oxide multi-gas sensor, designed
> for indoor air quality monitoring. The driver supports readings of
> CO2 and VOC, and can be accessed via both SPI and I2C.
> 
> Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
> 
> Signed-off-by: Gustavo Silva <gustavograzs@xxxxxxxxx>
Hi Gustavo,

A few more comments inline.

Jonathan

> diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
> new file mode 100644
> index 000000000..a535f62c4
> --- /dev/null
> +++ b/drivers/iio/chemical/ens160_core.c
> @@ -0,0 +1,221 @@

...

> +static void ens160_set_idle(void *data)
> +{
> +	ens160_set_mode(data, ENS160_REG_MODE_IDLE);
> +}
> +
> +static int ens160_chip_init(struct ens160_data *data)
> +{
> +	struct device *dev = regmap_get_device(data->regmap);
> +	unsigned int status;
> +	int ret;
> +
> +	ret = ens160_set_mode(data, ENS160_REG_MODE_RESET);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_bulk_read(data->regmap, ENS160_REG_PART_ID, &data->buf,
> +			       sizeof(data->buf));
> +	if (ret)
> +		return ret;
> +
> +	if (le16_to_cpu(data->buf) != ENS160_PART_ID)
> +		return -ENODEV;
> +
> +	ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
> +			   ENS160_REG_COMMAND_CLRGPR);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
> +			   ENS160_REG_COMMAND_GET_APPVER);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_bulk_read(data->regmap, ENS160_REG_GPR_READ4,
> +			       data->fw_version, sizeof(data->fw_version));
> +	if (ret)
> +		return ret;
> +
> +	dev_info(dev, "firmware version: %u.%u.%u\n", data->fw_version[2],
> +		 data->fw_version[1], data->fw_version[0]);
> +
> +	ret = ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
> +	if (ret)
> +		return ret;

I'd expect to see the devm code to set this to IDLE registered here
not before this function is called.  If it makes sense after reset
then register it there.

> +
> +	ret = regmap_read(data->regmap, ENS160_REG_DEVICE_STATUS, &status);
> +	if (ret)
> +		return ret;
> +
> +	if (FIELD_GET(ENS160_STATUS_VALIDITY_FLAG, status)
> +	    != ENS160_STATUS_NORMAL)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static const struct iio_info ens160_info = {
> +	.read_raw = ens160_read_raw,
> +};
> +
> +int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
> +			   const char *name)
> +{
> +	struct ens160_data *data;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	data = iio_priv(indio_dev);
> +	data->regmap = regmap;
> +
> +	indio_dev->name = name;
> +	indio_dev->info = &ens160_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = ens160_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(ens160_channels);
> +
> +	ret = devm_add_action_or_reset(dev, ens160_set_idle, data);
What is this 'undoing'?  My guess is this belongs after chip_init.
Note that the expectation is that functions that return error codes
should not have side effects, so you may need to clean up manually
in ens160_chip_init() or move this devm call in there so it's immediately
after whatever it undoing.

> +	if (ret)
> +		return ret;
> +
> +	ret = ens160_chip_init(data);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "chip initialization failed\n");
> +
> +	return devm_iio_device_register(dev, indio_dev);
> +}
> +EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);
> +
> +MODULE_AUTHOR("Gustavo Silva <gustavograzs@xxxxxxxxx>");
> +MODULE_DESCRIPTION("ScioSense ENS160 driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c
> new file mode 100644
> index 000000000..2f0b08e52
> --- /dev/null
> +++ b/drivers/iio/chemical/ens160_i2c.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * ScioSense ENS160 multi-gas sensor I2C driver
> + *
> + * Copyright (c) 2024 Gustavo Silva <gustavograzs@xxxxxxxxx>
> + *
> + * 7-Bit I2C slave address is:
> + *	- 0x52 if ADDR pin LOW
> + *	- 0x53 if ADDR pin HIGH
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +#include "ens160.h"
> +
> +static const struct regmap_config ens160_regmap_i2c_conf = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +};
> +
> +static int ens160_i2c_probe(struct i2c_client *client)
> +{
> +	struct regmap *regmap;
> +
> +	regmap = devm_regmap_init_i2c(client, &ens160_regmap_i2c_conf);
> +	if (IS_ERR(regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(regmap),
> +				     "Failed to register i2c regmap\n");
> +
> +	return devm_ens160_core_probe(&client->dev, regmap, "ens160_i2c");

The user tends not to care if it's spi or i2c + it's easy to tell anyway
by looking at the parent of the iio device. + the ABI is part number, not
part number with a bus prefix so some standard tools may run into problems
with this form.

So drop that _i2c and the _spi one.







[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux