Devicetree
 help / color / mirror / Atom feed
* [PATCH v3 0/3] iio: flow: Sensirion SLF3S liquid flow sensor
@ 2026-05-30 20:54 Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 1/3] iio: types: add IIO_VOLUMEFLOW channel type Wadim Mueller
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Wadim Mueller @ 2026-05-30 20:54 UTC (permalink / raw)
  To: Jonathan Cameron, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	David Lechner, Nuno Sá, Andy Shevchenko, Maxwell Doose
  Cc: linux-iio, devicetree, linux-kernel

Hi all,

v3 addresses the per-patch review feedback from Jonathan (driver +
cover, https://lore.kernel.org/linux-iio/20260528124413.6c91e1bb@jic23-huawei/)
and Krzysztof (dt-binding,
https://lore.kernel.org/linux-iio/20260528-transparent-adventurous-python-af8f69@quoll/).
As requested this is sent as a fresh thread, not in-reply-to v2.

The IIO_VOLUMEFLOW patch (1/3) is unchanged from v2.

Changes since v2:

  * dt-bindings: drop the generic-only "sensirion,slf3s" compatible;
    the per-variant compatibles stay (-0600F, -1300F, -4000B)
  * dt-bindings: drop the optional interrupts property -- the driver
    is polled-only and the binding should not advertise something we
    do not consume
  * dt-bindings: drop the sensirion,medium property and move medium
    selection to the IIO sysfs in_volumeflow_medium ext_info enum;
    the sensor starts in water mode after probe and IPA is selected
    at runtime via that attribute
  * dt-bindings: MAINTAINERS no longer claims drivers/iio/flow/
  * driver: includes cleaned up per IWYU (drop property.h since no
    DT property is read any more, add array_size.h / dev_printk.h /
    device.h / errno.h / types.h / units.h)
  * driver: drop the SLF3S_MEAS_LEN define in favour of ARRAY_SIZE()
  * driver: inline SLF3S_TEMP_SCALE_MILLIC at the call site with a
    short comment that explains the 1000/200 ratio
  * driver: use 600 * MICRO / 30 * MICRO / 1920 * MILLI from
    linux/units.h for the per-variant scale denominators
  * driver: slf3s_send_cmd() takes cmd[at_least 2] (kernel idiom)
    rather than cmd[static 2]
  * driver: detection wins over the DT-supplied compatible; a
    mismatch is reported with dev_info and the sensor-reported
    variant is used
  * driver: SLF3S_MEAS_START_DELAY_US bumped to 60 ms (datasheet
    section 2.2, tw) and a 25 ms tPU power-up delay is observed
    between regulator enable and the first I2C command
  * driver: blank line before plain return statements; minor reflow
    to 80 columns
  * commit messages: drop the manual Cc trailers (get_maintainer.pl
    handles those) and move Signed-off-by to the end of the trailer
    block

Patches:

  1/3  iio: types: add IIO_VOLUMEFLOW channel type (unchanged)
  2/3  dt-bindings: iio: flow: add Sensirion SLF3S binding
  3/3  iio: flow: add Sensirion SLF3S liquid flow sensor driver

Tested with an SLF3S-0600F on a TI AM64x platform; W=1 build clean,
checkpatch --strict clean, dt_binding_check clean.

Thanks,
Wadim

Wadim Mueller (3):
  iio: types: add IIO_VOLUMEFLOW channel type
  dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor
  iio: flow: add Sensirion SLF3S liquid flow sensor driver

 Documentation/ABI/testing/sysfs-bus-iio       |  11 +
 .../bindings/iio/flow/sensirion,slf3s.yaml    |  49 +++
 MAINTAINERS                                   |   8 +
 drivers/iio/Kconfig                           |   1 +
 drivers/iio/Makefile                          |   1 +
 drivers/iio/flow/Kconfig                      |  27 ++
 drivers/iio/flow/Makefile                     |   7 +
 drivers/iio/flow/slf3s.c                      | 406 ++++++++++++++++++
 drivers/iio/industrialio-core.c               |   1 +
 include/uapi/linux/iio/types.h                |   1 +
 tools/iio/iio_event_monitor.c                 |   2 +
 11 files changed, 514 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml
 create mode 100644 drivers/iio/flow/Kconfig
 create mode 100644 drivers/iio/flow/Makefile
 create mode 100644 drivers/iio/flow/slf3s.c

-- 
2.52.0


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

* [PATCH v3 1/3] iio: types: add IIO_VOLUMEFLOW channel type
  2026-05-30 20:54 [PATCH v3 0/3] iio: flow: Sensirion SLF3S liquid flow sensor Wadim Mueller
@ 2026-05-30 20:54 ` Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 2/3] dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver Wadim Mueller
  2 siblings, 0 replies; 5+ messages in thread
From: Wadim Mueller @ 2026-05-30 20:54 UTC (permalink / raw)
  To: Jonathan Cameron, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	David Lechner, Nuno Sá, Andy Shevchenko, Maxwell Doose,
	linux-iio, linux-kernel
  Cc: devicetree

Add a new IIO channel type for liquid volumetric flow sensors.  The
unit exposed via the standard _scale attribute is litres per second
(l/s), so drivers reporting smaller native units (e.g. ml/min) only
need to set a fractional scale.

Update iio-core's name table, the iio_event_monitor whitelist and
the sysfs-bus-iio ABI document to match.  The new _scale attribute is
folded into the existing shared _scale block; only the per-type _raw
needs a fresh entry.

Signed-off-by: Wadim Mueller <wafgo01@gmail.com>
---
 Documentation/ABI/testing/sysfs-bus-iio | 11 +++++++++++
 drivers/iio/industrialio-core.c         |  1 +
 include/uapi/linux/iio/types.h          |  1 +
 tools/iio/iio_event_monitor.c           |  2 ++
 4 files changed, 15 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 5f87dcee7..2188557cb 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -507,6 +507,8 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_volumeflow_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_volumeflowY_scale
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -2458,3 +2460,12 @@ Description:
 		seconds, expressed as:
 
 		- a range specified as "[min step max]"
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_volumeflow_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_volumeflowY_raw
+KernelVersion:	6.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled) volumetric flow rate reading from the channel.
+		To convert to standard units (litres per second) apply the
+		channel's _scale (and _offset, when present).
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 22eefd048..aa34fcd8e 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -98,6 +98,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_CHROMATICITY] = "chromaticity",
 	[IIO_ATTENTION] = "attention",
 	[IIO_ALTCURRENT] = "altcurrent",
+	[IIO_VOLUMEFLOW] = "volumeflow",
 };
 
 static const char * const iio_modifier_names[] = {
diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
index 6d269b844..49480f321 100644
--- a/include/uapi/linux/iio/types.h
+++ b/include/uapi/linux/iio/types.h
@@ -53,6 +53,7 @@ enum iio_chan_type {
 	IIO_CHROMATICITY,
 	IIO_ATTENTION,
 	IIO_ALTCURRENT,
+	IIO_VOLUMEFLOW,
 };
 
 enum iio_modifier {
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c
index 03ca33869..078004750 100644
--- a/tools/iio/iio_event_monitor.c
+++ b/tools/iio/iio_event_monitor.c
@@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_CHROMATICITY] = "chromaticity",
 	[IIO_ATTENTION] = "attention",
 	[IIO_ALTCURRENT] = "altcurrent",
+	[IIO_VOLUMEFLOW] = "volumeflow",
 };
 
 static const char * const iio_ev_type_text[] = {
@@ -193,6 +194,7 @@ static bool event_is_known(struct iio_event_data *event)
 	case IIO_CHROMATICITY:
 	case IIO_ATTENTION:
 	case IIO_ALTCURRENT:
+	case IIO_VOLUMEFLOW:
 		break;
 	default:
 		return false;
-- 
2.52.0


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

* [PATCH v3 2/3] dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor
  2026-05-30 20:54 [PATCH v3 0/3] iio: flow: Sensirion SLF3S liquid flow sensor Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 1/3] iio: types: add IIO_VOLUMEFLOW channel type Wadim Mueller
@ 2026-05-30 20:54 ` Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver Wadim Mueller
  2 siblings, 0 replies; 5+ messages in thread
From: Wadim Mueller @ 2026-05-30 20:54 UTC (permalink / raw)
  To: Jonathan Cameron, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	David Lechner, Nuno Sá, Andy Shevchenko, Maxwell Doose,
	linux-iio, devicetree, linux-kernel

Document the bindings for the Sensirion SLF3S family of digital
liquid-flow sensors on I2C.  The family currently covers the
SLF3S-0600F, SLF3S-1300F and SLF3S-4000B variants.

The driver auto-detects the variant from the product-information
register at probe time; the per-variant compatible strings exist
for documentation and dt_binding_check purposes.

The active calibration medium (water / IPA) is runtime-switchable
via the in_volumeflow_medium sysfs attribute and therefore not a
DT property.

Signed-off-by: Wadim Mueller <wafgo01@gmail.com>
---
 .../bindings/iio/flow/sensirion,slf3s.yaml    | 49 +++++++++++++++++++
 MAINTAINERS                                   |  8 +++
 2 files changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml

diff --git a/Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml b/Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml
new file mode 100644
index 000000000..dc41120e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/flow/sensirion,slf3s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sensirion SLF3S liquid flow sensor
+
+maintainers:
+  - Wadim Mueller <wafgo01@gmail.com>
+
+description:
+  Family of digital liquid-flow sensors from Sensirion with I2C
+  interface.  All family members share the same register map; sub-types
+  differ only in the flow scale factor and the calibrated measurement
+  range, both of which are detected at probe time via the
+  product-information register.
+
+properties:
+  compatible:
+    enum:
+      - sensirion,slf3s-0600f
+      - sensirion,slf3s-1300f
+      - sensirion,slf3s-4000b
+
+  reg:
+    maxItems: 1
+
+  vdd-supply: true
+
+required:
+  - compatible
+  - reg
+  - vdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        flow-sensor@8 {
+            compatible = "sensirion,slf3s-0600f";
+            reg = <0x08>;
+            vdd-supply = <&reg_3v3>;
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 06a8c7457..222a03b6d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24187,6 +24187,14 @@ S:	Maintained
 F:	Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
 F:	drivers/iio/chemical/sgp40.c
 
+SENSIRION SLF3S LIQUID FLOW SENSOR DRIVER
+M:	Wadim Mueller <wafgo01@gmail.com>
+R:	Maxwell Doose <m32285159@gmail.com>
+L:	linux-iio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/flow/sensirion,slf3s.yaml
+F:	drivers/iio/flow/slf3s.c
+
 SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
 M:	Tomasz Duszynski <tduszyns@gmail.com>
 S:	Maintained
-- 
2.52.0


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

* [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver
  2026-05-30 20:54 [PATCH v3 0/3] iio: flow: Sensirion SLF3S liquid flow sensor Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 1/3] iio: types: add IIO_VOLUMEFLOW channel type Wadim Mueller
  2026-05-30 20:54 ` [PATCH v3 2/3] dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor Wadim Mueller
@ 2026-05-30 20:54 ` Wadim Mueller
  2026-05-30 21:14   ` sashiko-bot
  2 siblings, 1 reply; 5+ messages in thread
From: Wadim Mueller @ 2026-05-30 20:54 UTC (permalink / raw)
  To: Jonathan Cameron, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	David Lechner, Nuno Sá, Andy Shevchenko, Maxwell Doose,
	linux-kernel, linux-iio
  Cc: devicetree

Add a driver for the Sensirion SLF3S family of digital
liquid-flow sensors on I2C.  Currently supported variants are
SLF3S-0600F, SLF3S-1300F and SLF3S-4000B; they share the same
register map and differ only in flow-scale factor and calibrated
measurement range.  The variant (and therefore the scale) is
auto-detected from the product-information register at probe time.

Each measurement frame returns a 16-bit signed flow value, a
16-bit signed temperature reading and a status word, each
protected by a CRC-8 byte.  The driver exposes the flow rate as
IIO_VOLUMEFLOW and the temperature as IIO_TEMP via the standard
IIO read_raw / read_scale interface.

The active calibration medium can be switched at runtime between
the factory-calibrated water and isopropyl-alcohol modes via the
in_volumeflow_medium sysfs attribute; the sensor starts in water
mode after probe.

This driver also creates the drivers/iio/flow/ subdirectory and
the corresponding Kconfig/Makefile glue.

Signed-off-by: Wadim Mueller <wafgo01@gmail.com>
---
 drivers/iio/Kconfig       |   1 +
 drivers/iio/Makefile      |   1 +
 drivers/iio/flow/Kconfig  |  27 +++
 drivers/iio/flow/Makefile |   7 +
 drivers/iio/flow/slf3s.c  | 406 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 442 insertions(+)
 create mode 100644 drivers/iio/flow/Kconfig
 create mode 100644 drivers/iio/flow/Makefile
 create mode 100644 drivers/iio/flow/slf3s.c

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 661127aed..652557a5b 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -92,6 +92,7 @@ source "drivers/iio/common/Kconfig"
 source "drivers/iio/dac/Kconfig"
 source "drivers/iio/dummy/Kconfig"
 source "drivers/iio/filter/Kconfig"
+source "drivers/iio/flow/Kconfig"
 source "drivers/iio/frequency/Kconfig"
 source "drivers/iio/gyro/Kconfig"
 source "drivers/iio/health/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb80ef837..f03a4100c 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -29,6 +29,7 @@ obj-y += dac/
 obj-y += dummy/
 obj-y += gyro/
 obj-y += filter/
+obj-y += flow/
 obj-y += frequency/
 obj-y += health/
 obj-y += humidity/
diff --git a/drivers/iio/flow/Kconfig b/drivers/iio/flow/Kconfig
new file mode 100644
index 000000000..1eee131ea
--- /dev/null
+++ b/drivers/iio/flow/Kconfig
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Liquid / gas flow sensor drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Flow sensors"
+
+config SENSIRION_SLF3S
+	tristate "Sensirion SLF3S liquid flow sensor"
+	depends on I2C
+	select CRC8
+	help
+	  Say yes here to build support for the Sensirion SLF3S family
+	  of digital liquid-flow sensors:
+
+	    - SLF3S-0600F
+	    - SLF3S-1300F
+	    - SLF3S-4000B
+
+	  The driver reports the volumetric flow rate and the embedded
+	  temperature reading via the standard IIO interface.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called slf3s.
+
+endmenu
diff --git a/drivers/iio/flow/Makefile b/drivers/iio/flow/Makefile
new file mode 100644
index 000000000..3cf4ab95c
--- /dev/null
+++ b/drivers/iio/flow/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for industrial I/O flow sensor drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_SENSIRION_SLF3S) += slf3s.o
diff --git a/drivers/iio/flow/slf3s.c b/drivers/iio/flow/slf3s.c
new file mode 100644
index 000000000..497a56f59
--- /dev/null
+++ b/drivers/iio/flow/slf3s.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensirion SLF3S liquid flow sensor driver.
+ *
+ * Supports the SLF3S-0600F, SLF3S-1300F and SLF3S-4000B liquid-flow
+ * sensors over I2C.  Each measurement frame returns a 16-bit signed
+ * flow value, a 16-bit signed temperature value and a status word,
+ * each protected by a CRC-8 byte.
+ *
+ * The active calibration medium (water or isopropyl alcohol) is
+ * runtime-switchable via the in_volumeflow_medium sysfs attribute and
+ * defaults to water.
+ *
+ * Datasheet: https://sensirion.com/products/catalog/SLF3S-0600F/
+ *
+ * Copyright (C) 2026 CMBlu Energy GmbH
+ * Author: Wadim Mueller <wafgo01@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+#define SLF3S_CRC8_POLY			0x31
+#define SLF3S_CRC8_INIT			0xff
+
+#define SLF3S_PRODUCT_ID_LEN		18
+#define SLF3S_PRODUCT_FAMILY_BYTE	1
+#define SLF3S_PRODUCT_SUBTYPE_BYTE	3
+#define SLF3S_PRODUCT_FAMILY_ID		0x03
+
+/* Datasheet section 2.2: tPU = 25 ms max from power-on to first cmd. */
+#define SLF3S_POWER_UP_DELAY_US		(25 * USEC_PER_MSEC)
+/* Datasheet section 2.2: tw = 60 ms typical until first valid sample. */
+#define SLF3S_MEAS_START_DELAY_US	(60 * USEC_PER_MSEC)
+
+static const u8 slf3s_cmd_prep_pid[]	= { 0x36, 0x7c };
+static const u8 slf3s_cmd_read_pid[]	= { 0xe1, 0x02 };
+static const u8 slf3s_cmd_start_water[]	= { 0x36, 0x08 };
+static const u8 slf3s_cmd_start_ipa[]	= { 0x36, 0x15 };
+static const u8 slf3s_cmd_stop_meas[]	= { 0x3f, 0xf9 };
+
+enum slf3s_medium {
+	SLF3S_MEDIUM_WATER,
+	SLF3S_MEDIUM_IPA,
+};
+
+static const char * const slf3s_medium_modes[] = {
+	[SLF3S_MEDIUM_WATER]	= "water",
+	[SLF3S_MEDIUM_IPA]	= "ipa",
+};
+
+/**
+ * struct slf3s_variant - per-variant calibration constants
+ * @sub_type:	product-info sub-type byte returned by the sensor
+ * @name:	name reported via @iio_dev.name
+ * @scale_num:	flow scale numerator (l/s per LSB)
+ * @scale_den:	flow scale denominator (l/s per LSB)
+ */
+struct slf3s_variant {
+	u8 sub_type;
+	const char *name;
+	int scale_num;
+	int scale_den;
+};
+
+static const struct slf3s_variant slf3s_variants[] = {
+	[0] = {
+		.sub_type	= 0x03,
+		.name		= "slf3s-0600f",
+		.scale_num	= 1,
+		.scale_den	= 600 * MICRO,
+	},
+	[1] = {
+		.sub_type	= 0x02,
+		.name		= "slf3s-1300f",
+		.scale_num	= 1,
+		.scale_den	= 30 * MICRO,
+	},
+	[2] = {
+		.sub_type	= 0x05,
+		.name		= "slf3s-4000b",
+		.scale_num	= 1,
+		.scale_den	= 1920 * MILLI,
+	},
+};
+
+/**
+ * struct slf3s_data - per-device state
+ * @client:	I2C client this instance is bound to
+ * @variant:	pointer into @slf3s_variants for the detected device
+ * @medium:	currently active calibration medium
+ * @crc_table:	pre-computed CRC-8 lookup table for SLF3S_CRC8_POLY
+ */
+struct slf3s_data {
+	struct i2c_client *client;
+	const struct slf3s_variant *variant;
+	enum slf3s_medium medium;
+	u8 crc_table[CRC8_TABLE_SIZE];
+};
+
+static bool slf3s_crc_valid(const struct slf3s_data *sf, const u8 *block)
+{
+	return crc8(sf->crc_table, block, 2, SLF3S_CRC8_INIT) == block[2];
+}
+
+static int slf3s_send_cmd(struct i2c_client *client, const u8 cmd[at_least 2])
+{
+	int ret = i2c_master_send(client, cmd, 2);
+
+	if (ret == 2)
+		return 0;
+
+	return ret < 0 ? ret : -EIO;
+}
+
+/*
+ * Read the product-info block and pick the matching variant.  The
+ * sub-type byte returned by the sensor is the source of truth; a
+ * DT-supplied compatible only seeds an initial guess and is overridden
+ * on mismatch (with an informational message so misconfigured device
+ * trees are easy to spot).
+ *
+ * Bus / CRC failures are real errors and fail probe.  An unknown
+ * sub-type byte fails probe too: we cannot publish a meaningful scale
+ * without a matching entry in slf3s_variants[].
+ */
+static int slf3s_detect_variant(struct slf3s_data *sf)
+{
+	struct i2c_client *client = sf->client;
+	u8 buf[SLF3S_PRODUCT_ID_LEN];
+	int ret;
+
+	ret = slf3s_send_cmd(client, slf3s_cmd_prep_pid);
+	if (ret)
+		return ret;
+
+	ret = slf3s_send_cmd(client, slf3s_cmd_read_pid);
+	if (ret)
+		return ret;
+
+	ret = i2c_master_recv(client, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+	if (ret != sizeof(buf))
+		return -EIO;
+
+	for (unsigned int i = 0; i < SLF3S_PRODUCT_ID_LEN; i += 3) {
+		if (!slf3s_crc_valid(sf, &buf[i]))
+			return -EIO;
+	}
+
+	if (buf[SLF3S_PRODUCT_FAMILY_BYTE] != SLF3S_PRODUCT_FAMILY_ID)
+		dev_info(&client->dev,
+			 "unexpected family byte 0x%02x (expected 0x%02x)\n",
+			 buf[SLF3S_PRODUCT_FAMILY_BYTE],
+			 SLF3S_PRODUCT_FAMILY_ID);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(slf3s_variants); i++) {
+		if (buf[SLF3S_PRODUCT_SUBTYPE_BYTE] !=
+		    slf3s_variants[i].sub_type)
+			continue;
+
+		if (sf->variant && sf->variant != &slf3s_variants[i])
+			dev_info(&client->dev,
+				 "DT compatible says %s but sensor reports %s; using %s\n",
+				 sf->variant->name,
+				 slf3s_variants[i].name,
+				 slf3s_variants[i].name);
+
+		sf->variant = &slf3s_variants[i];
+
+		return 0;
+	}
+
+	dev_err(&client->dev, "unknown SLF3S sub-type 0x%02x\n",
+		buf[SLF3S_PRODUCT_SUBTYPE_BYTE]);
+
+	return -ENODEV;
+}
+
+static int slf3s_read_sample(struct slf3s_data *sf, int *flow, int *temp)
+{
+	u8 buf[9];
+	int ret;
+
+	ret = i2c_master_recv(sf->client, buf, ARRAY_SIZE(buf));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(buf))
+		return -EIO;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(buf); i += 3) {
+		if (!slf3s_crc_valid(sf, &buf[i]))
+			return -EIO;
+	}
+
+	*flow = sign_extend32(get_unaligned_be16(&buf[0]), 15);
+	*temp = sign_extend32(get_unaligned_be16(&buf[3]), 15);
+
+	return 0;
+}
+
+static int slf3s_get_medium(struct iio_dev *indio_dev,
+			    const struct iio_chan_spec *chan)
+{
+	struct slf3s_data *sf = iio_priv(indio_dev);
+
+	return sf->medium;
+}
+
+static int slf3s_set_medium(struct iio_dev *indio_dev,
+			    const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct slf3s_data *sf = iio_priv(indio_dev);
+	const u8 *start_cmd;
+	int ret;
+
+	if (!iio_device_claim_direct(indio_dev))
+		return -EBUSY;
+
+	ret = slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas);
+	if (ret)
+		goto out;
+
+	start_cmd = (mode == SLF3S_MEDIUM_IPA) ? slf3s_cmd_start_ipa
+					       : slf3s_cmd_start_water;
+
+	ret = slf3s_send_cmd(sf->client, start_cmd);
+	if (ret)
+		goto out;
+
+	fsleep(SLF3S_MEAS_START_DELAY_US);
+	sf->medium = mode;
+out:
+	iio_device_release_direct(indio_dev);
+
+	return ret;
+}
+
+static const struct iio_enum slf3s_medium_enum = {
+	.items		= slf3s_medium_modes,
+	.num_items	= ARRAY_SIZE(slf3s_medium_modes),
+	.get		= slf3s_get_medium,
+	.set		= slf3s_set_medium,
+};
+
+static const struct iio_chan_spec_ext_info slf3s_ext_info[] = {
+	IIO_ENUM("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum),
+	IIO_ENUM_AVAILABLE("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum),
+	{ }
+};
+
+static const struct iio_chan_spec slf3s_channels[] = {
+	{
+		.type = IIO_VOLUMEFLOW,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.ext_info = slf3s_ext_info,
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+	},
+};
+
+static int slf3s_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan, int *val,
+			  int *val2, long mask)
+{
+	struct slf3s_data *sf = iio_priv(indio_dev);
+	int flow, temp, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+
+		ret = slf3s_read_sample(sf, &flow, &temp);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+
+		*val = (chan->type == IIO_VOLUMEFLOW) ? flow : temp;
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_VOLUMEFLOW) {
+			*val = sf->variant->scale_num;
+			*val2 = sf->variant->scale_den;
+
+			return IIO_VAL_FRACTIONAL;
+		}
+		/* Temperature LSB = 1/200 degC; IIO_TEMP wants milli-degC. */
+		*val = 1000 / 200;
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info slf3s_info = {
+	.read_raw = slf3s_read_raw,
+};
+
+static void slf3s_stop_meas(void *data)
+{
+	struct slf3s_data *sf = data;
+
+	slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas);
+}
+
+static int slf3s_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct slf3s_data *sf;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*sf));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	sf = iio_priv(indio_dev);
+	sf->client = client;
+	sf->variant = i2c_get_match_data(client);
+	sf->medium = SLF3S_MEDIUM_WATER;
+	crc8_populate_msb(sf->crc_table, SLF3S_CRC8_POLY);
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable vdd supply\n");
+
+	fsleep(SLF3S_POWER_UP_DELAY_US);
+
+	ret = slf3s_detect_variant(sf);
+	if (ret)
+		return dev_err_probe(dev, ret, "product info read failed\n");
+
+	ret = slf3s_send_cmd(client, slf3s_cmd_start_water);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to start measurement\n");
+
+	fsleep(SLF3S_MEAS_START_DELAY_US);
+
+	ret = devm_add_action_or_reset(dev, slf3s_stop_meas, sf);
+	if (ret)
+		return ret;
+
+	indio_dev->name = sf->variant->name;
+	indio_dev->channels = slf3s_channels;
+	indio_dev->num_channels = ARRAY_SIZE(slf3s_channels);
+	indio_dev->info = &slf3s_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id slf3s_id[] = {
+	{ .name = "slf3s-0600f",
+	  .driver_data = (kernel_ulong_t)&slf3s_variants[0] },
+	{ .name = "slf3s-1300f",
+	  .driver_data = (kernel_ulong_t)&slf3s_variants[1] },
+	{ .name = "slf3s-4000b",
+	  .driver_data = (kernel_ulong_t)&slf3s_variants[2] },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, slf3s_id);
+
+static const struct of_device_id slf3s_of_match[] = {
+	{ .compatible = "sensirion,slf3s-0600f", .data = &slf3s_variants[0] },
+	{ .compatible = "sensirion,slf3s-1300f", .data = &slf3s_variants[1] },
+	{ .compatible = "sensirion,slf3s-4000b", .data = &slf3s_variants[2] },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, slf3s_of_match);
+
+static struct i2c_driver slf3s_driver = {
+	.driver = {
+		.name		= "slf3s",
+		.of_match_table	= slf3s_of_match,
+	},
+	.probe		= slf3s_probe,
+	.id_table	= slf3s_id,
+};
+module_i2c_driver(slf3s_driver);
+
+MODULE_AUTHOR("Wadim Mueller <wafgo01@gmail.com>");
+MODULE_DESCRIPTION("Sensirion SLF3S liquid flow sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.52.0


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

* Re: [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver
  2026-05-30 20:54 ` [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver Wadim Mueller
@ 2026-05-30 21:14   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-05-30 21:14 UTC (permalink / raw)
  To: Wadim Mueller; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Probe fails after a warm reboot or kexec because the sensor is not stopped before reading the product ID.
- [Medium] Missing power management (PM) operations causes device failure after system suspend/resume.
--

commit f4e028602d040a62e916ee2e4f3679882fcd7b4e
Author: Wadim Mueller <wafgo01@gmail.com>

iio: flow: add Sensirion SLF3S liquid flow sensor driver

This adds a new IIO driver for the Sensirion SLF3S family of liquid-flow
sensors. The driver supports reporting volumetric flow rate and temperature
over I2C, and handles switching the calibration medium between water and
isopropyl alcohol at runtime.

> diff --git a/drivers/iio/flow/slf3s.c b/drivers/iio/flow/slf3s.c
> new file mode 100644
> index 0000000000000..497a56f59ff97
> --- /dev/null
> +++ b/drivers/iio/flow/slf3s.c

[ ... ]

> +static int slf3s_detect_variant(struct slf3s_data *sf)
> +{
> +	struct i2c_client *client = sf->client;
> +	u8 buf[SLF3S_PRODUCT_ID_LEN];
> +	int ret;
> +
> +	ret = slf3s_send_cmd(client, slf3s_cmd_prep_pid);
> +	if (ret)
> +		return ret;

[Severity: High]
If the system goes through a warm reboot or kexec, won't the sensor still be
running in continuous measurement mode since there is no .shutdown callback?

If the sensor is actively measuring, will it NACK the 'read product ID'
command sent here and cause the probe to unconditionally fail? Should a stop
measurement command be sent before trying to read the product ID?

[ ... ]

> +static struct i2c_driver slf3s_driver = {
> +	.driver = {
> +		.name		= "slf3s",
> +		.of_match_table	= slf3s_of_match,
> +	},
> +	.probe		= slf3s_probe,
> +	.id_table	= slf3s_id,
> +};
> +module_i2c_driver(slf3s_driver);

[Severity: Medium]
Since the driver lacks power management operations, what happens when the
system suspends and resumes?

If power is cut to the sensor during suspend, won't it reset to the IDLE
state and cause subsequent IIO reads to fail because the driver never
re-issues the start command? Or if power isn't cut, will leaving it actively
measuring waste power?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260530205435.37326-1-wafgo01@gmail.com?part=3

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

end of thread, other threads:[~2026-05-30 21:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-30 20:54 [PATCH v3 0/3] iio: flow: Sensirion SLF3S liquid flow sensor Wadim Mueller
2026-05-30 20:54 ` [PATCH v3 1/3] iio: types: add IIO_VOLUMEFLOW channel type Wadim Mueller
2026-05-30 20:54 ` [PATCH v3 2/3] dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor Wadim Mueller
2026-05-30 20:54 ` [PATCH v3 3/3] iio: flow: add Sensirion SLF3S liquid flow sensor driver Wadim Mueller
2026-05-30 21:14   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox