Skip to contentSkip to conversation

iio: mcp9600: Features and improvements

PATCH Superseded Ben Collins 7 participants 23 messages Aug 18, 2025 – Aug 19, 2025

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

v5 cover iio: mcp9600: Features and improvements

ChangeLog:
v4 -> v5:
- Missed a one line fix to IIR patch (5/5)

v3 -> v4:
- Based on feedback from David Lechner <[email protected]>
* Allow fallback compatible in dt-bindings for mcp9601.
- Based on feedback from Jonathan Cameron <[email protected]>
* Be explicit in patch description for fixed width changes.
* Check chip_info for NULL to quiet warnings from kernel-test-robot
* Remove "and similar" for long description of MCP9600.
- Based on lots of feedback, use frequency values for IIR, and use filter_type[none, ema] to enable or disable.
- Set default 3 for thermocouple in dt-binding
- Rework open/short circuit in dt-bindings

v2 -> v3:
- Improve changelogs in each patch
- Based on feedback from Andy Shevchenko <[email protected]>
* Set register offsets to fixed width
* Fix typos
* Future-proof Kconfig changes
* Convert to using chip_info paradigm
* Verbiage: dt -> firmware description
* Use proper specifiers and drop castings
* Fix register offset to be fixed-width
* u8 for cfg var
* Fix % type for u32 to be %u
* Make blank lines consistent between case statements
* FIELD_PREP -> FIELD_MODIFY
* Remove explicit setting of 0 value in filter_level
- Based on feedback from David Lechner <[email protected]>
* Rework IIR values exposed to sysfs. Using the ratios, there was no way to represent "disabled" (i.e. infinity). Based on the bmp280 driver I went with using the power coefficients (e.g. 1, 2, 4, 8, ...) where 1 is disabled (n=0).

v1 -> v2:
- Break into individual patches

v1:
- Initial patch to enable IIR and thermocouple-type
- Recognize mcp9601

Ben Collins (5):
dt-bindings: iio: mcp9600: Add compatible for microchip,mcp9601
iio: mcp9600: White space and fixed width cleanup
iio: mcp9600: Recognize chip id for mcp9601
iio: mcp9600: Add support for thermocouple-type
iio: mcp9600: Add support for IIR filter

 .../iio/temperature/microchip,mcp9600.yaml    |  25 +-
 drivers/iio/temperature/Kconfig               |   8 +-
 drivers/iio/temperature/mcp9600.c             | 220 ++++++++++++++++--
 3 files changed, 231 insertions(+), 22 deletions(-)
Signature · 1 line
2.39.5
#1 lore raw

PATCH v5 1/5 dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

From: Ben Collins <[email protected]>

The mcp9600 driver supports the mcp9601 chip, but complains about not recognizing the device id on probe. A separate patch...

iio: mcp9600: Recognize chip id for mcp9601

...addresses this. This patch updates the dt-bindings for this chip to reflect the change to allow explicitly setting microchip,mcp9601 as the expected chip type.

The mcp9601 also supports features not found on the mcp9600, so this will also allow the driver to differentiate the support of these features.

In addition, the thermocouple-type needs a default of 3 (k-type). The driver doesn't support this, yet. A later patch in this series adds it:

iio: mcp9600: Add support for thermocouple-type

Lastly, the open/short circuit functionality is dependent on mcp9601 chipsset. Add constraints for this and a new property, microchip,vsense, enables this feature since it depends on the chip being wired properly.

Passed dt_binding_check.

---
 .../iio/temperature/microchip,mcp9600.yaml    | 69 +++++++++++++++----
 1 file changed, 56 insertions(+), 13 deletions(-)
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +56 -13
index d2cafa38a5442..1caeb6526fd20 100644
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Microchip MCP9600 thermocouple EMF converter
+title: Microchip MCP9600 and similar thermocouple EMF converters
 
 maintainers:
   - Andrew Hepp <[email protected]>
@@ -14,29 +14,30 @@ description:
 
 properties:
   compatible:
-    const: microchip,mcp9600
+    oneOf:
+      - const: microchip,mcp9600
+      - items:
+          - const: microchip,mcp9600
+          - const: microchip,mcp9601
 
   reg:
     maxItems: 1
 
   interrupts:
     minItems: 1
-    maxItems: 6
+    maxItems: 4
 
   interrupt-names:
     minItems: 1
-    maxItems: 6
     items:
-      enum:
-        - open-circuit
-        - short-circuit
-        - alert1
-        - alert2
-        - alert3
-        - alert4
+      - const: alert1
+      - const: alert2
+      - const: alert3
+      - const: alert4
 
   thermocouple-type:
     $ref: /schemas/types.yaml#/definitions/uint32
+    default: 3
     description:
       Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted).
       Use defines in dt-bindings/iio/temperature/thermocouple.h.
@@ -44,6 +45,33 @@ properties:
 
   vdd-supply: true
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: microchip,mcp9601
+    then:
+      properties:
+        interrupts:
+          minItems: 1
+          maxItems: 6
+        interrupt-names:
+          items:
+            - const: alert1
+            - const: alert2
+            - const: alert3
+            - const: alert4
+            - const: open-circuit
+            - const: short-circuit
+        microchip,vsense:
+          default: false
+          description:
+            This flag indicates that the chip has been wired with VSENSE to
+            enable open and short circuit detect. By default, this is false,
+            since there's no way to detect that the chip is wired correctly.
+          type: boolean
+
 required:
   - compatible
   - reg
@@ -62,9 +90,24 @@ examples:
             compatible = "microchip,mcp9600";
             reg = <0x60>;
             interrupt-parent = <&gpio>;
-            interrupts = <25 IRQ_TYPE_EDGE_RISING>;
-            interrupt-names = "open-circuit";
+            interrupts = <25 IRQ_TYPE_EDGE_RISIN>;
+            interrupt-names = "alert1";
             thermocouple-type = <THERMOCOUPLE_TYPE_K>;
             vdd-supply = <&vdd>;
         };
     };
+  - |
+    #include <dt-bindings/iio/temperature/thermocouple.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        temperature-sensor@60 {
+            compatible = "microchip,mcp9601", "microchip,mcp9600";
+            microchip,vsense;
+            reg = <0x62>;
+            interrupt-parent = <&gpio>;
+            vdd-supply = <&vdd>;
+        };
+    };
Signature · 1 line
2.39.5
#2 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

Quoted 11 lines · Ben Collins

From: Ben Collins <[email protected]>

The mcp9600 driver supports the mcp9601 chip, but complains about not recognizing the device id on probe. A separate patch...

iio: mcp9600: Recognize chip id for mcp9601

...addresses this. This patch updates the dt-bindings for this chip to reflect the change to allow explicitly setting microchip,mcp9601 as the expected chip type.

Quoted 7 lines

The mcp9601 also supports features not found on the mcp9600, so this will also allow the driver to differentiate the support of these features.

In addition, the thermocouple-type needs a default of 3 (k-type). The driver doesn't support this, yet. A later patch in this series adds it:

None of this driver argument here and earlier is relevant. Please describe the hardware and reasons behind this patch.

Quoted 8 lines

iio: mcp9600: Add support for thermocouple-type

Lastly, the open/short circuit functionality is dependent on mcp9601 chipsset. Add constraints for this and a new property, microchip,vsense, enables this feature since it depends on the chip being wired properly.

Passed dt_binding_check.

Drop, not relevant. You do not have to say that you built your code. You must build your code.

Quoted 27 lines
---
 .../iio/temperature/microchip,mcp9600.yaml    | 69 +++++++++++++++----
 1 file changed, 56 insertions(+), 13 deletions(-)
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +4 -2
index d2cafa38a5442..1caeb6526fd20 100644
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Microchip MCP9600 thermocouple EMF converter
+title: Microchip MCP9600 and similar thermocouple EMF converters
 
 maintainers:
   - Andrew Hepp <[email protected]>
@@ -14,29 +14,30 @@ description:
 
 properties:
   compatible:
-    const: microchip,mcp9600
+    oneOf:
+      - const: microchip,mcp9600
+      - items:

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml description: · line 28

Quoted 10 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +3 -1
+          - const: microchip,mcp9600
+          - const: microchip,mcp9601
 
   reg:
     maxItems: 1
 
   interrupts:
     minItems: 1
-    maxItems: 6
+    maxItems: 4

Why?
I did not find explanation of this in commit msg.

Quoted 6 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +0 -2
   interrupt-names:
     minItems: 1
-    maxItems: 6
     items:
-      enum:

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml description: · line 36

Quoted 10 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +4 -6
-        - open-circuit
-        - short-circuit
-        - alert1
-        - alert2
-        - alert3
-        - alert4
+      - const: alert1
+      - const: alert2
+      - const: alert3
+      - const: alert4

Neither this and it is ABI break. ABI breaking needs clear reasoning why and some evaluation of impact on users.

Quoted 22 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +12 -0
   thermocouple-type:
     $ref: /schemas/types.yaml#/definitions/uint32
+    default: 3
     description:
       Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted).
       Use defines in dt-bindings/iio/temperature/thermocouple.h.
@@ -44,6 +45,33 @@ properties:
 
   vdd-supply: true
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: microchip,mcp9601
+    then:
+      properties:
+        interrupts:
+          minItems: 1
+          maxItems: 6

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml properties: · line 68

Quoted 10 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +10 -0
+        interrupt-names:
+          items:
+            - const: alert1
+            - const: alert2
+            - const: alert3
+            - const: alert4
+            - const: open-circuit
+            - const: short-circuit
+        microchip,vsense:
+          default: false

There is no default for bool.

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml properties: · line 72

Quoted 4 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +4 -0
+          description:
+            This flag indicates that the chip has been wired with VSENSE to
+            enable open and short circuit detect. By default, this is false,
+            since there's no way to detect that the chip is wired correctly.

Properties should be defined in top level. Here you only disallow them (see example schema).

Quoted 19 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +6 -2
+          type: boolean
+
 required:
   - compatible
   - reg
@@ -62,9 +90,24 @@ examples:
             compatible = "microchip,mcp9600";
             reg = <0x60>;
             interrupt-parent = <&gpio>;
-            interrupts = <25 IRQ_TYPE_EDGE_RISING>;
-            interrupt-names = "open-circuit";
+            interrupts = <25 IRQ_TYPE_EDGE_RISIN>;
+            interrupt-names = "alert1";
             thermocouple-type = <THERMOCOUPLE_TYPE_K>;
             vdd-supply = <&vdd>;
         };
     };
+  - |
+    #include <dt-bindings/iio/temperature/thermocouple.h>

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml examples: · line 110

Quoted 10 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +10 -0
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        temperature-sensor@60 {
+            compatible = "microchip,mcp9601", "microchip,mcp9600";
+            microchip,vsense;
+            reg = <0x62>;
+            interrupt-parent = <&gpio>;

Incomplete interrupts.

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml examples: · line 113

Quoted 3 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +3 -0
+            vdd-supply = <&vdd>;
+        };
+    };

Best regards,
Krzysztof

#3 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

Quoted 8 lines · Krzysztof Kozlowski

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml description: · line 28

Quoted 4 lines · Ben Collins

interrupts:
minItems: 1

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +1 -1
-    maxItems: 6
+    maxItems: 4

Why?
I did not find explanation of this in commit msg.

It's also not correct, since the outermost constraint remains 6 after the patch, so the if/else should reduce the constraints, rather than increase it as is done here.

Quoted 18 lines
Quoted 7 lines

interrupt-names:
minItems: 1

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +0 -2
-    maxItems: 6
     items:
-      enum:

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml description: · line 36

Quoted 10 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +4 -6
-        - open-circuit
-        - short-circuit
-        - alert1
-        - alert2
-        - alert3
-        - alert4
+      - const: alert1
+      - const: alert2
+      - const: alert3
+      - const: alert4
Quoted 2 lines

Neither this and it is ABI break. ABI breaking needs clear reasoning why and some evaluation of impact on users.

I think it should be a standalone patch too, since it is a fix for the existing mcp9600 device rather than something for the mcp9601 device that is being added by this patch...

Quoted 6 lines
Quoted 6 lines

thermocouple-type:
$ref: /schemas/types.yaml#/definitions/uint32
+ default: 3

As is this, which is codifying the existing restriction rather than being something new as 0x03 is what THERMOCOUPLE_TYPE_K is defined to be.

Quoted 3 lines
Quoted 3 lines

description:
Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted). Use defines in dt-bindings/iio/temperature/thermocouple.h.

#4 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

In reply to Ben Collins
Quoted 25 lines · Ben Collins

From: Ben Collins <[email protected]>

The mcp9600 driver supports the mcp9601 chip, but complains about not recognizing the device id on probe. A separate patch...

iio: mcp9600: Recognize chip id for mcp9601

...addresses this. This patch updates the dt-bindings for this chip to reflect the change to allow explicitly setting microchip,mcp9601 as the expected chip type.

The mcp9601 also supports features not found on the mcp9600, so this will also allow the driver to differentiate the support of these features.

In addition, the thermocouple-type needs a default of 3 (k-type). The driver doesn't support this, yet. A later patch in this series adds it:

iio: mcp9600: Add support for thermocouple-type

Lastly, the open/short circuit functionality is dependent on mcp9601 chipsset. Add constraints for this and a new property, microchip,vsense, enables this feature since it depends on the chip being wired properly.

Quoted 7 lines

Passed dt_binding_check.

---
 .../iio/temperature/microchip,mcp9600.yaml    | 69 +++++++++++++++----
 1 file changed, 56 insertions(+), 13 deletions(-)

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

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.example.dts:34.34-35 syntax error FATAL ERROR: Unable to parse input tree
make[2]: *** [scripts/Makefile.dtbs:131: Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.example.dtb] Error 1 make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1527: dt_binding_check] Error 2
make: *** [Makefile:248: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

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.

#5 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

Quoted 11 lines · Rob Herring (Arm)
Quoted 2 lines · Ben Collins

From: Ben Collins <[email protected]>

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.example.dts:34.34-35 syntax error FATAL ERROR: Unable to parse input tree
make[2]: *** [scripts/Makefile.dtbs:131: Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.example.dtb] Error 1 make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1527: dt_binding_check] Error 2
make: *** [Makefile:248: __sub-make] Error 2

Thanks. Found this already and fix will be in v6.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
#6 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

In reply to Ben Collins
Quoted 18 lines · Ben Collins

From: Ben Collins <[email protected]>

The mcp9600 driver supports the mcp9601 chip, but complains about not recognizing the device id on probe. A separate patch...

iio: mcp9600: Recognize chip id for mcp9601

...addresses this. This patch updates the dt-bindings for this chip to reflect the change to allow explicitly setting microchip,mcp9601 as the expected chip type.

The mcp9601 also supports features not found on the mcp9600, so this will also allow the driver to differentiate the support of these features.

In addition, the thermocouple-type needs a default of 3 (k-type). The driver doesn't support this, yet. A later patch in this series adds it:

Quoted 8 lines

iio: mcp9600: Add support for thermocouple-type

Lastly, the open/short circuit functionality is dependent on mcp9601 chipsset. Add constraints for this and a new property, microchip,vsense, enables this feature since it depends on the chip being wired properly.

Passed dt_binding_check.

Yeah...

...

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml examples: · line 93

Quoted 3 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +1 -2
-            interrupts = <25 IRQ_TYPE_EDGE_RISING>;
-            interrupt-names = "open-circuit";
+            interrupts = <25 IRQ_TYPE_EDGE_RISIN>;

Except that it wasn't it. You need to test your final code, after you commit. Mentioning that you tested it and then actually do not test and send something which does not build, heh...

Best regards,
Krzysztof

#7 lore raw

Re: [PATCH v5 1/5] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints

Quoted 33 lines · Krzysztof Kozlowski
Quoted 18 lines · Ben Collins

From: Ben Collins <[email protected]>

The mcp9600 driver supports the mcp9601 chip, but complains about not recognizing the device id on probe. A separate patch...

iio: mcp9600: Recognize chip id for mcp9601

...addresses this. This patch updates the dt-bindings for this chip to reflect the change to allow explicitly setting microchip,mcp9601 as the expected chip type.

The mcp9601 also supports features not found on the mcp9600, so this will also allow the driver to differentiate the support of these features.

In addition, the thermocouple-type needs a default of 3 (k-type). The driver doesn't support this, yet. A later patch in this series adds it:

Quoted 8 lines

iio: mcp9600: Add support for thermocouple-type

Lastly, the open/short circuit functionality is dependent on mcp9601 chipsset. Add constraints for this and a new property, microchip,vsense, enables this feature since it depends on the chip being wired properly.

Passed dt_binding_check.

Yeah...

...

Quoted 7 lines

Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml examples: · line 93

Quoted 3 lines
Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +1 -2
-            interrupts = <25 IRQ_TYPE_EDGE_RISING>;
-            interrupt-names = "open-circuit";
+            interrupts = <25 IRQ_TYPE_EDGE_RISIN>;

Except that it wasn't it. You need to test your final code, after you commit. Mentioning that you tested it and then actually do not test and send something which does not build, heh...

I actually did, and fixed it, but it didn't make it into the commit when I emailed.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
#8 lore raw

PATCH v5 2/5 iio: mcp9600: White space and fixed width cleanup

In reply to Ben Collins

From: Ben Collins <[email protected]>

Make tabs consistent for register definitions and also fix width to byte size.

---
 drivers/iio/temperature/mcp9600.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/iio/temperature/mcp9600.c +7 -7
index 6e9108d5cf75f..40906bb200ec9 100644
@@ -23,25 +23,25 @@
 #include <linux/iio/iio.h>
 
 /* MCP9600 registers */
-#define MCP9600_HOT_JUNCTION 0x0
-#define MCP9600_COLD_JUNCTION 0x2
-#define MCP9600_STATUS			0x4
+#define MCP9600_HOT_JUNCTION		0x00
+#define MCP9600_COLD_JUNCTION		0x02
+#define MCP9600_STATUS			0x04
 #define MCP9600_STATUS_ALERT(x)		BIT(x)
-#define MCP9600_ALERT_CFG1		0x8
+#define MCP9600_ALERT_CFG1		0x08
 #define MCP9600_ALERT_CFG(x)		(MCP9600_ALERT_CFG1 + (x - 1))
 #define MCP9600_ALERT_CFG_ENABLE	BIT(0)
 #define MCP9600_ALERT_CFG_ACTIVE_HIGH	BIT(2)
 #define MCP9600_ALERT_CFG_FALLING	BIT(3)
 #define MCP9600_ALERT_CFG_COLD_JUNCTION	BIT(4)
-#define MCP9600_ALERT_HYSTERESIS1	0xc
+#define MCP9600_ALERT_HYSTERESIS1	0x0c
 #define MCP9600_ALERT_HYSTERESIS(x)	(MCP9600_ALERT_HYSTERESIS1 + (x - 1))
 #define MCP9600_ALERT_LIMIT1		0x10
 #define MCP9600_ALERT_LIMIT(x)		(MCP9600_ALERT_LIMIT1 + (x - 1))
 #define MCP9600_ALERT_LIMIT_MASK	GENMASK(15, 2)
-#define MCP9600_DEVICE_ID 0x20
+#define MCP9600_DEVICE_ID		0x20
 
 /* MCP9600 device id value */
-#define MCP9600_DEVICE_ID_MCP9600 0x40
+#define MCP9600_DEVICE_ID_MCP9600	0x40
 
 #define MCP9600_ALERT_COUNT		4
 
Signature · 1 line
2.39.5
#9 lore raw

PATCH v5 3/5 iio: mcp9600: Recognize chip id for mcp9601

In reply to Ben Collins

From: Ben Collins <[email protected]>

The current driver works with mcp9601, but emits a warning because it does not recognize the chip id.

MCP9601 is a superset of MCP9600. The drivers works without changes on this chipset.

However, the 9601 chip supports open/closed-circuit detection if wired properly, so we'll need to be able to differentiate between them.

---
 drivers/iio/temperature/Kconfig   |  8 +++--
 drivers/iio/temperature/mcp9600.c | 55 +++++++++++++++++++++++++------
 2 files changed, 50 insertions(+), 13 deletions(-)
drivers/iio/temperature/Kconfig +5 -3
index 1244d8e17d504..9328b2250aced 100644
@@ -173,11 +173,13 @@ config MAX31865
 	  will be called max31865.
 
 config MCP9600
-	tristate "MCP9600 thermocouple EMF converter"
+	tristate "MCP9600 and similar thermocouple EMF converters"
 	depends on I2C
 	help
-	  If you say yes here you get support for MCP9600
-	  thermocouple EMF converter connected via I2C.
+	  If you say yes here you get support for...
+	  - MCP9600
+	  - MCP9601
+	  ...thermocouple EMF converters connected via I2C.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called mcp9600.
drivers/iio/temperature/mcp9600.c +45 -10

94 lines not on this page · raw message

Signature · 1 line
2.39.5
maintainer
#10 lore raw

Re: [PATCH v5 3/5] iio: mcp9600: Recognize chip id for mcp9601

Quoted 5 lines · On Sun, 17 Aug 2025 23:59:51 -0400 Ben Collins <[email protected]> wrote:

From: Ben Collins <[email protected]>

The current driver works with mcp9601, but emits a warning because it does not recognize the chip id.

Quoted 7 lines

MCP9601 is a superset of MCP9600. The drivers works without changes on this chipset.

However, the 9601 chip supports open/closed-circuit detection if wired properly, so we'll need to be able to differentiate between them.

Hi Ben

One minor thing inline that need fixing up.

Quoted 9 lines
drivers/iio/temperature/mcp9600.c +0 -0
index 40906bb200ec9..54de38a39292e 100644
@@ -42,6 +42,7 @@
 
@@ -416,16 +422,33 @@ static int mcp9600_probe_alerts(struct iio_dev *indio_dev)
 
 static int mcp9600_probe(struct i2c_client *client)

drivers/iio/temperature/mcp9600.c static int mcp9600_probe_alerts(struct iio_dev *indio_dev) · line 432

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +6 -1
 {
+	const struct mcp_chip_info *chip_info = i2c_get_match_data(client);
 	struct iio_dev *indio_dev;
 	struct mcp9600_data *data;
-	int ret, ch_sel;
+	int ch_sel, dev_id, ret;
+
+	if (chip_info == NULL)
+		return dev_err_probe(&client->dev, -EINVAL,
+                                     "No chip-info found for device\n");

This line seems to be indented with spaces, not tabs then spaces which is the coding style. I only noticed because of the shift seen in this reply.

Quoted 25 lines
drivers/iio/temperature/mcp9600.c +18 -6
+
+	dev_id = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID);
+	if (dev_id < 0)
+		return dev_err_probe(&client->dev, dev_id,
+				     "Failed to read device ID\n");
+
+	switch (dev_id) {
+	case MCP9600_DEVICE_ID_MCP9600:
+	case MCP9600_DEVICE_ID_MCP9601:
+		if (dev_id != chip_info->chip_id)
+			dev_warn(&client->dev,
+				 "Expected id %02x, but device responded with %02x\n",
+				 chip_info->chip_id, dev_id);
+		break;
 
-	ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID);
-	if (ret < 0)
-		return dev_err_probe(&client->dev, ret, "Failed to read device ID\n");
-	if (ret != MCP9600_DEVICE_ID_MCP9600)
-		dev_warn(&client->dev, "Expected ID %x, got %x\n",
-				MCP9600_DEVICE_ID_MCP9600, ret);
+	default:
+		dev_warn(&client->dev, "Unknown id %x, using %x\n", dev_id,
+			 chip_info->chip_id);
+	}
#11 lore raw

PATCH v5 4/5 iio: mcp9600: Add support for thermocouple-type

In reply to Ben Collins

From: Ben Collins <[email protected]>

dt-bindings documentation for this driver claims to support thermocouple-type, but the driver does not actually make use of the property.

Implement usage of the property to configure the chip for the selected thermocouple-type.

---
 drivers/iio/temperature/mcp9600.c | 69 +++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
drivers/iio/temperature/mcp9600.c +69 -0
index 54de38a39292e..fa382a988a991 100644
@@ -22,11 +22,15 @@
 #include <linux/iio/events.h>
 #include <linux/iio/iio.h>
 
+#include <dt-bindings/iio/temperature/thermocouple.h>
+
 /* MCP9600 registers */
 #define MCP9600_HOT_JUNCTION		0x00
 #define MCP9600_COLD_JUNCTION		0x02
 #define MCP9600_STATUS			0x04
 #define MCP9600_STATUS_ALERT(x)		BIT(x)
+#define MCP9600_SENSOR_CFG		0x05
+#define MCP9600_SENSOR_TYPE_MASK	GENMASK(6, 4)
 #define MCP9600_ALERT_CFG1		0x08
 #define MCP9600_ALERT_CFG(x)		(MCP9600_ALERT_CFG1 + (x - 1))
 #define MCP9600_ALERT_CFG_ENABLE	BIT(0)
@@ -66,6 +70,30 @@ static const char * const mcp9600_alert_name[MCP9600_ALERT_COUNT] = {
 	[MCP9600_ALERT4] = "alert4",
 };
 
+/* Map between dt-bindings enum and the chip's type value */
+static const unsigned int mcp9600_type_map[] = {
+	[THERMOCOUPLE_TYPE_K] = 0,
+	[THERMOCOUPLE_TYPE_J] = 1,
+	[THERMOCOUPLE_TYPE_T] = 2,
+	[THERMOCOUPLE_TYPE_N] = 3,
+	[THERMOCOUPLE_TYPE_S] = 4,
+	[THERMOCOUPLE_TYPE_E] = 5,
+	[THERMOCOUPLE_TYPE_B] = 6,
+	[THERMOCOUPLE_TYPE_R] = 7,
+};
+
+/* Map thermocouple type to a char for for iio info in sysfs */
+static const int mcp9600_tc_types[] = {
+	[THERMOCOUPLE_TYPE_K] = 'K',
+	[THERMOCOUPLE_TYPE_J] = 'J',
+	[THERMOCOUPLE_TYPE_T] = 'T',
+	[THERMOCOUPLE_TYPE_N] = 'N',
+	[THERMOCOUPLE_TYPE_S] = 'S',
+	[THERMOCOUPLE_TYPE_E] = 'E',
+	[THERMOCOUPLE_TYPE_B] = 'B',
+	[THERMOCOUPLE_TYPE_R] = 'R',
+};
+
 static const struct iio_event_spec mcp9600_events[] = {
 	{
 		.type = IIO_EV_TYPE_THRESH,
@@ -89,6 +117,7 @@ static const struct iio_event_spec mcp9600_events[] = {
 			.type = IIO_TEMP,				       \
 			.address = MCP9600_HOT_JUNCTION,		       \
 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	       \
+					      BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE) | \
 					      BIT(IIO_CHAN_INFO_SCALE),	       \
 			.event_spec = &mcp9600_events[hj_ev_spec_off],	       \
 			.num_event_specs = hj_num_ev,			       \
@@ -131,6 +160,7 @@ struct mcp_chip_info {
 
 struct mcp9600_data {
 	struct i2c_client *client;
+	u32 thermocouple_type;
 };
 
 static int mcp9600_read(struct mcp9600_data *data,
@@ -165,11 +195,32 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
+		*val = mcp9600_tc_types[data->thermocouple_type];
+		return IIO_VAL_CHAR;
 	default:
 		return -EINVAL;
 	}
 }
 
+static int mcp9600_config(struct mcp9600_data *data)
+{
+	struct i2c_client *client = data->client;
+	int ret;
+	u8 cfg;
+
+	cfg  = FIELD_PREP(MCP9600_SENSOR_TYPE_MASK,
+			  mcp9600_type_map[data->thermocouple_type]);
+
+	ret = i2c_smbus_write_byte_data(client, MCP9600_SENSOR_CFG, cfg);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to set sensor configuration\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
 {
 	if (channel2 == IIO_MOD_TEMP_AMBIENT) {
@@ -457,6 +508,24 @@ static int mcp9600_probe(struct i2c_client *client)
 	data = iio_priv(indio_dev);
 	data->client = client;
 
+	/* Accept type from dt with default of Type-K. */
+	data->thermocouple_type = THERMOCOUPLE_TYPE_K;
+	ret = device_property_read_u32(&client->dev, "thermocouple-type",
+				       &data->thermocouple_type);
+	if (ret < 0 && ret != -EINVAL)
+		return dev_err_probe(&client->dev, ret,
+				     "Error reading thermocouple-type property\n");
+
+	if (data->thermocouple_type >= ARRAY_SIZE(mcp9600_type_map))
+		return dev_err_probe(&client->dev, -EINVAL,
+				     "Invalid thermocouple-type property %u.\n",
+				     data->thermocouple_type);
+
+	/* Set initial config. */
+	ret = mcp9600_config(data);
+	if (ret < 0)
+		return ret;
+
 	ch_sel = mcp9600_probe_alerts(indio_dev);
 	if (ch_sel < 0)
 		return ch_sel;
Signature · 1 line
2.39.5
#12 lore raw

PATCH v5 5/5 iio: mcp9600: Add support for IIR filter

In reply to Ben Collins

From: Ben Collins <[email protected]>

MCP9600 supports an IIR filter with 7 levels. Add IIR attribute to allow get/set of this value.

Use a filter_type[none, ema] for enabling the IIR filter.

---
 drivers/iio/temperature/mcp9600.c | 157 ++++++++++++++++++++++++++++++
 1 file changed, 157 insertions(+)
drivers/iio/temperature/mcp9600.c +157 -0
index fa382a988a991..54bc657460e5d 100644
@@ -31,6 +31,7 @@
 #define MCP9600_STATUS_ALERT(x)		BIT(x)
 #define MCP9600_SENSOR_CFG		0x05
 #define MCP9600_SENSOR_TYPE_MASK	GENMASK(6, 4)
+#define MCP9600_FILTER_MASK		GENMASK(2, 0)
 #define MCP9600_ALERT_CFG1		0x08
 #define MCP9600_ALERT_CFG(x)		(MCP9600_ALERT_CFG1 + (x - 1))
 #define MCP9600_ALERT_CFG_ENABLE	BIT(0)
@@ -94,6 +95,27 @@ static const int mcp9600_tc_types[] = {
 	[THERMOCOUPLE_TYPE_R] = 'R',
 };
 
+enum mcp9600_filter {
+	MCP9600_FILTER_TYPE_NONE,
+	MCP9600_FILTER_TYPE_EMA,
+};
+
+static const char * const mcp9600_filter_type[] = {
+	[MCP9600_FILTER_TYPE_NONE] = "none",
+	[MCP9600_FILTER_TYPE_EMA] = "ema",
+};
+
+static const int mcp_iir_coefficients_avail[7][2] = {
+	/* Level 0 is no filter */
+	{ 0, 524549 },
+	{ 0, 243901 },
+	{ 0, 119994 },
+	{ 0,  59761 },
+	{ 0,  29851 },
+	{ 0,  14922 },
+	{ 0,   7461 },
+};
+
 static const struct iio_event_spec mcp9600_events[] = {
 	{
 		.type = IIO_EV_TYPE_THRESH,
@@ -118,7 +140,11 @@ static const struct iio_event_spec mcp9600_events[] = {
 			.address = MCP9600_HOT_JUNCTION,		       \
 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	       \
 					      BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE) | \
+					      BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |  \
 					      BIT(IIO_CHAN_INFO_SCALE),	       \
+			.info_mask_separate_available =                        \
+					      BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+			.ext_info = mcp9600_ext_filter,			       \
 			.event_spec = &mcp9600_events[hj_ev_spec_off],	       \
 			.num_event_specs = hj_num_ev,			       \
 		},							       \
@@ -134,6 +160,26 @@ static const struct iio_event_spec mcp9600_events[] = {
 		},							       \
 	}
 
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan);
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode);
+
+static const struct iio_enum mcp9600_filter_enum = {
+	.items = mcp9600_filter_type,
+	.num_items = ARRAY_SIZE(mcp9600_filter_type),
+	.get = mcp9600_get_filter,
+	.set = mcp9600_set_filter,
+};
+
+static const struct iio_chan_spec_ext_info mcp9600_ext_filter[] = {
+	IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &mcp9600_filter_enum),
+	IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL,
+			   &mcp9600_filter_enum),
+	{ }
+};
+
 static const struct iio_chan_spec mcp9600_channels[][2] = {
 	MCP9600_CHANNELS(0, 0, 0, 0), /* Alerts: - - - - */
 	MCP9600_CHANNELS(1, 0, 0, 0), /* Alerts: 1 - - - */
@@ -161,6 +207,8 @@ struct mcp_chip_info {
 struct mcp9600_data {
 	struct i2c_client *client;
 	u32 thermocouple_type;
+	/* Filter enabled is 1-7, with 0 being off (filter_type none) */
+	u8 filter_level;
 };
 
 static int mcp9600_read(struct mcp9600_data *data,
@@ -191,13 +239,45 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
 		if (ret)
 			return ret;
 		return IIO_VAL_INT;
+
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)
+			return -EINVAL;
+
+		*val = mcp_iir_coefficients_avail[data->filter_level - 1][0];
+		*val2 = mcp_iir_coefficients_avail[data->filter_level - 1][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_read_avail(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      const int **vals, int *type, int *length,
+			      long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)
+			return -EINVAL;
+
+		*vals = (int *)mcp_iir_coefficients_avail;
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = 2 * ARRAY_SIZE(mcp_iir_coefficients_avail);
+		return IIO_AVAIL_LIST;
 	default:
 		return -EINVAL;
 	}
@@ -211,6 +291,7 @@ static int mcp9600_config(struct mcp9600_data *data)
 
 	cfg  = FIELD_PREP(MCP9600_SENSOR_TYPE_MASK,
 			  mcp9600_type_map[data->thermocouple_type]);
+	FIELD_MODIFY(MCP9600_FILTER_MASK, &cfg, data->filter_level);
 
 	ret = i2c_smbus_write_byte_data(client, MCP9600_SENSOR_CFG, cfg);
 	if (ret < 0) {
@@ -221,6 +302,79 @@ static int mcp9600_config(struct mcp9600_data *data)
 	return 0;
 }
 
+static int mcp9600_write_raw_get_fmt(struct iio_dev *indio_dev,
+				     struct iio_chan_spec const *chan,
+				     long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+	int i;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		for (i = 0; i < ARRAY_SIZE(mcp_iir_coefficients_avail); i++) {
+			if (mcp_iir_coefficients_avail[i][0] == val &&
+			    mcp_iir_coefficients_avail[i][1] == val2)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(mcp_iir_coefficients_avail))
+			return -EINVAL;
+
+		data->filter_level = i + 1;
+		return mcp9600_config(data);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	if (data->filter_level == 0)
+		return MCP9600_FILTER_TYPE_NONE;
+
+	return MCP9600_FILTER_TYPE_EMA;
+}
+
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	switch (mode) {
+	case MCP9600_FILTER_TYPE_NONE:
+		data->filter_level = 0;
+		return mcp9600_config(data);
+
+	case MCP9600_FILTER_TYPE_EMA:
+		if (data->filter_level == 0) {
+			/* Minimum filter by default */
+			data->filter_level = 1;
+			return mcp9600_config(data);
+		}
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
 {
 	if (channel2 == IIO_MOD_TEMP_AMBIENT) {
@@ -358,6 +512,9 @@ static int mcp9600_write_thresh(struct iio_dev *indio_dev,
 
 static const struct iio_info mcp9600_info = {
 	.read_raw = mcp9600_read_raw,
+	.read_avail = mcp9600_read_avail,
+	.write_raw = mcp9600_write_raw,
+	.write_raw_get_fmt = mcp9600_write_raw_get_fmt,
 	.read_event_config = mcp9600_read_event_config,
 	.write_event_config = mcp9600_write_event_config,
 	.read_event_value = mcp9600_read_thresh,
Signature · 1 line
2.39.5
maintainer
#13 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 6 lines · On Sun, 17 Aug 2025 23:59:53 -0400 Ben Collins <[email protected]> wrote:

From: Ben Collins <[email protected]>

MCP9600 supports an IIR filter with 7 levels. Add IIR attribute to allow get/set of this value.

Use a filter_type[none, ema] for enabling the IIR filter.

Hi Ben,

A few comments inline. You also need to send an additional patch to update the filter_type docs in Documentation/ABI/testing/sysfs-bus-iio

Thanks,

Jonathan

Quoted 47 lines
---
 drivers/iio/temperature/mcp9600.c | 157 ++++++++++++++++++++++++++++++
 1 file changed, 157 insertions(+)
drivers/iio/temperature/mcp9600.c +22 -0
index fa382a988a991..54bc657460e5d 100644
@@ -31,6 +31,7 @@
 #define MCP9600_STATUS_ALERT(x)		BIT(x)
 #define MCP9600_SENSOR_CFG		0x05
 #define MCP9600_SENSOR_TYPE_MASK	GENMASK(6, 4)
+#define MCP9600_FILTER_MASK		GENMASK(2, 0)
 #define MCP9600_ALERT_CFG1		0x08
 #define MCP9600_ALERT_CFG(x)		(MCP9600_ALERT_CFG1 + (x - 1))
 #define MCP9600_ALERT_CFG_ENABLE	BIT(0)
@@ -94,6 +95,27 @@ static const int mcp9600_tc_types[] = {
 	[THERMOCOUPLE_TYPE_R] = 'R',
 };
 
+enum mcp9600_filter {
+	MCP9600_FILTER_TYPE_NONE,
+	MCP9600_FILTER_TYPE_EMA,
+};
+
+static const char * const mcp9600_filter_type[] = {
+	[MCP9600_FILTER_TYPE_NONE] = "none",
+	[MCP9600_FILTER_TYPE_EMA] = "ema",
+};
+
+static const int mcp_iir_coefficients_avail[7][2] = {
+	/* Level 0 is no filter */
+	{ 0, 524549 },
+	{ 0, 243901 },
+	{ 0, 119994 },
+	{ 0,  59761 },
+	{ 0,  29851 },
+	{ 0,  14922 },
+	{ 0,   7461 },
+};
+
 static const struct iio_event_spec mcp9600_events[] = {
 	{
 		.type = IIO_EV_TYPE_THRESH,

drivers/iio/temperature/mcp9600.c static const struct iio_event_spec mcp9600_events[] = { · line 143

Quoted 4 lines
drivers/iio/temperature/mcp9600.c +1 -0
@@ -118,7 +140,11 @@ static const struct iio_event_spec mcp9600_events[] = {
 			.address = MCP9600_HOT_JUNCTION,		       \
 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	       \
 					      BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE) | \
+					      BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |  \

Probably just one space before \ is the most consistent choice.

Quoted 8 lines
drivers/iio/temperature/mcp9600.c +3 -0
 					      BIT(IIO_CHAN_INFO_SCALE),	       \
+			.info_mask_separate_available =                        \
+					      BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+			.ext_info = mcp9600_ext_filter,			       \
 			.event_spec = &mcp9600_events[hj_ev_spec_off],	       \
 			.num_event_specs = hj_num_ev,			       \
 		},							       \

drivers/iio/temperature/mcp9600.c static const struct iio_event_spec mcp9600_events[] = { · line 167

Quoted 8 lines
drivers/iio/temperature/mcp9600.c +5 -0
@@ -134,6 +160,26 @@ static const struct iio_event_spec mcp9600_events[] = {
 		},							       \
 	}
 
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan);
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode);

shuffle the code around so you don't need a forward definition.. There is no particular reason I can see to have get and set later.

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +7 -0
+
+static const struct iio_enum mcp9600_filter_enum = {
+	.items = mcp9600_filter_type,
+	.num_items = ARRAY_SIZE(mcp9600_filter_type),
+	.get = mcp9600_get_filter,
+	.set = mcp9600_set_filter,
+};
 
 static int mcp9600_read(struct mcp9600_data *data,

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 242

Quoted 4 lines
drivers/iio/temperature/mcp9600.c +1 -0
@@ -191,13 +239,45 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
 		if (ret)
 			return ret;
 		return IIO_VAL_INT;
+

Unrelated changes. White space changes should not be mixed in a patch doing anything significant. If you want to do this, extra patch needed.

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 5 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+

If you want the extra space put it in previous patch.

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 12 lines
drivers/iio/temperature/mcp9600.c +12 -0
+			return -EINVAL;
+
+		*val = mcp_iir_coefficients_avail[data->filter_level - 1][0];
+		*val2 = mcp_iir_coefficients_avail[data->filter_level - 1][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_read_avail(struct iio_dev *indio_dev,

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 275

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+			      struct iio_chan_spec const *chan,
+			      const int **vals, int *type, int *length,
+			      long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)
+			return -EINVAL;

Don't block this. It makes for a confusing interface.

Quoted 17 lines
drivers/iio/temperature/mcp9600.c +6 -0
+
+		*vals = (int *)mcp_iir_coefficients_avail;
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = 2 * ARRAY_SIZE(mcp_iir_coefficients_avail);
+		return IIO_AVAIL_LIST;
 	default:
 		return -EINVAL;
 	}
@@ -211,6 +291,7 @@ static int mcp9600_config(struct mcp9600_data *data)
 
 	cfg  = FIELD_PREP(MCP9600_SENSOR_TYPE_MASK,
 			  mcp9600_type_map[data->thermocouple_type]);
+	FIELD_MODIFY(MCP9600_FILTER_MASK, &cfg, data->filter_level);
 
 	ret = i2c_smbus_write_byte_data(client, MCP9600_SENSOR_CFG, cfg);
 	if (ret < 0) {

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 311

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +7 -0
@@ -221,6 +302,79 @@ static int mcp9600_config(struct mcp9600_data *data)
 	return 0;
 }
 
+static int mcp9600_write_raw_get_fmt(struct iio_dev *indio_dev,
+				     struct iio_chan_spec const *chan,
+				     long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return IIO_VAL_INT_PLUS_MICRO;

That's the default so you shouldn't need a write_raw_get_fmt for this.

Quoted 27 lines
drivers/iio/temperature/mcp9600.c +27 -0
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+	int i;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		for (i = 0; i < ARRAY_SIZE(mcp_iir_coefficients_avail); i++) {
+			if (mcp_iir_coefficients_avail[i][0] == val &&
+			    mcp_iir_coefficients_avail[i][1] == val2)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(mcp_iir_coefficients_avail))
+			return -EINVAL;
+
+		data->filter_level = i + 1;
+		return mcp9600_config(data);
+
+	default:

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 348

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	if (data->filter_level == 0)

I'd use a separate enable flag for this.

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+		return MCP9600_FILTER_TYPE_NONE;
+
+	return MCP9600_FILTER_TYPE_EMA;
+}
+
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 368

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+
+	switch (mode) {
+	case MCP9600_FILTER_TYPE_NONE:
+		data->filter_level = 0;
+		return mcp9600_config(data);
+
+	case MCP9600_FILTER_TYPE_EMA:
+		if (data->filter_level == 0) {
+			/* Minimum filter by default */
+			data->filter_level = 1;

As above, I'd just let the user write it whenever they like (default to 1 on boot) and then they have to see if it is set to none to see whether it has an effect.

Quoted 22 lines
drivers/iio/temperature/mcp9600.c +12 -0
+			return mcp9600_config(data);
+		}
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
 {
 	if (channel2 == IIO_MOD_TEMP_AMBIENT) {
@@ -358,6 +512,9 @@ static int mcp9600_write_thresh(struct iio_dev *indio_dev,
 
 static const struct iio_info mcp9600_info = {
 	.read_raw = mcp9600_read_raw,
+	.read_avail = mcp9600_read_avail,
+	.write_raw = mcp9600_write_raw,
+	.write_raw_get_fmt = mcp9600_write_raw_get_fmt,
 	.read_event_config = mcp9600_read_event_config,
 	.write_event_config = mcp9600_write_event_config,
 	.read_event_value = mcp9600_read_thresh,
#14 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 5 lines · Jonathan Cameron
Quoted 2 lines · On Sun, 17 Aug 2025 23:59:53 -0400 Ben Collins <[email protected]> wrote:

From: Ben Collins <[email protected]>

Quoted 8 lines
Quoted 4 lines

MCP9600 supports an IIR filter with 7 levels. Add IIR attribute to allow get/set of this value.

Use a filter_type[none, ema] for enabling the IIR filter.

Hi Ben,

A few comments inline. You also need to send an additional patch to update the filter_type docs in Documentation/ABI/testing/sysfs-bus-iio

Hi Jonathan,

I just sent a v6 because I was getting too many comments on the dt-bindings patch.

I'll send a v7 with these changes and anything else that comes up.

More comments below.

Quoted 7 lines
Quoted 7 lines

---

(quoted diff) +0 -0
@@ -134,6 +160,26 @@ static const struct iio_event_spec mcp9600_events[] = {
 		},							       \
 	}
 
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static const struct iio_event_spec mcp9600_events[] = { · line 167

Quoted 5 lines
drivers/iio/temperature/mcp9600.c +5 -0
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan);
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode);

shuffle the code around so you don't need a forward definition.. There is no particular reason I can see to have get and set later.

The set function, for one, calls mcp9600_config, which comes after the use of the get/set in the ext_info. I'll see if I can shuffle that around in the prior patch to avoid this.

Quoted 8 lines
Quoted 7 lines
drivers/iio/temperature/mcp9600.c +7 -0
+
+static const struct iio_enum mcp9600_filter_enum = {
+	.items = mcp9600_filter_type,
+	.num_items = ARRAY_SIZE(mcp9600_filter_type),
+	.get = mcp9600_get_filter,
+	.set = mcp9600_set_filter,
+};
Quoted 9 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 242

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 static int mcp9600_read(struct mcp9600_data *data,
@@ -191,13 +239,45 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
 		if (ret)
 			return ret;
 		return IIO_VAL_INT;
+

Unrelated changes. White space changes should not be mixed in a patch doing anything significant. If you want to do this, extra patch needed.

Noted.

Quoted 7 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 5 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

Quoted 43 lines
Quoted 12 lines
drivers/iio/temperature/mcp9600.c +12 -0
+			return -EINVAL;
+
+		*val = mcp_iir_coefficients_avail[data->filter_level - 1][0];
+		*val2 = mcp_iir_coefficients_avail[data->filter_level - 1][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_read_avail(struct iio_dev *indio_dev,

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 275

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+			      struct iio_chan_spec const *chan,
+			      const int **vals, int *type, int *length,
+			      long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)
+			return -EINVAL;

Don't block this. It makes for a confusing interface.

Quoted 20 lines
drivers/iio/temperature/mcp9600.c +6 -0
+
+		*vals = (int *)mcp_iir_coefficients_avail;
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = 2 * ARRAY_SIZE(mcp_iir_coefficients_avail);
+		return IIO_AVAIL_LIST;
 	default:
 		return -EINVAL;
 	}
@@ -211,6 +291,7 @@ static int mcp9600_config(struct mcp9600_data *data)
 
 	cfg  = FIELD_PREP(MCP9600_SENSOR_TYPE_MASK,
 			  mcp9600_type_map[data->thermocouple_type]);
+	FIELD_MODIFY(MCP9600_FILTER_MASK, &cfg, data->filter_level);
 
 	ret = i2c_smbus_write_byte_data(client, MCP9600_SENSOR_CFG, cfg);
 	if (ret < 0) {
@@ -221,6 +302,79 @@ static int mcp9600_config(struct mcp9600_data *data)
 	return 0;
 }
 
Quoted 9 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 311

Quoted 7 lines
drivers/iio/temperature/mcp9600.c +7 -0
+static int mcp9600_write_raw_get_fmt(struct iio_dev *indio_dev,
+				     struct iio_chan_spec const *chan,
+				     long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return IIO_VAL_INT_PLUS_MICRO;

That's the default so you shouldn't need a write_raw_get_fmt for this.

Ok.

Quoted 86 lines
Quoted 27 lines
drivers/iio/temperature/mcp9600.c +27 -0
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+	int i;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		for (i = 0; i < ARRAY_SIZE(mcp_iir_coefficients_avail); i++) {
+			if (mcp_iir_coefficients_avail[i][0] == val &&
+			    mcp_iir_coefficients_avail[i][1] == val2)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(mcp_iir_coefficients_avail))
+			return -EINVAL;
+
+		data->filter_level = i + 1;
+		return mcp9600_config(data);
+
+	default:

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 348

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+		return -EINVAL;
+	}
+}
+
+static int mcp9600_get_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);
+
+	if (data->filter_level == 0)

I'd use a separate enable flag for this.

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+		return MCP9600_FILTER_TYPE_NONE;
+
+	return MCP9600_FILTER_TYPE_EMA;
+}
+
+static int mcp9600_set_filter(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      unsigned int mode)
+{
+	struct mcp9600_data *data = iio_priv(indio_dev);

drivers/iio/temperature/mcp9600.c static int mcp9600_config(struct mcp9600_data *data) · line 368

Quoted 10 lines
drivers/iio/temperature/mcp9600.c +10 -0
+
+	switch (mode) {
+	case MCP9600_FILTER_TYPE_NONE:
+		data->filter_level = 0;
+		return mcp9600_config(data);
+
+	case MCP9600_FILTER_TYPE_EMA:
+		if (data->filter_level == 0) {
+			/* Minimum filter by default */
+			data->filter_level = 1;

As above, I'd just let the user write it whenever they like (default to 1 on boot) and then they have to see if it is set to none to see whether it has an effect.

Quoted 22 lines
drivers/iio/temperature/mcp9600.c +12 -0
+			return mcp9600_config(data);
+		}
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
 static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
 {
 	if (channel2 == IIO_MOD_TEMP_AMBIENT) {
@@ -358,6 +512,9 @@ static int mcp9600_write_thresh(struct iio_dev *indio_dev,
 
 static const struct iio_info mcp9600_info = {
 	.read_raw = mcp9600_read_raw,
+	.read_avail = mcp9600_read_avail,
+	.write_raw = mcp9600_write_raw,
+	.write_raw_get_fmt = mcp9600_write_raw_get_fmt,
 	.read_event_config = mcp9600_read_event_config,
 	.write_event_config = mcp9600_write_event_config,
 	.read_event_value = mcp9600_read_thresh,
Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
reviewer
#15 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 12 lines · Ben Collins
Quoted 11 lines · Jonathan Cameron
Quoted 6 lines · On Sun, 17 Aug 2025 23:59:53 -0400 Ben Collins <[email protected]> wrote:

From: Ben Collins <[email protected]>

MCP9600 supports an IIR filter with 7 levels. Add IIR attribute to allow get/set of this value.

Use a filter_type[none, ema] for enabling the IIR filter.

Hi Ben,

Quoted 7 lines
Quoted 2 lines

A few comments inline. You also need to send an additional patch to update the filter_type docs in Documentation/ABI/testing/sysfs-bus-iio

Hi Jonathan,

I just sent a v6 because I was getting too many comments on the dt-bindings patch.

Actually, folks will be happier if you slow down a bit. General advice is only submit one revision per week since some people only have time to review once per week.

If you are really in a hurry, there should still be no more than one revision per day. Otherwise, it is really hard for reviewers to keep up.

As it is, the subject of what I presume is v6 still says v5 in the cover letter and doesn't have a version in the rest of the patches. And there are still some of the same problems with the devicetree patch that didn't get addressed. If you slow down a bit and take a little more care before firing off the next one, it will likely be better received.

Quoted 3 lines

I'll send a v7 with these changes and anything else that comes up.

#16 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 16 lines · David Lechner
Quoted 15 lines · Ben Collins
Quoted 13 lines · Jonathan Cameron
Quoted 6 lines · On Sun, 17 Aug 2025 23:59:53 -0400 Ben Collins <[email protected]> wrote:

From: Ben Collins <[email protected]>

MCP9600 supports an IIR filter with 7 levels. Add IIR attribute to allow get/set of this value.

Use a filter_type[none, ema] for enabling the IIR filter.

Hi Ben,

A few comments inline. You also need to send an additional patch to update the filter_type docs in Documentation/ABI/testing/sysfs-bus-iio

Quoted 8 lines
Quoted 4 lines

Hi Jonathan,

I just sent a v6 because I was getting too many comments on the dt-bindings patch.

Actually, folks will be happier if you slow down a bit. General advice is only submit one revision per week since some people only have time to review once per week.

I appreciate the info. Admittedly, when I was more prolific with kernel development, the pipline and protocol was much leaner, so I'm not used to the more recent "norm" quite yet.

Not complaining, just noting. I'll get there.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
maintainer
#17 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

In reply to Ben Collins
Quoted 19 lines
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+  

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)  

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

ABI design is a pain sometimes.

Thanks,

Jonathan

#18 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 35 lines · Jonathan Cameron
Quoted 19 lines
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+  

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)  

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

Quoted 6 lines

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

I'm somewhat wondering if the filter frequency and frequency_available attributes should not even show in sysfs unless the filter_type was something other than "none".

Quoted 2 lines

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

Just to make sure I understand, you'd like to see a filter_enable attribute and filter_type would not contain "none", then frequency and frequency_available would always show something for whatever was in filter_type?

Quoted 1 line

ABI design is a pain sometimes.

The epitome of being able to paint yourself into a corner.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
maintainer
#19 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 39 lines · On Mon, 18 Aug 2025 16:00:20 -0400 Ben Collins <[email protected]> wrote:
Quoted 38 lines · Jonathan Cameron
Quoted 19 lines
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+    

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)    

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

Quoted 8 lines
Quoted 3 lines

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

I'm somewhat wondering if the filter frequency and frequency_available attributes should not even show in sysfs unless the filter_type was something other than "none".

I'm not keen on that and trying to bolt is_visible into the mess of how we generate attributes would be hard and actual add and remove of attributes is horrible for races with userspace.

Quoted 7 lines
Quoted 2 lines

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

Just to make sure I understand, you'd like to see a filter_enable attribute and filter_type would not contain "none", then frequency and frequency_available would always show something for whatever was in filter_type?

Yes. I think that is best way forwards. If we want to retrofit the one user of none to support the new ABI as well it should be easy to do.

Quoted 5 lines
Quoted 2 lines

ABI design is a pain sometimes.

The epitome of being able to paint yourself into a corner.

Yup.

J

maintainer
#20 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 57 lines · On Tue, 19 Aug 2025 19:28:51 +0100 Jonathan Cameron <[email protected]> wrote:
Quoted 39 lines · On Mon, 18 Aug 2025 16:00:20 -0400 Ben Collins <[email protected]> wrote:
Quoted 38 lines · Jonathan Cameron
Quoted 19 lines
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+      

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)      

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

Quoted 8 lines
Quoted 3 lines

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

I'm somewhat wondering if the filter frequency and frequency_available attributes should not even show in sysfs unless the filter_type was something other than "none".

I'm not keen on that and trying to bolt is_visible into the mess of how we generate attributes would be hard and actual add and remove of attributes is horrible for races with userspace.

Quoted 3 lines
Quoted 2 lines

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

Quoted 8 lines
Quoted 4 lines

Just to make sure I understand, you'd like to see a filter_enable attribute and filter_type would not contain "none", then frequency and frequency_available would always show something for whatever was in filter_type?

Yes. I think that is best way forwards. If we want to retrofit the one user of none to support the new ABI as well it should be easy to do.

Ignore that. David convinced me otherwise. Lets take this a bit slow and discuss it fully in other branch of this thread.

J

Quoted 9 lines
Quoted 5 lines
Quoted 2 lines

ABI design is a pain sometimes.

The epitome of being able to paint yourself into a corner.

Yup.

J

#21 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

Quoted 65 lines · Jonathan Cameron
Quoted 62 lines · On Tue, 19 Aug 2025 19:28:51 +0100 Jonathan Cameron <[email protected]> wrote:
Quoted 39 lines · On Mon, 18 Aug 2025 16:00:20 -0400 Ben Collins <[email protected]> wrote:
Quoted 38 lines · Jonathan Cameron
Quoted 19 lines
Quoted 8 lines

Review

Quoted 6 lines
(quoted diff) +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+      

If you want the extra space put it in previous patch.

Quoted 10 lines

Review

Quoted 6 lines
(quoted diff) +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)      

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

Quoted 8 lines
Quoted 3 lines

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

I'm somewhat wondering if the filter frequency and frequency_available attributes should not even show in sysfs unless the filter_type was something other than "none".

I'm not keen on that and trying to bolt is_visible into the mess of how we generate attributes would be hard and actual add and remove of attributes is horrible for races with userspace.

Quoted 7 lines
Quoted 2 lines

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

Just to make sure I understand, you'd like to see a filter_enable attribute and filter_type would not contain "none", then frequency and frequency_available would always show something for whatever was in filter_type?

Quoted 6 lines
Quoted 3 lines

Yes. I think that is best way forwards. If we want to retrofit the one user of none to support the new ABI as well it should be easy to do.

Ignore that. David convinced me otherwise. Lets take this a bit slow and discuss it fully in other branch of this thread.

Maybe a working solution would help the conversation to see how it would look.

I think I can rework ad4080 so that it keeps "none" filter_type, but also can make use of filter_enable. That way it can continue to work for users while still providing a better interface for anything else moving forward.

I can send this as a separate RFC series from my current mcp9600 changes to break this out.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF
#22 lore raw

Re: [PATCH v5 5/5] iio: mcp9600: Add support for IIR filter

In reply to Jonathan Cameron
Quoted 57 lines · Jonathan Cameron
Quoted 39 lines · On Mon, 18 Aug 2025 16:00:20 -0400 Ben Collins <[email protected]> wrote:
Quoted 38 lines · Jonathan Cameron
Quoted 19 lines
Quoted 8 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 247

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +1 -0
 	case IIO_CHAN_INFO_SCALE:
 		*val = 62;
 		*val2 = 500000;
 		return IIO_VAL_INT_PLUS_MICRO;
+    

If you want the extra space put it in previous patch.

Quoted 10 lines

drivers/iio/temperature/mcp9600.c static int mcp9600_read_raw(struct iio_dev *indio_dev, · line 253

Quoted 6 lines
drivers/iio/temperature/mcp9600.c +3 -0
 	case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
 		*val = mcp9600_tc_types[data->thermocouple_type];
 		return IIO_VAL_CHAR;
+
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (data->filter_level == 0)    

Return the current requested value. An error is just going to confuse someone who tried to write this before enabling the filter and then checked to see if the write was successful.

Quoted 4 lines

I could not get a concensus on this. On the one hand, if a user sets a value here, would they not assume that the filter was enabled? What about cases where a filter_type can be more than one valid type with different available coefficients for each? What should it show then?

So I was thinking of this like other things with 'enables' such as events. For those you always set the value first. They don't really have a type field though (well they do but the ABI allows multiple at once unlike filters so we end up with a quite different looking ABI).

Agreed it gets challenging with multiple filter types. If it weren't for advertising the range I'd suggest just stashing whatever was written and then mapping it to nearest possible when the filter type is set. That's what the ad7124 does for changing between filters anyway though oddly it doesn't seem to have a control for filter type.

This is a good argument against the whole 'none' value for filter type
- that's not much used so we could deprecate it for new drivers.

Quoted 8 lines
Quoted 3 lines

I'm not particularly keen on filter_enable but seems we are coming back around to that option to avoid this corner case. Alternative being what you have here which isn't great for ease of use.

I'm somewhat wondering if the filter frequency and frequency_available attributes should not even show in sysfs unless the filter_type was something other than "none".

I'm not keen on that and trying to bolt is_visible into the mess of how we generate attributes would be hard and actual add and remove of attributes is horrible for races with userspace.

Quoted 3 lines
Quoted 2 lines

So for next version let's go for that. Make sure to include Documentation in a separate patch though so it's easy to see an poke holes in.

Quoted 7 lines
Quoted 4 lines

Just to make sure I understand, you'd like to see a filter_enable attribute and filter_type would not contain "none", then frequency and frequency_available would always show something for whatever was in filter_type?

Yes. I think that is best way forwards. If we want to retrofit the one user of none to support the new ABI as well it should be easy to do.

I'm good with that. I'll get a patch to update the ABI, add filter_enable usage in mcp9600 IIR patch, and provide another patch for ad4080 to convert to this.

Signature · 5 lines
 Ben Collins
 https://libjwt.io
 https://github.com/benmcollins
 --
 3EC9 7598 1672 961A 1139  173A 5D5A 57C7 242B 22CF