Skip to contentSkip to conversation

Add driver for Murata IRS-D200

PATCH In review Waqar Hameed 2 participants 6 messages Jul 19, 2023 – Jul 25, 2023

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v4 cover Add driver for Murata IRS-D200

Murata IRS-D200 is a PIR sensor for human detection. In this series we add devicetree bindings and an IIO driver with support for triggered buffer and events. Link to the datasheet should be added to the devicetree bindings, when that is available.

Changes in v4:

[iio]
* Use iio_trigger_poll_nested() instead of iio_trigger_poll_chained(). (Remnant from old tree... Sorry!)

Link to v3: https://lore.kernel.org/lkml/[email protected]/

Changes in v3:

[dt-bindings]
* Add "Reviewed-by" footer in commit message.

[iio]
* Use __le16 for buffers in regmap_bulk_read/write().
* Use 8 instead of BIT(3) in irsd200_write_nr_count().
* Rename val to tmp in irsd200_write_event_config().
* Return 0 on success in irsd200_write_event_config().
* Return IRQ_HANDLED instead of IRQ_NONE in error paths.
* Return IRQ_NONE when not clearing anything in irsd200_irq_thread().
* Use devm_regulator_get_enable() in probe.

Link to v2: https://lore.kernel.org/lkml/[email protected]/

Changes in v2:

[dt-bindings]
* Remove "bindings for" in commit subject.
* Remove superfluous yaml block style indicator ('|') for description:.
* Change node name in example from pir to proximity.
* Add required vdd-supply property.

[iio]
* Add event enums for running period and count.
* Use set_trigger_state callback instead of iio_buffer_setup_ops's predisable and postenable.
* Use regmap_bulk_read() in irsd200_read_data() and irsd200_read_timer().
* Use regmap_bulk_write() in irsd200_write_timer().
* Remove comment for macro IRS_UPPER_COUNT().
* Move IIO_EV_INFO_LOW/HIGH_PASS_FILTER_3DB from iio_event_spec to iio_chan_spec.
* Ignore timer (IRS_INTR_TIMER) interrupts.
* Clarify comment on ssleep(3) in irsd200_write_data_rate().
* Only check for non-zero return values from regmap functions (as opposed to ret < 0).
* Add macro defines for operation states.
* Remove fix size in static const array declarations.
* Remove unnecessary ret variable in irsd200_write_raw().
* Remove comments in irsd200_event_spec[].
* Remove unnecessary call to i2c_set_clientdata() in probe.
* Use dev_err_probe() everywhere in probe.
* Remove unnecessary braces around if statement in probe.
* Get and enable regulator in probe.

Link to v1: https://lore.kernel.org/lkml/[email protected]/

Waqar Hameed (3):
dt-bindings: iio: proximity: Add Murata IRS-D200
iio: Add event enums for running period and count
iio: Add driver for Murata IRS-D200

 Documentation/ABI/testing/sysfs-bus-iio       |  16 +
 .../iio/proximity/murata,irsd200.yaml         |  60 ++
 drivers/iio/industrialio-event.c              |   2 +
 drivers/iio/proximity/Kconfig                 |  12 +
 drivers/iio/proximity/Makefile                |   1 +
 drivers/iio/proximity/irsd200.c               | 962 ++++++++++++++++++
 include/linux/iio/types.h                     |   2 +
 7 files changed, 1055 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml
 create mode 100644 drivers/iio/proximity/irsd200.c

base-commit: 3f01e9fed8454dcd89727016c3e5b2fbb8f8e50c

Signature · 1 line
2.30.2
#1 lore raw

PATCH v4 1/3 dt-bindings: iio: proximity: Add Murata IRS-D200

Murata IRS-D200 is a PIR sensor for human detection. It uses the I2C bus for communication with interrupt support. Add devicetree bindings requiring the compatible string, I2C slave address (reg), power supply and interrupts.

---
 .../iio/proximity/murata,irsd200.yaml         | 60 +++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml
Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml new file +60 -0
new file mode 100644
index 000000000000..67f5389ece67
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/murata,irsd200.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Murata IRS-D200 PIR sensor
+
+maintainers:
+  - Waqar Hameed <[email protected]>
+
+description:
+  PIR sensor for human detection.
+
+properties:
+  compatible:
+    const: murata,irsd200
+
+  reg:
+    items:
+      - enum:
+          - 0x48
+          - 0x49
+        description: |
+          When the AD pin is connected to GND, the slave address is 0x48.
+          When the AD pin is connected to VDD, the slave address is 0x49.
+
+  interrupts:
+    maxItems: 1
+    description:
+      Type should be IRQ_TYPE_EDGE_RISING.
+
+  vdd-supply:
+    description:
+      3.3 V supply voltage.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - vdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        proximity@48 {
+            compatible = "murata,irsd200";
+            reg = <0x48>;
+            interrupts = <24 IRQ_TYPE_EDGE_RISING>;
+            vdd-supply = <&regulator_3v3>;
+        };
+    };
+...
Signature · 1 line
2.30.2
#2 lore raw

PATCH v4 2/3 iio: Add event enums for running period and count

In reply to Waqar Hameed

There are devices (such as Murata IRS-D200 PIR proximity sensor) that check the data signal with a running period. I.e. for a specified time, they count the number of conditions that have occurred, and then signal if that is more than a specified amount.

IIO_EV_INFO_PERIOD resets when the condition no longer is true and is therefore not suitable for these devices. Add a new iio_event_info IIO_EV_INFO_RUNNING_PERIOD that can be used as a running period. Also add a new IIO_EV_INFO_RUNNING_COUNT that can be used to specify the number of conditions that must occur during this running period.

---
 Documentation/ABI/testing/sysfs-bus-iio | 16 ++++++++++++++++
 drivers/iio/industrialio-event.c        |  2 ++
 include/linux/iio/types.h               |  2 ++
 3 files changed, 20 insertions(+)
Documentation/ABI/testing/sysfs-bus-iio +16 -0
index 7140e8e7313f..a2854dc9a839 100644
@@ -2163,3 +2163,19 @@ Contact:	[email protected]
 Description:
 		An example format is 16-bytes, 2-digits-per-byte, HEX-string
 		representing the sensor unique ID number.
+
+What:		/sys/.../events/in_proximity_thresh_either_runningperiod
+KernelVersion:	6.6
+Contact:	[email protected]
+Description:
+		A running period of time (in seconds) for which
+		in_proximity_thresh_either_runningcount amount of conditions
+		must occur before an event is generated. If direction is not
+		specified then this period applies to both directions.
+
+What:		/sys/.../events/in_proximity_thresh_either_runningcount
+KernelVersion:	6.6
+Contact:	[email protected]
+Description:
+		Number of conditions that must occur, during a running
+		period, before an event is generated.
drivers/iio/industrialio-event.c +2 -0
index f77ce49d4c36..19f7a91157ee 100644
@@ -252,6 +252,8 @@ static const char * const iio_ev_info_text[] = {
 	[IIO_EV_INFO_TIMEOUT] = "timeout",
 	[IIO_EV_INFO_RESET_TIMEOUT] = "reset_timeout",
 	[IIO_EV_INFO_TAP2_MIN_DELAY] = "tap2_min_delay",
+	[IIO_EV_INFO_RUNNING_PERIOD] = "runningperiod",
+	[IIO_EV_INFO_RUNNING_COUNT] = "runningcount",
 };
 
 static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
include/linux/iio/types.h +2 -0
index 82faa98c719a..117bde7d6ad7 100644
@@ -19,6 +19,8 @@ enum iio_event_info {
 	IIO_EV_INFO_TIMEOUT,
 	IIO_EV_INFO_RESET_TIMEOUT,
 	IIO_EV_INFO_TAP2_MIN_DELAY,
+	IIO_EV_INFO_RUNNING_PERIOD,
+	IIO_EV_INFO_RUNNING_COUNT,
 };
 
 #define IIO_VAL_INT 1
Signature · 1 line
2.30.2
#3 lore raw

PATCH v4 3/3 iio: Add driver for Murata IRS-D200

In reply to Waqar Hameed

Murata IRS-D200 is a PIR sensor for human detection. It has support for raw data measurements and detection event notification.

Add a driver with support for triggered buffer and events. Map the various settings to the iio framework, e.g. threshold values, sampling frequency, filter frequencies etc.

---
 drivers/iio/proximity/Kconfig   |  12 +
 drivers/iio/proximity/Makefile  |   1 +
 drivers/iio/proximity/irsd200.c | 962 ++++++++++++++++++++++++++++++++
 3 files changed, 975 insertions(+)
 create mode 100644 drivers/iio/proximity/irsd200.c
drivers/iio/proximity/Kconfig +12 -0
index 0e5c17530b8b..2ca3b0bc5eba 100644
@@ -32,6 +32,18 @@ config CROS_EC_MKBP_PROXIMITY
 	  To compile this driver as a module, choose M here: the
 	  module will be called cros_ec_mkbp_proximity.
 
+config IRSD200
+	tristate "Murata IRS-D200 PIR sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for the Murata IRS-D200 PIR sensor.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called irsd200.
+
 config ISL29501
 	tristate "Intersil ISL29501 Time Of Flight sensor"
 	depends on I2C
drivers/iio/proximity/Makefile +1 -0
index cc838bb5408a..f36598380446 100644
@@ -6,6 +6,7 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AS3935)		+= as3935.o
 obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
+obj-$(CONFIG_IRSD200)		+= irsd200.o
 obj-$(CONFIG_ISL29501)		+= isl29501.o
 obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
 obj-$(CONFIG_MB1232)		+= mb1232.o
drivers/iio/proximity/irsd200.c new file +962 -0

962 lines not on this page · raw message

Signature · 1 line
2.30.2
maintainer
#4 lore raw

Re: [PATCH v4 3/3] iio: Add driver for Murata IRS-D200

Quoted 8 lines · On Wed, 19 Jul 2023 09:51:17 +0200 Waqar Hameed <[email protected]> wrote:

Murata IRS-D200 is a PIR sensor for human detection. It has support for raw data measurements and detection event notification.

Add a driver with support for triggered buffer and events. Map the various settings to the iio framework, e.g. threshold values, sampling frequency, filter frequencies etc.

Hi Waqar.

I had some more feedback (see inline) but as it was all very minor, I've made the changes whilst applying. Let me know if I messed anything up!

Applied to the togreg branch of iio.git and pushed out as testing for 0-day to see if it can find anything we missed.

Thanks,

Jonathan

drivers/iio/proximity/irsd200.c line 79

Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10 -0
+
+/*
+ * Index corresponds to the (field) value of IRS_REG_FILTER register. Note that
+ * this represents a fractional value (e.g the first value corresponds to 3 / 10
+ * = 0.3 Hz).
+ */
+static const unsigned int irsd200_hp_filter_freq[][2] = {
+	{3, 10},
+	{5, 10},
+};

Prefer space after / before {}

...

Quoted 7 lines
drivers/iio/proximity/irsd200.c new file +7 -0
+static int irsd200_write_event_config(struct iio_dev *indio_dev,
+				      const struct iio_chan_spec *chan,
+				      enum iio_event_type type,
+				      enum iio_event_direction dir, int state)
+{
+	struct irsd200_data *data = iio_priv(indio_dev);
+	unsigned int tmp;

drivers/iio/proximity/irsd200.c line 665

Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10 -0
+	int ret;
+
+	switch (type) {
+	case IIO_EV_TYPE_THRESH:
+		/* Clear the count register (by reading from it). */
+		ret = regmap_read(data->regmap, IRS_REG_COUNT, &tmp);
+		if (ret)
+			return ret;
+
+		tmp = !!state;

Don't use tmp again here as it suggests some use of previous value. I'd just put !!state in where the parameter is used.

drivers/iio/proximity/irsd200.c line 671

Quoted 6 lines
drivers/iio/proximity/irsd200.c new file +6 -0
+		ret = regmap_field_write(
+			data->regfields[IRS_REGF_INTR_COUNT_THR_OR], tmp);
+		if (ret)
+			return ret;
+
+		return 0;
		return regmap_field_write(
			data->regfields[IRS_REGF_INTR_COUNT_THR_OR], !!state);
Quoted 78 lines
drivers/iio/proximity/irsd200.c new file +78 -0
+	default:
+		return -EINVAL;
+	}
+}
+
+static irqreturn_t irsd200_irq_thread(int irq, void *dev_id)
+{
+	struct iio_dev *indio_dev = dev_id;
+	struct irsd200_data *data = iio_priv(indio_dev);
+	enum iio_event_direction dir;
+	unsigned int lower_count;
+	unsigned int upper_count;
+	unsigned int status = 0;
+	unsigned int source = 0;
+	unsigned int clear = 0;
+	unsigned int count = 0;
+	int ret;
+
+	ret = regmap_read(data->regmap, IRS_REG_INTR, &source);
+	if (ret) {
+		dev_err(data->dev, "Could not read interrupt source (%d)\n",
+			ret);
+		return IRQ_HANDLED;
+	}
+
+	ret = regmap_read(data->regmap, IRS_REG_STATUS, &status);
+	if (ret) {
+		dev_err(data->dev, "Could not acknowledge interrupt (%d)\n",
+			ret);
+		return IRQ_HANDLED;
+	}
+
+	if (status & BIT(IRS_INTR_DATA) && iio_buffer_enabled(indio_dev)) {
+		iio_trigger_poll_nested(indio_dev->trig);
+		clear |= BIT(IRS_INTR_DATA);
+	}
+
+	if (status & BIT(IRS_INTR_COUNT_THR_OR) &&
+	    source & BIT(IRS_INTR_COUNT_THR_OR)) {
+		/*
+		 * The register value resets to zero after reading. We therefore
+		 * need to read once and manually extract the lower and upper
+		 * count register fields.
+		 */
+		ret = regmap_read(data->regmap, IRS_REG_COUNT, &count);
+		if (ret)
+			dev_err(data->dev, "Could not read count (%d)\n", ret);
+
+		upper_count = IRS_UPPER_COUNT(count);
+		lower_count = IRS_LOWER_COUNT(count);
+
+		/*
+		 * We only check the OR mode to be able to push events for
+		 * rising and falling thresholds. AND mode is covered when both
+		 * upper and lower count is non-zero, and is signaled with
+		 * IIO_EV_DIR_EITHER.
+		 */
+		if (upper_count && !lower_count)
+			dir = IIO_EV_DIR_RISING;
+		else if (!upper_count && lower_count)
+			dir = IIO_EV_DIR_FALLING;
+		else
+			dir = IIO_EV_DIR_EITHER;
+
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+						    IIO_EV_TYPE_THRESH, dir),
+			       iio_get_time_ns(indio_dev));
+
+		/*
+		 * The OR mode will always trigger when the AND mode does, but
+		 * not vice versa. However, it seems like the AND bit needs to
+		 * be cleared if data capture _and_ threshold count interrupts
+		 * are desirable, even though it hasn't explicitly been selected
+		 * (with IRS_REG_INTR). Either way, it doesn't hurt...
+		 */
+		clear |= BIT(IRS_INTR_COUNT_THR_OR) |
+			 BIT(IRS_INTR_COUNT_THR_AND);

drivers/iio/proximity/irsd200.c line 759

Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10 -0
+	}
+
+	if (clear) {
+		ret = regmap_write(data->regmap, IRS_REG_STATUS, clear);
+		if (ret)
+			dev_err(data->dev,
+				"Could not clear interrupt status (%d)\n", ret);
+	}
+
+	return clear ? IRQ_HANDLED : IRQ_NONE;
	if (!clear)
		return IRQ_NONE

	ret = regmap_write(data->regmap ...
	if (ret)
		...
	return IRQ_HANDLED;

Avoids complexity of checking clear multiple times and keeps the 'error' paths as the ones that are indented. (here it might just be a shared interrupt rather than an error).

Quoted 13 lines
drivers/iio/proximity/irsd200.c new file +11 -0
+}
 
 
+
+static const struct iio_chan_spec irsd200_channels[] = {
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
+			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),
+		.info_mask_separate_available =

drivers/iio/proximity/irsd200.c line 850

Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10 -0
+			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
+			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),
+		.event_spec = irsd200_event_spec,
+		.num_event_specs = ARRAY_SIZE(irsd200_event_spec),
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_CPU,

As a general rule, we don't adjust the byte ordering of data going out via the buffered interface, instead leaving that work for userspace. Given the handling here is very simple, I don't feel that strongly about keeping to that, but thought I'd mention it.

Jonathan

Quoted 3 lines
drivers/iio/proximity/irsd200.c new file +3 -0
+		},
+	},
+};
#5 lore raw

Re: [PATCH v4 3/3] iio: Add driver for Murata IRS-D200

On Sun, Jul 23, 2023 at 13:22 +0100 Jonathan Cameron <[email protected]> wrote:

[...]

Quoted 5 lines

I had some more feedback (see inline) but as it was all very minor, I've made the changes whilst applying. Let me know if I messed anything up!

Applied to the togreg branch of iio.git and pushed out as testing for 0-day to see if it can find anything we missed.

Looks good to me! Thank you very much Jonathan!