devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense
@ 2024-05-29  0:14 Gustavo Silva
  2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

Add vendor prefix for ScioSense B.V.
https://www.sciosense.com/

Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
---
no changes in v2
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b97d298b3..298f13a0d 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1246,6 +1246,8 @@ patternProperties:
     description: Smart Battery System
   "^schindler,.*":
     description: Schindler
+  "^sciosense,.*":
+    description: ScioSense B.V.
   "^seagate,.*":
     description: Seagate Technology PLC
   "^seeed,.*":

base-commit: 084eeee1d8da6b4712719264b01cb27b41307f54
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
@ 2024-05-29  0:14 ` Gustavo Silva
  2024-05-29  1:42   ` Rob Herring (Arm)
  2024-05-29 16:36   ` Conor Dooley
  2024-05-29  0:14 ` [PATCH v2 3/6] iio: chemical: add driver for " Gustavo Silva
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

Add bindings for ScioSense ENS160 multi-gas sensor.

Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf

Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
---
changes in v2:
 - Add devicetree binding file specifically for this sensor instead of
   adding it to trivial-devices.yaml. This is needed in order to
   document that this chip supports Vdd and Vddio supplies.
 .../iio/chemical/sciosense,ens160.yaml        | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml

diff --git a/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
new file mode 100644
index 000000000..7dd442f94
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ScioSense ENS160 multi-gas sensor
+
+maintainers:
+  - Gustavo Silva <gustavograzs@gmail.com>
+
+description: |
+  Digital Multi-Gas Sensor for Monitoring Indoor Air Quality.
+
+  Datasheet:
+    https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
+
+properties:
+  compatible:
+    enum:
+      - sciosense,ens160
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-supply: true
+  vddio-supply: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      gas-sensor@52 {
+        compatible = "sciosense,ens160";
+        reg = <0x52>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+      };
+    };
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      gas-sensor@0 {
+        compatible = "sciosense,ens160";
+        reg = <0>;
+        spi-max-frequency = <10000000>;
+        interrupt-parent = <&gpio>;
+        interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+      };
+    };
+
+...
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 3/6] iio: chemical: add driver for ENS160 sensor
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
  2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
@ 2024-05-29  0:14 ` Gustavo Silva
  2024-06-02 11:24   ` Jonathan Cameron
  2024-05-29  0:14 ` [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support Gustavo Silva
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

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@gmail.com>
---
changes in v2:
 - Make regmap bulk reads DMA safe by adding buffers to the end of
   iio_priv() struct and marking it __aligned(IIO_DMA_MINALIGN)
 - Remove unnecessary time delays
 - Use devm_add_action_or_reset() to register custom cleanup and delete
   the remove() function
 - Add missing register definition ENS160_REG_DATA_AQI
 - Use dev_err_probe() where applicable
 - Hardcode device name
 - Remove unnecessary dev_set_drvdata() call
 - Do not set driver_data to 0 in {spi,i2c}_device_id structs
 drivers/iio/chemical/Kconfig       |  22 +++
 drivers/iio/chemical/Makefile      |   3 +
 drivers/iio/chemical/ens160.h      |   7 +
 drivers/iio/chemical/ens160_core.c | 221 +++++++++++++++++++++++++++++
 drivers/iio/chemical/ens160_i2c.c  |  60 ++++++++
 drivers/iio/chemical/ens160_spi.c  |  60 ++++++++
 6 files changed, 373 insertions(+)
 create mode 100644 drivers/iio/chemical/ens160.h
 create mode 100644 drivers/iio/chemical/ens160_core.c
 create mode 100644 drivers/iio/chemical/ens160_i2c.c
 create mode 100644 drivers/iio/chemical/ens160_spi.c

diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 02649ab81..e407afab8 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -76,6 +76,28 @@ config CCS811
 	  Say Y here to build I2C interface support for the AMS
 	  CCS811 VOC (Volatile Organic Compounds) sensor
 
+config ENS160
+	tristate "ScioSense ENS160 sensor driver"
+	depends on (I2C || SPI)
+	select REGMAP
+	select ENS160_I2C if I2C
+	select ENS160_SPI if SPI
+	help
+	  Say yes here to build support for ScioSense ENS160 multi-gas sensor.
+
+	  This driver can also be built as a module. If so, the module for I2C
+	  would be called ens160_i2c and ens160_spi for SPI support.
+
+config ENS160_I2C
+	tristate
+	depends on I2C && ENS160
+	select REGMAP_I2C
+
+config ENS160_SPI
+	tristate
+	depends on SPI && ENS160
+	select REGMAP_SPI
+
 config IAQCORE
 	tristate "AMS iAQ-Core VOC sensors"
 	depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 2f3dee8bb..4866db06b 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -11,6 +11,9 @@ obj-$(CONFIG_BME680) += bme680_core.o
 obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
 obj-$(CONFIG_BME680_SPI) += bme680_spi.o
 obj-$(CONFIG_CCS811)		+= ccs811.o
+obj-$(CONFIG_ENS160) += ens160_core.o
+obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o
+obj-$(CONFIG_ENS160_SPI) += ens160_spi.o
 obj-$(CONFIG_IAQCORE)		+= ams-iaq-core.o
 obj-$(CONFIG_PMS7003) += pms7003.o
 obj-$(CONFIG_SCD30_CORE) += scd30_core.o
diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h
new file mode 100644
index 000000000..d0df15f08
--- /dev/null
+++ b/drivers/iio/chemical/ens160.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ENS160_H_
+#define ENS160_H_
+
+int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
+			   const char *name);
+#endif
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 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ScioSense ENS160 multi-gas sensor driver
+ *
+ * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
+ *
+ * Datasheet:
+ *  https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "ens160.h"
+
+#define ENS160_PART_ID 0x160
+
+#define ENS160_BOOTING_TIME_MS 10U
+
+#define ENS160_REG_PART_ID	0x00
+
+#define ENS160_REG_OPMODE	0x10
+
+#define ENS160_REG_MODE_DEEP_SLEEP	0x00
+#define ENS160_REG_MODE_IDLE		0x01
+#define ENS160_REG_MODE_STANDARD	0x02
+#define ENS160_REG_MODE_RESET		0xF0
+
+#define ENS160_REG_COMMAND		0x12
+#define ENS160_REG_COMMAND_GET_APPVER	0x0E
+#define ENS160_REG_COMMAND_CLRGPR	0xCC
+
+#define ENS160_REG_TEMP_IN		0x13
+#define ENS160_REG_RH_IN		0x15
+#define ENS160_REG_DEVICE_STATUS	0x20
+#define ENS160_REG_DATA_AQI		0x21
+#define ENS160_REG_DATA_TVOC		0x22
+#define ENS160_REG_DATA_ECO2		0x24
+#define ENS160_REG_DATA_T		0x30
+#define ENS160_REG_DATA_RH		0x32
+#define ENS160_REG_GPR_READ4		0x4C
+
+#define ENS160_STATUS_VALIDITY_FLAG	GENMASK(3, 2)
+
+#define ENS160_STATUS_NORMAL		0x00
+
+struct ens160_data {
+	struct regmap *regmap;
+	u8 fw_version[3] __aligned(IIO_DMA_MINALIGN);
+	__le16 buf;
+};
+
+static const struct iio_chan_spec ens160_channels[] = {
+	{
+		.type = IIO_CONCENTRATION,
+		.channel2 = IIO_MOD_VOC,
+		.modified = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.address = ENS160_REG_DATA_TVOC,
+	},
+	{
+		.type = IIO_CONCENTRATION,
+		.channel2 = IIO_MOD_CO2,
+		.modified = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.address = ENS160_REG_DATA_ECO2,
+	},
+};
+
+static int ens160_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	struct ens160_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = regmap_bulk_read(data->regmap, chan->address,
+					&data->buf, sizeof(data->buf));
+		if (ret)
+			return ret;
+		*val = le16_to_cpu(data->buf);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->channel2) {
+		case IIO_MOD_CO2:
+			/* The sensor reads CO2 data as ppm */
+			*val = 0;
+			*val2 = 100;
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_MOD_VOC:
+			/* The sensor reads VOC data as ppb */
+			*val = 0;
+			*val2 = 100;
+			return IIO_VAL_INT_PLUS_NANO;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ens160_set_mode(struct ens160_data *data, u8 mode)
+{
+	int ret;
+
+	ret = regmap_write(data->regmap, ENS160_REG_OPMODE, mode);
+	if (ret)
+		return ret;
+
+	msleep(ENS160_BOOTING_TIME_MS);
+
+	return 0;
+}
+
+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;
+
+	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);
+	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@gmail.com>");
+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@gmail.com>
+ *
+ * 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");
+}
+
+static const struct i2c_device_id ens160_i2c_id[] = {
+	{ "ens160" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ens160_i2c_id);
+
+static const struct of_device_id ens160_of_i2c_match[] = {
+	{ .compatible = "sciosense,ens160" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ens160_of_i2c_match);
+
+static struct i2c_driver ens160_i2c_driver = {
+	.driver = {
+		.name		= "ens160_i2c",
+		.of_match_table	= ens160_of_i2c_match,
+	},
+	.probe = ens160_i2c_probe,
+	.id_table = ens160_i2c_id,
+};
+module_i2c_driver(ens160_i2c_driver);
+
+MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
+MODULE_DESCRIPTION("ScioSense ENS160 I2C driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ENS160);
diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c
new file mode 100644
index 000000000..9a6c9c7e3
--- /dev/null
+++ b/drivers/iio/chemical/ens160_spi.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ScioSense ENS160 multi-gas sensor SPI driver
+ *
+ * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "ens160.h"
+
+#define ENS160_SPI_READ BIT(0)
+
+static const struct regmap_config ens160_regmap_spi_conf = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_shift = -1,
+	.read_flag_mask = ENS160_SPI_READ,
+};
+
+static int ens160_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &ens160_regmap_spi_conf);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+				     "Failed to register spi regmap\n");
+
+	return devm_ens160_core_probe(&spi->dev, regmap, "ens160_spi");
+}
+
+static const struct of_device_id ens160_spi_of_match[] = {
+	{ .compatible = "sciosense,ens160" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ens160_spi_of_match);
+
+static const struct spi_device_id ens160_spi_id[] = {
+	{ "ens160" },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ens160_spi_id);
+
+static struct spi_driver ens160_spi_driver = {
+	.driver = {
+		.name	= "ens160_spi",
+		.of_match_table = ens160_spi_of_match,
+	},
+	.probe		= ens160_spi_probe,
+	.id_table	= ens160_spi_id,
+};
+module_spi_driver(ens160_spi_driver);
+
+MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
+MODULE_DESCRIPTION("ScioSense ENS160 SPI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ENS160);
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
  2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
  2024-05-29  0:14 ` [PATCH v2 3/6] iio: chemical: add driver for " Gustavo Silva
@ 2024-05-29  0:14 ` Gustavo Silva
  2024-06-02 11:27   ` Jonathan Cameron
  2024-05-29  0:14 ` [PATCH v2 5/6] iio: chemical: ens160: add power management support Gustavo Silva
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

ENS160 supports a data ready interrupt. Use it in combination with
triggered buffer for continuous data readings.

Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
---
changes in v2:
 - Remove copy of irq variable in device private data. Pass the variable
   directly to the required functions
 - Remove IRQ direction from irqflags in devm_request_threaded_irq()
   call
 - Use iio_trigger_generic_data_rdy_poll instead of custom irq handler
 - In the trigger handler, bulk read all the channels
 drivers/iio/chemical/ens160.h      |   2 +-
 drivers/iio/chemical/ens160_core.c | 144 ++++++++++++++++++++++++++---
 drivers/iio/chemical/ens160_i2c.c  |   3 +-
 drivers/iio/chemical/ens160_spi.c  |   3 +-
 4 files changed, 138 insertions(+), 14 deletions(-)

diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h
index d0df15f08..e6cc0987a 100644
--- a/drivers/iio/chemical/ens160.h
+++ b/drivers/iio/chemical/ens160.h
@@ -2,6 +2,6 @@
 #ifndef ENS160_H_
 #define ENS160_H_
 
-int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
+int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
 			   const char *name);
 #endif
diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
index a535f62c4..74ef7f150 100644
--- a/drivers/iio/chemical/ens160_core.c
+++ b/drivers/iio/chemical/ens160_core.c
@@ -10,6 +10,9 @@
 
 #include <linux/bitfield.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
 
@@ -19,9 +22,14 @@
 
 #define ENS160_BOOTING_TIME_MS 10U
 
-#define ENS160_REG_PART_ID	0x00
+#define ENS160_REG_PART_ID		0x00
 
-#define ENS160_REG_OPMODE	0x10
+#define ENS160_REG_OPMODE		0x10
+
+#define ENS160_REG_CONFIG		0x11
+#define ENS160_REG_CONFIG_INTEN		BIT(0)
+#define ENS160_REG_CONFIG_INTDAT	BIT(1)
+#define ENS160_REG_CONFIG_INT_CFG	BIT(5)
 
 #define ENS160_REG_MODE_DEEP_SLEEP	0x00
 #define ENS160_REG_MODE_IDLE		0x01
@@ -48,7 +56,12 @@
 
 struct ens160_data {
 	struct regmap *regmap;
-	u8 fw_version[3] __aligned(IIO_DMA_MINALIGN);
+	struct mutex mutex;
+	struct {
+		__le16 chans[2];
+		s64 timestamp __aligned(8);
+	} scan __aligned(IIO_DMA_MINALIGN);
+	u8 fw_version[3];
 	__le16 buf;
 };
 
@@ -60,6 +73,13 @@ static const struct iio_chan_spec ens160_channels[] = {
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 				      BIT(IIO_CHAN_INFO_SCALE),
 		.address = ENS160_REG_DATA_TVOC,
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
 	},
 	{
 		.type = IIO_CONCENTRATION,
@@ -68,7 +88,15 @@ static const struct iio_chan_spec ens160_channels[] = {
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 				      BIT(IIO_CHAN_INFO_SCALE),
 		.address = ENS160_REG_DATA_ECO2,
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
 	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
 static int ens160_read_raw(struct iio_dev *indio_dev,
@@ -80,13 +108,16 @@ static int ens160_read_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		ret = regmap_bulk_read(data->regmap, chan->address,
-					&data->buf, sizeof(data->buf));
-		if (ret)
-			return ret;
-		*val = le16_to_cpu(data->buf);
-		return IIO_VAL_INT;
-
+		iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+			guard(mutex)(&data->mutex);
+			ret = regmap_bulk_read(data->regmap, chan->address,
+					       &data->buf, sizeof(data->buf));
+			if (ret)
+				return ret;
+			*val = le16_to_cpu(data->buf);
+			return IIO_VAL_INT;
+		}
+		unreachable();
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->channel2) {
 		case IIO_MOD_CO2:
@@ -184,7 +215,83 @@ static const struct iio_info ens160_info = {
 	.read_raw = ens160_read_raw,
 };
 
-int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
+static irqreturn_t ens160_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ens160_data *data = iio_priv(indio_dev);
+	int ret;
+
+	guard(mutex)(&data->mutex);
+
+	ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC,
+			       data->scan.chans, sizeof(data->scan.chans));
+	if (ret)
+		goto err;
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+					   pf->timestamp);
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int ens160_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct ens160_data *data = iio_priv(indio_dev);
+	unsigned int int_bits = ENS160_REG_CONFIG_INTEN |
+				ENS160_REG_CONFIG_INTDAT |
+				ENS160_REG_CONFIG_INT_CFG;
+
+	if (state)
+		return regmap_set_bits(data->regmap, ENS160_REG_CONFIG,
+				       int_bits);
+	else
+		return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG,
+					 int_bits);
+}
+
+static const struct iio_trigger_ops ens160_trigger_ops = {
+	.set_trigger_state = ens160_set_trigger_state,
+	.validate_device = iio_trigger_validate_own_device,
+};
+
+static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)
+{
+	struct device *dev = indio_dev->dev.parent;
+	struct iio_trigger *trig;
+	int ret;
+
+	trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+				      iio_device_id(indio_dev));
+	if (!trig)
+		return dev_err_probe(dev, -ENOMEM,
+				     "failed to allocate trigger\n");
+
+	trig->ops = &ens160_trigger_ops;
+	iio_trigger_set_drvdata(trig, indio_dev);
+
+	ret = devm_iio_trigger_register(dev, trig);
+	if (ret)
+		return ret;
+
+	indio_dev->trig = iio_trigger_get(trig);
+
+	ret = devm_request_threaded_irq(dev, irq,
+					iio_trigger_generic_data_rdy_poll,
+					NULL,
+					IRQF_ONESHOT,
+					indio_dev->name,
+					indio_dev->trig);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to request irq\n");
+
+	return 0;
+}
+
+int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
 			   const char *name)
 {
 	struct ens160_data *data;
@@ -204,6 +311,13 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
 	indio_dev->channels = ens160_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ens160_channels);
 
+	if (irq > 0) {
+		ret = ens160_setup_trigger(indio_dev, irq);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to setup trigger\n");
+	}
+
 	ret = devm_add_action_or_reset(dev, ens160_set_idle, data);
 	if (ret)
 		return ret;
@@ -212,6 +326,14 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
 	if (ret)
 		return dev_err_probe(dev, ret, "chip initialization failed\n");
 
+	mutex_init(&data->mutex);
+
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+					      iio_pollfunc_store_time,
+					      ens160_trigger_handler, NULL);
+	if (ret)
+		return ret;
+
 	return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);
diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c
index 2f0b08e52..4bf3c455c 100644
--- a/drivers/iio/chemical/ens160_i2c.c
+++ b/drivers/iio/chemical/ens160_i2c.c
@@ -29,7 +29,8 @@ static int ens160_i2c_probe(struct i2c_client *client)
 		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");
+	return devm_ens160_core_probe(&client->dev, regmap, client->irq,
+				      "ens160_i2c");
 }
 
 static const struct i2c_device_id ens160_i2c_id[] = {
diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c
index 9a6c9c7e3..91528c5e3 100644
--- a/drivers/iio/chemical/ens160_spi.c
+++ b/drivers/iio/chemical/ens160_spi.c
@@ -29,7 +29,8 @@ static int ens160_spi_probe(struct spi_device *spi)
 		return dev_err_probe(&spi->dev, PTR_ERR(regmap),
 				     "Failed to register spi regmap\n");
 
-	return devm_ens160_core_probe(&spi->dev, regmap, "ens160_spi");
+	return devm_ens160_core_probe(&spi->dev, regmap, spi->irq,
+				      "ens160_spi");
 }
 
 static const struct of_device_id ens160_spi_of_match[] = {
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 5/6] iio: chemical: ens160: add power management support
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
                   ` (2 preceding siblings ...)
  2024-05-29  0:14 ` [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support Gustavo Silva
@ 2024-05-29  0:14 ` Gustavo Silva
  2024-05-29  0:14 ` [PATCH v2 6/6] MAINTAINERS: Add ScioSense ENS160 Gustavo Silva
  2024-05-29  7:29 ` [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Krzysztof Kozlowski
  5 siblings, 0 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

ENS160 supports a deep sleep mode for minimal power consumption.
Use it to add PM sleep capability to the driver.

Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
---
no changes in v2
 drivers/iio/chemical/ens160.h      |  3 +++
 drivers/iio/chemical/ens160_core.c | 23 +++++++++++++++++++++++
 drivers/iio/chemical/ens160_i2c.c  |  1 +
 drivers/iio/chemical/ens160_spi.c  |  1 +
 4 files changed, 28 insertions(+)

diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h
index e6cc0987a..f9f0575ce 100644
--- a/drivers/iio/chemical/ens160.h
+++ b/drivers/iio/chemical/ens160.h
@@ -4,4 +4,7 @@
 
 int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
 			   const char *name);
+
+extern const struct dev_pm_ops ens160_pm_ops;
+
 #endif
diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
index 74ef7f150..dd501e655 100644
--- a/drivers/iio/chemical/ens160_core.c
+++ b/drivers/iio/chemical/ens160_core.c
@@ -215,6 +215,29 @@ static const struct iio_info ens160_info = {
 	.read_raw = ens160_read_raw,
 };
 
+static int ens160_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ens160_data *data = iio_priv(indio_dev);
+
+	return ens160_set_mode(data, ENS160_REG_MODE_DEEP_SLEEP);
+}
+
+static int ens160_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ens160_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
+	if (ret)
+		return ret;
+
+	return ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
+}
+EXPORT_NS_SIMPLE_DEV_PM_OPS(ens160_pm_ops, ens160_suspend, ens160_resume,
+			    IIO_ENS160);
+
 static irqreturn_t ens160_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c
index 4bf3c455c..06d2967a9 100644
--- a/drivers/iio/chemical/ens160_i2c.c
+++ b/drivers/iio/chemical/ens160_i2c.c
@@ -49,6 +49,7 @@ static struct i2c_driver ens160_i2c_driver = {
 	.driver = {
 		.name		= "ens160_i2c",
 		.of_match_table	= ens160_of_i2c_match,
+		.pm		= pm_sleep_ptr(&ens160_pm_ops),
 	},
 	.probe = ens160_i2c_probe,
 	.id_table = ens160_i2c_id,
diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c
index 91528c5e3..f9603f51d 100644
--- a/drivers/iio/chemical/ens160_spi.c
+++ b/drivers/iio/chemical/ens160_spi.c
@@ -49,6 +49,7 @@ static struct spi_driver ens160_spi_driver = {
 	.driver = {
 		.name	= "ens160_spi",
 		.of_match_table = ens160_spi_of_match,
+		.pm = pm_sleep_ptr(&ens160_pm_ops),
 	},
 	.probe		= ens160_spi_probe,
 	.id_table	= ens160_spi_id,
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 6/6] MAINTAINERS: Add ScioSense ENS160
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
                   ` (3 preceding siblings ...)
  2024-05-29  0:14 ` [PATCH v2 5/6] iio: chemical: ens160: add power management support Gustavo Silva
@ 2024-05-29  0:14 ` Gustavo Silva
  2024-05-29  7:29 ` [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Krzysztof Kozlowski
  5 siblings, 0 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-29  0:14 UTC (permalink / raw)
  To: jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

Add myself as maintainer for ScioSense ENS160 multi-gas sensor driver.

Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
---
no changes in v2
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 304429f9b..92a130c8c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19660,6 +19660,14 @@ F:	include/linux/wait.h
 F:	include/uapi/linux/sched.h
 F:	kernel/sched/
 
+SCIOSENSE ENS160 MULTI-GAS SENSOR DRIVER
+M:	Gustavo Silva <gustavograzs@gmail.com>
+S:	Maintained
+F:	drivers/iio/chemical/ens160_core.c
+F:	drivers/iio/chemical/ens160_i2c.c
+F:	drivers/iio/chemical/ens160_spi.c
+F:	drivers/iio/chemical/ens160.h
+
 SCSI LIBSAS SUBSYSTEM
 R:	John Garry <john.g.garry@oracle.com>
 R:	Jason Yan <yanaijie@huawei.com>
-- 
2.45.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor
  2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
@ 2024-05-29  1:42   ` Rob Herring (Arm)
  2024-05-29 16:36   ` Conor Dooley
  1 sibling, 0 replies; 15+ messages in thread
From: Rob Herring (Arm) @ 2024-05-29  1:42 UTC (permalink / raw)
  To: Gustavo Silva
  Cc: linux-kernel, christophe.jaillet, devicetree, jic23, conor+dt,
	krzk+dt, lars, linux-iio


On Tue, 28 May 2024 21:14:19 -0300, Gustavo Silva wrote:
> Add bindings for ScioSense ENS160 multi-gas sensor.
> 
> Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
> 
> Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
> ---
> changes in v2:
>  - Add devicetree binding file specifically for this sensor instead of
>    adding it to trivial-devices.yaml. This is needed in order to
>    document that this chip supports Vdd and Vddio supplies.
>  .../iio/chemical/sciosense,ens160.yaml        | 68 +++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.example.dtb: gas-sensor@0: 'spi-max-frequency' does not match any of the regexes: 'pinctrl-[0-9]+'
	from schema $id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20240529001504.33648-2-gustavograzs@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense
  2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
                   ` (4 preceding siblings ...)
  2024-05-29  0:14 ` [PATCH v2 6/6] MAINTAINERS: Add ScioSense ENS160 Gustavo Silva
@ 2024-05-29  7:29 ` Krzysztof Kozlowski
  2024-05-29 16:34   ` Conor Dooley
  2024-05-31 22:22   ` Gustavo Silva
  5 siblings, 2 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-29  7:29 UTC (permalink / raw)
  To: Gustavo Silva, jic23
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

On 29/05/2024 02:14, Gustavo Silva wrote:
> Add vendor prefix for ScioSense B.V.
> https://www.sciosense.com/
> 
> Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
> ---

This is a friendly reminder during the review process.

It looks like you received a tag and forgot to add it.

If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions, under or above your Signed-off-by tag. Tag is "received", when
provided in a message replied to you on the mailing list. Tools like b4
can help here. However, there's no need to repost patches *only* to add
the tags. The upstream maintainer will do that for tags received on the
version they apply.

https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitting-patches.rst#L577

If a tag was not added on purpose, please state why and what changed.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense
  2024-05-29  7:29 ` [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Krzysztof Kozlowski
@ 2024-05-29 16:34   ` Conor Dooley
  2024-05-31 22:22   ` Gustavo Silva
  1 sibling, 0 replies; 15+ messages in thread
From: Conor Dooley @ 2024-05-29 16:34 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Gustavo Silva, jic23, robh, krzk+dt, conor+dt, lars,
	christophe.jaillet, devicetree, linux-iio, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]

On Wed, May 29, 2024 at 09:29:54AM +0200, Krzysztof Kozlowski wrote:
> On 29/05/2024 02:14, Gustavo Silva wrote:
> > Add vendor prefix for ScioSense B.V.
> > https://www.sciosense.com/
> > 
> > Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
> > ---
> 
> This is a friendly reminder during the review process.
> 
> It looks like you received a tag and forgot to add it.

Acked-by: Conor Dooley <conor.dooley@microchip.com>

Thanks,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor
  2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
  2024-05-29  1:42   ` Rob Herring (Arm)
@ 2024-05-29 16:36   ` Conor Dooley
  2024-05-29 16:37     ` Conor Dooley
  1 sibling, 1 reply; 15+ messages in thread
From: Conor Dooley @ 2024-05-29 16:36 UTC (permalink / raw)
  To: Gustavo Silva
  Cc: jic23, robh, krzk+dt, conor+dt, lars, christophe.jaillet,
	devicetree, linux-iio, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2780 bytes --]

On Tue, May 28, 2024 at 09:14:19PM -0300, Gustavo Silva wrote:
> Add bindings for ScioSense ENS160 multi-gas sensor.
> 
> Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
> 
> Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
> ---
> changes in v2:
>  - Add devicetree binding file specifically for this sensor instead of
>    adding it to trivial-devices.yaml. This is needed in order to
>    document that this chip supports Vdd and Vddio supplies.
>  .../iio/chemical/sciosense,ens160.yaml        | 68 +++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
> new file mode 100644
> index 000000000..7dd442f94
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
> @@ -0,0 +1,68 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ScioSense ENS160 multi-gas sensor
> +
> +maintainers:
> +  - Gustavo Silva <gustavograzs@gmail.com>
> +
> +description: |
> +  Digital Multi-Gas Sensor for Monitoring Indoor Air Quality.
> +
> +  Datasheet:
> +    https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
> +
> +properties:
> +  compatible:
> +    enum:
> +      - sciosense,ens160
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  vdd-supply: true
> +  vddio-supply: true
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    i2c {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +
> +      gas-sensor@52 {
> +        compatible = "sciosense,ens160";
> +        reg = <0x52>;
> +        interrupt-parent = <&gpio0>;
> +        interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
> +      };
> +    };
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    spi {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +
> +      gas-sensor@0 {
> +        compatible = "sciosense,ens160";
> +        reg = <0>;
> +        spi-max-frequency = <10000000>;

If you want to include this, you need to add an
allOf:
  - $ref: /schemas/spi/spi-peripheral-props.yaml#
above. Otherwise this looks pretty good, so with that added
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>

Thanks,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor
  2024-05-29 16:36   ` Conor Dooley
@ 2024-05-29 16:37     ` Conor Dooley
  2024-05-31 22:33       ` Gustavo Silva
  0 siblings, 1 reply; 15+ messages in thread
From: Conor Dooley @ 2024-05-29 16:37 UTC (permalink / raw)
  To: Gustavo Silva
  Cc: jic23, robh, krzk+dt, conor+dt, lars, christophe.jaillet,
	devicetree, linux-iio, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 500 bytes --]

On Wed, May 29, 2024 at 05:36:38PM +0100, Conor Dooley wrote:
> > +      gas-sensor@0 {
> > +        compatible = "sciosense,ens160";
> > +        reg = <0>;
> > +        spi-max-frequency = <10000000>;
> 
> If you want to include this, you need to add an
> allOf:
>   - $ref: /schemas/spi/spi-peripheral-props.yaml#
> above. Otherwise this looks pretty good, so with that added
> Reviewed-by: Conor Dooley <conor.dooley@microchip.com>

(Please make sure to actually test it next time!)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense
  2024-05-29  7:29 ` [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Krzysztof Kozlowski
  2024-05-29 16:34   ` Conor Dooley
@ 2024-05-31 22:22   ` Gustavo Silva
  1 sibling, 0 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-31 22:22 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: jic23, robh, krzk+dt, conor+dt, lars, christophe.jaillet,
	devicetree, linux-iio, linux-kernel

On Wed, May 29, 2024 at 09:29:54AM GMT, Krzysztof Kozlowski wrote:
> On 29/05/2024 02:14, Gustavo Silva wrote:
> > Add vendor prefix for ScioSense B.V.
> > https://www.sciosense.com/
> > 
> > Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
> > ---
> 
> This is a friendly reminder during the review process.
> 
> It looks like you received a tag and forgot to add it.
> 
> If you do not know the process, here is a short explanation:
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new
> versions, under or above your Signed-off-by tag. Tag is "received", when
> provided in a message replied to you on the mailing list. Tools like b4
> can help here. However, there's no need to repost patches *only* to add
> the tags. The upstream maintainer will do that for tags received on the
> version they apply.
> 
> https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitting-patches.rst#L577
> 
> If a tag was not added on purpose, please state why and what changed.
> 
> Best regards,
> Krzysztof
> 

Hi Krzysztof,

Sorry, I totally forgot to add the tag. If we need a new version of
this patch series, I'll make sure to add it.

Also, thank you for mentioning b4, I'll definitely give it a try.

Best regards,
Gustavo

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor
  2024-05-29 16:37     ` Conor Dooley
@ 2024-05-31 22:33       ` Gustavo Silva
  0 siblings, 0 replies; 15+ messages in thread
From: Gustavo Silva @ 2024-05-31 22:33 UTC (permalink / raw)
  To: Conor Dooley
  Cc: jic23, robh, krzk+dt, conor+dt, lars, christophe.jaillet,
	devicetree, linux-iio, linux-kernel

On Wed, May 29, 2024 at 05:37:17PM GMT, Conor Dooley wrote:
> On Wed, May 29, 2024 at 05:36:38PM +0100, Conor Dooley wrote:
> > > +      gas-sensor@0 {
> > > +        compatible = "sciosense,ens160";
> > > +        reg = <0>;
> > > +        spi-max-frequency = <10000000>;
> > 
> > If you want to include this, you need to add an
> > allOf:
> >   - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > above. Otherwise this looks pretty good, so with that added
> > Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> 
> (Please make sure to actually test it next time!)

Hi Conor,

I'll fix it in v3.
I had some trouble running the dt_binding_check target, but I got it
working now. I'll remember to run it in the future.
Thanks.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/6] iio: chemical: add driver for ENS160 sensor
  2024-05-29  0:14 ` [PATCH v2 3/6] iio: chemical: add driver for " Gustavo Silva
@ 2024-06-02 11:24   ` Jonathan Cameron
  0 siblings, 0 replies; 15+ messages in thread
From: Jonathan Cameron @ 2024-06-02 11:24 UTC (permalink / raw)
  To: Gustavo Silva
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

On Tue, 28 May 2024 21:14:20 -0300
Gustavo Silva <gustavograzs@gmail.com> 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@gmail.com>
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@gmail.com>");
> +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@gmail.com>
> + *
> + * 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.




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support
  2024-05-29  0:14 ` [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support Gustavo Silva
@ 2024-06-02 11:27   ` Jonathan Cameron
  0 siblings, 0 replies; 15+ messages in thread
From: Jonathan Cameron @ 2024-06-02 11:27 UTC (permalink / raw)
  To: Gustavo Silva
  Cc: robh, krzk+dt, conor+dt, lars, christophe.jaillet, devicetree,
	linux-iio, linux-kernel

On Tue, 28 May 2024 21:14:21 -0300
Gustavo Silva <gustavograzs@gmail.com> wrote:

> ENS160 supports a data ready interrupt. Use it in combination with
> triggered buffer for continuous data readings.
> 
> Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
A couple of really minor comments inline.

Thanks,

Jonathan


>  #endif
> diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
> index a535f62c4..74ef7f150 100644
> --- a/drivers/iio/chemical/ens160_core.c
> +++ b/drivers/iio/chemical/ens160_core.c
> @@ -10,6 +10,9 @@
>  
>  #include <linux/bitfield.h>
>  #include <linux/iio/iio.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
>  #include <linux/module.h>
>  #include <linux/regmap.h>
>  
> @@ -19,9 +22,14 @@
>  
>  #define ENS160_BOOTING_TIME_MS 10U
>  
> -#define ENS160_REG_PART_ID	0x00

move this in earlier patch so no need to realign here.

> +#define ENS160_REG_PART_ID		0x00
>  
> -#define ENS160_REG_OPMODE	0x10
> +#define ENS160_REG_OPMODE		0x10
> +
> +#define ENS160_REG_CONFIG		0x11
> +#define ENS160_REG_CONFIG_INTEN		BIT(0)
> +#define ENS160_REG_CONFIG_INTDAT	BIT(1)
> +#define ENS160_REG_CONFIG_INT_CFG	BIT(5)
>  
>  #define ENS160_REG_MODE_DEEP_SLEEP	0x00
>  #define ENS160_REG_MODE_IDLE		0x01
> @@ -48,7 +56,12 @@
>  
>  struct ens160_data {
>  	struct regmap *regmap;
> -	u8 fw_version[3] __aligned(IIO_DMA_MINALIGN);
> +	struct mutex mutex;

Mutex needs a comment to say what data it is protecting.

> +	struct {
> +		__le16 chans[2];
> +		s64 timestamp __aligned(8);
> +	} scan __aligned(IIO_DMA_MINALIGN);
> +	u8 fw_version[3];
>  	__le16 buf;
>  };


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2024-06-02 11:27 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-29  0:14 [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Gustavo Silva
2024-05-29  0:14 ` [PATCH v2 2/6] dt-bindings: iio: chemical: add ENS160 sensor Gustavo Silva
2024-05-29  1:42   ` Rob Herring (Arm)
2024-05-29 16:36   ` Conor Dooley
2024-05-29 16:37     ` Conor Dooley
2024-05-31 22:33       ` Gustavo Silva
2024-05-29  0:14 ` [PATCH v2 3/6] iio: chemical: add driver for " Gustavo Silva
2024-06-02 11:24   ` Jonathan Cameron
2024-05-29  0:14 ` [PATCH v2 4/6] iio: chemical: ens160: add triggered buffer support Gustavo Silva
2024-06-02 11:27   ` Jonathan Cameron
2024-05-29  0:14 ` [PATCH v2 5/6] iio: chemical: ens160: add power management support Gustavo Silva
2024-05-29  0:14 ` [PATCH v2 6/6] MAINTAINERS: Add ScioSense ENS160 Gustavo Silva
2024-05-29  7:29 ` [PATCH v2 1/6] dt-bindings: vendor-prefixes: add ScioSense Krzysztof Kozlowski
2024-05-29 16:34   ` Conor Dooley
2024-05-31 22:22   ` Gustavo Silva

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).