Linux-IIO Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/3] iio: max31856: provide more configuration options
@ 2019-09-23 12:17 Andrea Merello
  2019-09-23 12:17 ` [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency Andrea Merello
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Andrea Merello @ 2019-09-23 12:17 UTC (permalink / raw)
  To: jic23, patrick.havelange, paresh.chaudhary, pmeerw, lars,
	knaack.h, matthew.weber
  Cc: colin.king, linux-iio, Andrea Merello

This patch series makes it possible to configure some HW features at
runtime by introducing new IIO device attributes.

Two hardware features (power mains noise rejection and HW averaging)
were not previously configurable, and one (thermocouple type selection)
was only possible via DT, but in my experience this is quite limiting in
several scenario (see 3/3 commit message for complete explanation).

These patches have been tested backporting the driver on a 4.9 upstream
kernel (Xilinx mpsoc-based board), and then rebased on the IIO testing git
tree.

Andrea Merello (3):
  iio: max31856: add option for setting mains filter rejection frequency
  iio: max31856: add support for configuring the HW averaging
  iio: max31856: add support for runtime-configuring the thermocouple
    type

 drivers/iio/temperature/max31856.c | 136 +++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

--
2.17.1

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

* [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency
  2019-09-23 12:17 [PATCH 0/3] iio: max31856: provide more configuration options Andrea Merello
@ 2019-09-23 12:17 ` Andrea Merello
  2019-10-06  7:54   ` Jonathan Cameron
  2019-09-23 12:17 ` [PATCH 2/3] iio: max31856: add support for configuring the HW averaging Andrea Merello
  2019-09-23 12:17 ` [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type Andrea Merello
  2 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-09-23 12:17 UTC (permalink / raw)
  To: jic23, patrick.havelange, paresh.chaudhary, pmeerw, lars,
	knaack.h, matthew.weber
  Cc: colin.king, linux-iio, Andrea Merello

This sensor has an embedded notch filter for reducing interferences caused
by the power mains. This filter can be tuned to reject either 50Hz or 60Hz
(and harmonics).

Currently the said setting is left alone (the sensor defaults to 60Hz).
This patch introduces a IIO attribute that allows the user to set the said
filter to the desired frequency.

NOTE: this has been intentionally not tied to any DT property to allow
the configuration of this setting from userspace, e.g. with a GUI or by
reading a configuration file, or maybe reading a GPIO tied to a physical
switch or accessing some device that can autodetect the line frequency.

Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
---
 drivers/iio/temperature/max31856.c | 49 ++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
index 73ed550e3fc9..d12613f7ba3c 100644
--- a/drivers/iio/temperature/max31856.c
+++ b/drivers/iio/temperature/max31856.c
@@ -23,6 +23,7 @@
 #define MAX31856_CR0_1SHOT         BIT(6)
 #define MAX31856_CR0_OCFAULT       BIT(4)
 #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
+#define MAX31856_CR0_FILTER_50HZ   BIT(0)
 #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
 #define MAX31856_FAULT_OVUV        BIT(1)
 #define MAX31856_FAULT_OPEN        BIT(0)
@@ -63,6 +64,7 @@ static const struct iio_chan_spec max31856_channels[] = {
 struct max31856_data {
 	struct spi_device *spi;
 	u32 thermocouple_type;
+	bool filter_50hz;
 };
 
 static int max31856_read(struct max31856_data *data, u8 reg,
@@ -123,6 +125,11 @@ static int max31856_init(struct max31856_data *data)
 	reg_cr0_val &= ~MAX31856_CR0_1SHOT;
 	reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
 
+	if (data->filter_50hz)
+		reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
+	else
+		reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
+
 	return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
 }
 
@@ -249,12 +256,53 @@ static ssize_t show_fault_oc(struct device *dev,
 	return show_fault(dev, MAX31856_FAULT_OPEN, buf);
 }
 
+static ssize_t show_filter(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
+}
+
+static ssize_t set_filter(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+	unsigned int freq;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &freq);
+	if (ret)
+		return ret;
+
+	switch (freq) {
+	case 50:
+		data->filter_50hz = true;
+		break;
+	case 60:
+		data->filter_50hz = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	max31856_init(data);
+	return len;
+}
+
 static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
 static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
+static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
 
 static struct attribute *max31856_attributes[] = {
 	&iio_dev_attr_fault_ovuv.dev_attr.attr,
 	&iio_dev_attr_fault_oc.dev_attr.attr,
+	&iio_dev_attr_filter.dev_attr.attr,
 	NULL,
 };
 
@@ -280,6 +328,7 @@ static int max31856_probe(struct spi_device *spi)
 
 	data = iio_priv(indio_dev);
 	data->spi = spi;
+	data->filter_50hz = false;
 
 	spi_set_drvdata(spi, indio_dev);
 
-- 
2.17.1


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

* [PATCH 2/3] iio: max31856: add support for configuring the HW averaging
  2019-09-23 12:17 [PATCH 0/3] iio: max31856: provide more configuration options Andrea Merello
  2019-09-23 12:17 ` [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency Andrea Merello
@ 2019-09-23 12:17 ` Andrea Merello
  2019-10-06  7:55   ` Jonathan Cameron
  2019-09-23 12:17 ` [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type Andrea Merello
  2 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-09-23 12:17 UTC (permalink / raw)
  To: jic23, patrick.havelange, paresh.chaudhary, pmeerw, lars,
	knaack.h, matthew.weber
  Cc: colin.king, linux-iio, Andrea Merello

This sensor can perform samples averaging in hardware, but currently the
driver leaves this setting alone (default is no averaging).

This patch introduces a new IIO attribute that allows the user to set the
averaging as desired (the HW supports averaging of 2, 5, 8 or 16 samples)

Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
---
 drivers/iio/temperature/max31856.c | 43 ++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
index d12613f7ba3c..8b2e0102fa5c 100644
--- a/drivers/iio/temperature/max31856.c
+++ b/drivers/iio/temperature/max31856.c
@@ -24,6 +24,8 @@
 #define MAX31856_CR0_OCFAULT       BIT(4)
 #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
 #define MAX31856_CR0_FILTER_50HZ   BIT(0)
+#define MAX31856_AVERAGING_MASK    GENMASK(6, 4)
+#define MAX31856_AVERAGING_SHIFT   4
 #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
 #define MAX31856_FAULT_OVUV        BIT(1)
 #define MAX31856_FAULT_OPEN        BIT(0)
@@ -65,6 +67,7 @@ struct max31856_data {
 	struct spi_device *spi;
 	u32 thermocouple_type;
 	bool filter_50hz;
+	int averaging;
 };
 
 static int max31856_read(struct max31856_data *data, u8 reg,
@@ -109,6 +112,10 @@ static int max31856_init(struct max31856_data *data)
 
 	reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
 	reg_cr1_val |= data->thermocouple_type;
+
+	reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
+	reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
+
 	ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
 	if (ret)
 		return ret;
@@ -295,14 +302,50 @@ static ssize_t set_filter(struct device *dev,
 	return len;
 }
 
+static ssize_t show_averaging(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", 1 << data->averaging);
+}
+
+static ssize_t set_averaging(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf,
+			     size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+	unsigned int nsamples;
+	int shift;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &nsamples);
+	if (ret)
+		return ret;
+
+	shift = fls(nsamples) - 1;
+	if (nsamples > 16 || BIT(shift) != nsamples)
+		return -EINVAL;
+
+	data->averaging = shift;
+	max31856_init(data);
+	return len;
+}
+
 static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
 static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
 static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
+static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
 
 static struct attribute *max31856_attributes[] = {
 	&iio_dev_attr_fault_ovuv.dev_attr.attr,
 	&iio_dev_attr_fault_oc.dev_attr.attr,
 	&iio_dev_attr_filter.dev_attr.attr,
+	&iio_dev_attr_averaging.dev_attr.attr,
 	NULL,
 };
 
-- 
2.17.1


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

* [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type
  2019-09-23 12:17 [PATCH 0/3] iio: max31856: provide more configuration options Andrea Merello
  2019-09-23 12:17 ` [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency Andrea Merello
  2019-09-23 12:17 ` [PATCH 2/3] iio: max31856: add support for configuring the HW averaging Andrea Merello
@ 2019-09-23 12:17 ` Andrea Merello
  2019-10-06  7:58   ` Jonathan Cameron
  2 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-09-23 12:17 UTC (permalink / raw)
  To: jic23, patrick.havelange, paresh.chaudhary, pmeerw, lars,
	knaack.h, matthew.weber
  Cc: colin.king, linux-iio, Andrea Merello

The sensor support various thermocouple types (e.g. J, K, N, ...). The
driver allows to configure this parameter using a DT property.

This is useful when i.e. the thermocouple is physically tied to the sensor
and it is usually not removed, or when it is at least known in advace
which sensor will be connected to the circuit.

However, if the user can randomly connect any kind of thermocouples (i.e.
the device exposes a connector, and the user is free to connect its own
sensors), it would be more appropriate to provide a mechanism to
dynamically switch from one thermocouple type to another. This can be i.e.
handled in userspace by a GUI, a configuration file or a program that
detects the thermocouple type by reading a GPIO, or a eeprom on the probe,
or whatever.

This patch adds a IIO attribute that can be used to override, at run-time,
the DT-provided setting (which serves as default).

Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
---
 drivers/iio/temperature/max31856.c | 44 ++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
index 8b2e0102fa5c..588e791c79a3 100644
--- a/drivers/iio/temperature/max31856.c
+++ b/drivers/iio/temperature/max31856.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2018-2019 Rockwell Collins
  */
 
+#include <linux/ctype.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -70,6 +71,10 @@ struct max31856_data {
 	int averaging;
 };
 
+const char max31856_tc_types[] = {
+	'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
+};
+
 static int max31856_read(struct max31856_data *data, u8 reg,
 			 u8 val[], unsigned int read_size)
 {
@@ -336,16 +341,55 @@ static ssize_t set_averaging(struct device *dev,
 	return len;
 }
 
+static ssize_t show_tc_type(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+
+	return sprintf(buf, "%c\n", max31856_tc_types[data->thermocouple_type]);
+}
+
+static ssize_t set_tc_type(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf,
+			   size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct max31856_data *data = iio_priv(indio_dev);
+	char tmp;
+	int tc_type = -1;
+	int i;
+
+	if (sscanf(buf, "%c\n", &tmp) != 1)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
+		if (max31856_tc_types[i] == toupper(tmp)) {
+			tc_type = i;
+			break;
+		}
+	}
+	if (tc_type < 0)
+		return -EINVAL;
+	data->thermocouple_type = tc_type;
+	max31856_init(data);
+	return len;
+}
+
 static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
 static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
 static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
 static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
+static IIO_DEVICE_ATTR(thermocouple_type, 0644, show_tc_type, set_tc_type, 0);
 
 static struct attribute *max31856_attributes[] = {
 	&iio_dev_attr_fault_ovuv.dev_attr.attr,
 	&iio_dev_attr_fault_oc.dev_attr.attr,
 	&iio_dev_attr_filter.dev_attr.attr,
 	&iio_dev_attr_averaging.dev_attr.attr,
+	&iio_dev_attr_thermocouple_type.dev_attr.attr,
 	NULL,
 };
 
-- 
2.17.1


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

* Re: [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency
  2019-09-23 12:17 ` [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency Andrea Merello
@ 2019-10-06  7:54   ` Jonathan Cameron
  2019-10-16 13:14     ` Andrea Merello
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-06  7:54 UTC (permalink / raw)
  To: Andrea Merello
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	matthew.weber, colin.king, linux-iio

On Mon, 23 Sep 2019 14:17:12 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> This sensor has an embedded notch filter for reducing interferences caused
> by the power mains. This filter can be tuned to reject either 50Hz or 60Hz
> (and harmonics).
> 
> Currently the said setting is left alone (the sensor defaults to 60Hz).
> This patch introduces a IIO attribute that allows the user to set the said
> filter to the desired frequency.
> 
> NOTE: this has been intentionally not tied to any DT property to allow
> the configuration of this setting from userspace, e.g. with a GUI or by
> reading a configuration file, or maybe reading a GPIO tied to a physical
> switch or accessing some device that can autodetect the line frequency.
> 
> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
This one is not something that can be expect to be known from the setup
of the device as it will depend on local mains frequency.

So fine, to have it as a userspace control, but the name is too generic.
We already have a number of filter attributes and we should try to
work out how to bring it inline with them.

in_X_filter_low_pass_3db_frequency
in_X_filter_high_pass_3db_frequency

So would,
in_X_filter_notch_center_frequency work?
( I suppose we should use the American spelling ;)

This kind of ignores the harmonics aspect but at least documents the
main frequency being blocked.

There is a slight complexity that we have devices that have dual
notchfilters (50 and 60Hz) and ones where you can turn it off entirely.

I suppose no value would count as off and we could perhaps use a list
for both on at the same time (though that's a bit horrible).

> ---
>  drivers/iio/temperature/max31856.c | 49 ++++++++++++++++++++++++++++++
>  1 file changed, 49 insertions(+)
> 
> diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> index 73ed550e3fc9..d12613f7ba3c 100644
> --- a/drivers/iio/temperature/max31856.c
> +++ b/drivers/iio/temperature/max31856.c
> @@ -23,6 +23,7 @@
>  #define MAX31856_CR0_1SHOT         BIT(6)
>  #define MAX31856_CR0_OCFAULT       BIT(4)
>  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
> +#define MAX31856_CR0_FILTER_50HZ   BIT(0)
>  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
>  #define MAX31856_FAULT_OVUV        BIT(1)
>  #define MAX31856_FAULT_OPEN        BIT(0)
> @@ -63,6 +64,7 @@ static const struct iio_chan_spec max31856_channels[] = {
>  struct max31856_data {
>  	struct spi_device *spi;
>  	u32 thermocouple_type;
> +	bool filter_50hz;
>  };
>  
>  static int max31856_read(struct max31856_data *data, u8 reg,
> @@ -123,6 +125,11 @@ static int max31856_init(struct max31856_data *data)
>  	reg_cr0_val &= ~MAX31856_CR0_1SHOT;
>  	reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
>  
> +	if (data->filter_50hz)
> +		reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
> +	else
> +		reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
> +
>  	return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
>  }
>  
> @@ -249,12 +256,53 @@ static ssize_t show_fault_oc(struct device *dev,
>  	return show_fault(dev, MAX31856_FAULT_OPEN, buf);
>  }
>  
> +static ssize_t show_filter(struct device *dev,
> +			   struct device_attribute *attr,
> +			   char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
> +}
> +
> +static ssize_t set_filter(struct device *dev,
> +			  struct device_attribute *attr,
> +			  const char *buf,
> +			  size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +	unsigned int freq;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &freq);
> +	if (ret)
> +		return ret;
> +
> +	switch (freq) {
> +	case 50:
> +		data->filter_50hz = true;
> +		break;
> +	case 60:
> +		data->filter_50hz = false;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	max31856_init(data);
> +	return len;
> +}
> +
>  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
>  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> +static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
>  
>  static struct attribute *max31856_attributes[] = {
>  	&iio_dev_attr_fault_ovuv.dev_attr.attr,
>  	&iio_dev_attr_fault_oc.dev_attr.attr,
> +	&iio_dev_attr_filter.dev_attr.attr,
>  	NULL,
>  };
>  
> @@ -280,6 +328,7 @@ static int max31856_probe(struct spi_device *spi)
>  
>  	data = iio_priv(indio_dev);
>  	data->spi = spi;
> +	data->filter_50hz = false;
>  
>  	spi_set_drvdata(spi, indio_dev);
>  


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

* Re: [PATCH 2/3] iio: max31856: add support for configuring the HW averaging
  2019-09-23 12:17 ` [PATCH 2/3] iio: max31856: add support for configuring the HW averaging Andrea Merello
@ 2019-10-06  7:55   ` Jonathan Cameron
  2019-10-16 13:33     ` Andrea Merello
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-06  7:55 UTC (permalink / raw)
  To: Andrea Merello
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	matthew.weber, colin.king, linux-iio

On Mon, 23 Sep 2019 14:17:13 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> This sensor can perform samples averaging in hardware, but currently the
> driver leaves this setting alone (default is no averaging).
> 
> This patch introduces a new IIO attribute that allows the user to set the
> averaging as desired (the HW supports averaging of 2, 5, 8 or 16 samples)
> 
> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>

Sounds like oversampling combined with a lower sampling frequency, so
there is standard ABI for that.

Jonathan

> ---
>  drivers/iio/temperature/max31856.c | 43 ++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
> 
> diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> index d12613f7ba3c..8b2e0102fa5c 100644
> --- a/drivers/iio/temperature/max31856.c
> +++ b/drivers/iio/temperature/max31856.c
> @@ -24,6 +24,8 @@
>  #define MAX31856_CR0_OCFAULT       BIT(4)
>  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
>  #define MAX31856_CR0_FILTER_50HZ   BIT(0)
> +#define MAX31856_AVERAGING_MASK    GENMASK(6, 4)
> +#define MAX31856_AVERAGING_SHIFT   4
>  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
>  #define MAX31856_FAULT_OVUV        BIT(1)
>  #define MAX31856_FAULT_OPEN        BIT(0)
> @@ -65,6 +67,7 @@ struct max31856_data {
>  	struct spi_device *spi;
>  	u32 thermocouple_type;
>  	bool filter_50hz;
> +	int averaging;
>  };
>  
>  static int max31856_read(struct max31856_data *data, u8 reg,
> @@ -109,6 +112,10 @@ static int max31856_init(struct max31856_data *data)
>  
>  	reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
>  	reg_cr1_val |= data->thermocouple_type;
> +
> +	reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
> +	reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
> +
>  	ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
>  	if (ret)
>  		return ret;
> @@ -295,14 +302,50 @@ static ssize_t set_filter(struct device *dev,
>  	return len;
>  }
>  
> +static ssize_t show_averaging(struct device *dev,
> +			      struct device_attribute *attr,
> +			      char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", 1 << data->averaging);
> +}
> +
> +static ssize_t set_averaging(struct device *dev,
> +			     struct device_attribute *attr,
> +			     const char *buf,
> +			     size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +	unsigned int nsamples;
> +	int shift;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &nsamples);
> +	if (ret)
> +		return ret;
> +
> +	shift = fls(nsamples) - 1;
> +	if (nsamples > 16 || BIT(shift) != nsamples)
> +		return -EINVAL;
> +
> +	data->averaging = shift;
> +	max31856_init(data);
> +	return len;
> +}
> +
>  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
>  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
>  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> +static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
>  
>  static struct attribute *max31856_attributes[] = {
>  	&iio_dev_attr_fault_ovuv.dev_attr.attr,
>  	&iio_dev_attr_fault_oc.dev_attr.attr,
>  	&iio_dev_attr_filter.dev_attr.attr,
> +	&iio_dev_attr_averaging.dev_attr.attr,
>  	NULL,
>  };
>  


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

* Re: [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type
  2019-09-23 12:17 ` [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type Andrea Merello
@ 2019-10-06  7:58   ` Jonathan Cameron
  2019-10-16 13:43     ` Andrea Merello
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-06  7:58 UTC (permalink / raw)
  To: Andrea Merello
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	matthew.weber, colin.king, linux-iio

On Mon, 23 Sep 2019 14:17:14 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> The sensor support various thermocouple types (e.g. J, K, N, ...). The
> driver allows to configure this parameter using a DT property.
> 
> This is useful when i.e. the thermocouple is physically tied to the sensor
> and it is usually not removed, or when it is at least known in advace

advance

> which sensor will be connected to the circuit.
> 
> However, if the user can randomly connect any kind of thermocouples (i.e.
> the device exposes a connector, and the user is free to connect its own
> sensors), it would be more appropriate to provide a mechanism to
> dynamically switch from one thermocouple type to another. This can be i.e.
> handled in userspace by a GUI, a configuration file or a program that
> detects the thermocouple type by reading a GPIO, or a eeprom on the probe,
> or whatever.
> 
> This patch adds a IIO attribute that can be used to override, at run-time,
> the DT-provided setting (which serves as default).
> 
> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
For now this is device specific ABI so you need to have an entry in
Documentation/ABI/testing/sysfs-bus-iio-max31856

Or we could consider this generic enough to put it in a file
covering other thermocouple to digital sensors.

Thanks,

Jonathan

> ---
>  drivers/iio/temperature/max31856.c | 44 ++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> index 8b2e0102fa5c..588e791c79a3 100644
> --- a/drivers/iio/temperature/max31856.c
> +++ b/drivers/iio/temperature/max31856.c
> @@ -6,6 +6,7 @@
>   * Copyright (C) 2018-2019 Rockwell Collins
>   */
>  
> +#include <linux/ctype.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/err.h>
> @@ -70,6 +71,10 @@ struct max31856_data {
>  	int averaging;
>  };
>  
> +const char max31856_tc_types[] = {
> +	'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
> +};
> +
>  static int max31856_read(struct max31856_data *data, u8 reg,
>  			 u8 val[], unsigned int read_size)
>  {
> @@ -336,16 +341,55 @@ static ssize_t set_averaging(struct device *dev,
>  	return len;
>  }
>  
> +static ssize_t show_tc_type(struct device *dev,
> +			    struct device_attribute *attr,
> +			    char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%c\n", max31856_tc_types[data->thermocouple_type]);
> +}
> +
> +static ssize_t set_tc_type(struct device *dev,
> +			   struct device_attribute *attr,
> +			   const char *buf,
> +			   size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct max31856_data *data = iio_priv(indio_dev);
> +	char tmp;
> +	int tc_type = -1;
> +	int i;
> +
> +	if (sscanf(buf, "%c\n", &tmp) != 1)
> +		return -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
> +		if (max31856_tc_types[i] == toupper(tmp)) {
> +			tc_type = i;
> +			break;
> +		}
> +	}
> +	if (tc_type < 0)
> +		return -EINVAL;
> +	data->thermocouple_type = tc_type;
> +	max31856_init(data);
> +	return len;
> +}
> +
>  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
>  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
>  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
>  static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
> +static IIO_DEVICE_ATTR(thermocouple_type, 0644, show_tc_type, set_tc_type, 0);
>  
>  static struct attribute *max31856_attributes[] = {
>  	&iio_dev_attr_fault_ovuv.dev_attr.attr,
>  	&iio_dev_attr_fault_oc.dev_attr.attr,
>  	&iio_dev_attr_filter.dev_attr.attr,
>  	&iio_dev_attr_averaging.dev_attr.attr,
> +	&iio_dev_attr_thermocouple_type.dev_attr.attr,
>  	NULL,
>  };
>  


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

* Re: [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency
  2019-10-06  7:54   ` Jonathan Cameron
@ 2019-10-16 13:14     ` Andrea Merello
  2019-10-17 12:32       ` Jonathan Cameron
  0 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-10-16 13:14 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	Matthew Weber, Colin King, linux-iio

Il giorno dom 6 ott 2019 alle ore 09:54 Jonathan Cameron
<jic23@kernel.org> ha scritto:
>
> On Mon, 23 Sep 2019 14:17:12 +0200
> Andrea Merello <andrea.merello@gmail.com> wrote:
>
> > This sensor has an embedded notch filter for reducing interferences caused
> > by the power mains. This filter can be tuned to reject either 50Hz or 60Hz
> > (and harmonics).
> >
> > Currently the said setting is left alone (the sensor defaults to 60Hz).
> > This patch introduces a IIO attribute that allows the user to set the said
> > filter to the desired frequency.
> >
> > NOTE: this has been intentionally not tied to any DT property to allow
> > the configuration of this setting from userspace, e.g. with a GUI or by
> > reading a configuration file, or maybe reading a GPIO tied to a physical
> > switch or accessing some device that can autodetect the line frequency.
> >
> > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
> This one is not something that can be expect to be known from the setup
> of the device as it will depend on local mains frequency.
>
> So fine, to have it as a userspace control, but the name is too generic.
> We already have a number of filter attributes and we should try to
> work out how to bring it inline with them.

Sure

> in_X_filter_low_pass_3db_frequency
> in_X_filter_high_pass_3db_frequency
>
> So would,
> in_X_filter_notch_center_frequency work?
> ( I suppose we should use the American spelling ;)

Yes, it seems OK in this case. I will produce a V2 with this modification.

> This kind of ignores the harmonics aspect but at least documents the
> main frequency being blocked.

I think this is perfectly fine: the user wants to set the notch filter
center frequency to either 60Hz or 50Hz to match the line frequency,
then she/he expects the filter to simply "work" somehow; IMO the
harmonic thing does not needed to be explicit.

> There is a slight complexity that we have devices that have dual
> notchfilters (50 and 60Hz) and ones where you can turn it off entirely.
>
> I suppose no value would count as off and we could perhaps use a list
> for both on at the same time (though that's a bit horrible).

IMHO it seems reasonable. Maybe for all-off and both-on conditions we
could also use magic strings like i.e. "all" and "off".

> > ---
> >  drivers/iio/temperature/max31856.c | 49 ++++++++++++++++++++++++++++++
> >  1 file changed, 49 insertions(+)
> >
> > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > index 73ed550e3fc9..d12613f7ba3c 100644
> > --- a/drivers/iio/temperature/max31856.c
> > +++ b/drivers/iio/temperature/max31856.c
> > @@ -23,6 +23,7 @@
> >  #define MAX31856_CR0_1SHOT         BIT(6)
> >  #define MAX31856_CR0_OCFAULT       BIT(4)
> >  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
> > +#define MAX31856_CR0_FILTER_50HZ   BIT(0)
> >  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
> >  #define MAX31856_FAULT_OVUV        BIT(1)
> >  #define MAX31856_FAULT_OPEN        BIT(0)
> > @@ -63,6 +64,7 @@ static const struct iio_chan_spec max31856_channels[] = {
> >  struct max31856_data {
> >       struct spi_device *spi;
> >       u32 thermocouple_type;
> > +     bool filter_50hz;
> >  };
> >
> >  static int max31856_read(struct max31856_data *data, u8 reg,
> > @@ -123,6 +125,11 @@ static int max31856_init(struct max31856_data *data)
> >       reg_cr0_val &= ~MAX31856_CR0_1SHOT;
> >       reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
> >
> > +     if (data->filter_50hz)
> > +             reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
> > +     else
> > +             reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
> > +
> >       return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
> >  }
> >
> > @@ -249,12 +256,53 @@ static ssize_t show_fault_oc(struct device *dev,
> >       return show_fault(dev, MAX31856_FAULT_OPEN, buf);
> >  }
> >
> > +static ssize_t show_filter(struct device *dev,
> > +                        struct device_attribute *attr,
> > +                        char *buf)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +
> > +     return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
> > +}
> > +
> > +static ssize_t set_filter(struct device *dev,
> > +                       struct device_attribute *attr,
> > +                       const char *buf,
> > +                       size_t len)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +     unsigned int freq;
> > +     int ret;
> > +
> > +     ret = kstrtouint(buf, 10, &freq);
> > +     if (ret)
> > +             return ret;
> > +
> > +     switch (freq) {
> > +     case 50:
> > +             data->filter_50hz = true;
> > +             break;
> > +     case 60:
> > +             data->filter_50hz = false;
> > +             break;
> > +     default:
> > +             return -EINVAL;
> > +     }
> > +
> > +     max31856_init(data);
> > +     return len;
> > +}
> > +
> >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> > +static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> >
> >  static struct attribute *max31856_attributes[] = {
> >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> >       &iio_dev_attr_fault_oc.dev_attr.attr,
> > +     &iio_dev_attr_filter.dev_attr.attr,
> >       NULL,
> >  };
> >
> > @@ -280,6 +328,7 @@ static int max31856_probe(struct spi_device *spi)
> >
> >       data = iio_priv(indio_dev);
> >       data->spi = spi;
> > +     data->filter_50hz = false;
> >
> >       spi_set_drvdata(spi, indio_dev);
> >
>

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

* Re: [PATCH 2/3] iio: max31856: add support for configuring the HW averaging
  2019-10-06  7:55   ` Jonathan Cameron
@ 2019-10-16 13:33     ` Andrea Merello
  2019-10-17 12:34       ` Jonathan Cameron
  0 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-10-16 13:33 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	Matthew Weber, Colin King, linux-iio

Il giorno dom 6 ott 2019 alle ore 09:55 Jonathan Cameron
<jic23@kernel.org> ha scritto:
>
> On Mon, 23 Sep 2019 14:17:13 +0200
> Andrea Merello <andrea.merello@gmail.com> wrote:
>
> > This sensor can perform samples averaging in hardware, but currently the
> > driver leaves this setting alone (default is no averaging).
> >
> > This patch introduces a new IIO attribute that allows the user to set the
> > averaging as desired (the HW supports averaging of 2, 5, 8 or 16 samples)
> >
> > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
>
> Sounds like oversampling combined with a lower sampling frequency, so
> there is standard ABI for that.

OK. Do you refer to "oversampling_ratio"?

The datasheet says this applies to thermocouple measure, but by doing
some testing with real HW, it seems that this setting affects both
thermocouple and cold-junction measures, so I guess it shouldn't be in
the form "in_temp_raw_oversampling_ratio"; does this sound right to
you?

> Jonathan
>
> > ---
> >  drivers/iio/temperature/max31856.c | 43 ++++++++++++++++++++++++++++++
> >  1 file changed, 43 insertions(+)
> >
> > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > index d12613f7ba3c..8b2e0102fa5c 100644
> > --- a/drivers/iio/temperature/max31856.c
> > +++ b/drivers/iio/temperature/max31856.c
> > @@ -24,6 +24,8 @@
> >  #define MAX31856_CR0_OCFAULT       BIT(4)
> >  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
> >  #define MAX31856_CR0_FILTER_50HZ   BIT(0)
> > +#define MAX31856_AVERAGING_MASK    GENMASK(6, 4)
> > +#define MAX31856_AVERAGING_SHIFT   4
> >  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
> >  #define MAX31856_FAULT_OVUV        BIT(1)
> >  #define MAX31856_FAULT_OPEN        BIT(0)
> > @@ -65,6 +67,7 @@ struct max31856_data {
> >       struct spi_device *spi;
> >       u32 thermocouple_type;
> >       bool filter_50hz;
> > +     int averaging;
> >  };
> >
> >  static int max31856_read(struct max31856_data *data, u8 reg,
> > @@ -109,6 +112,10 @@ static int max31856_init(struct max31856_data *data)
> >
> >       reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
> >       reg_cr1_val |= data->thermocouple_type;
> > +
> > +     reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
> > +     reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
> > +
> >       ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
> >       if (ret)
> >               return ret;
> > @@ -295,14 +302,50 @@ static ssize_t set_filter(struct device *dev,
> >       return len;
> >  }
> >
> > +static ssize_t show_averaging(struct device *dev,
> > +                           struct device_attribute *attr,
> > +                           char *buf)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +
> > +     return sprintf(buf, "%d\n", 1 << data->averaging);
> > +}
> > +
> > +static ssize_t set_averaging(struct device *dev,
> > +                          struct device_attribute *attr,
> > +                          const char *buf,
> > +                          size_t len)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +     unsigned int nsamples;
> > +     int shift;
> > +     int ret;
> > +
> > +     ret = kstrtouint(buf, 10, &nsamples);
> > +     if (ret)
> > +             return ret;
> > +
> > +     shift = fls(nsamples) - 1;
> > +     if (nsamples > 16 || BIT(shift) != nsamples)
> > +             return -EINVAL;
> > +
> > +     data->averaging = shift;
> > +     max31856_init(data);
> > +     return len;
> > +}
> > +
> >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> >  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> > +static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
> >
> >  static struct attribute *max31856_attributes[] = {
> >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> >       &iio_dev_attr_fault_oc.dev_attr.attr,
> >       &iio_dev_attr_filter.dev_attr.attr,
> > +     &iio_dev_attr_averaging.dev_attr.attr,
> >       NULL,
> >  };
> >
>

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

* Re: [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type
  2019-10-06  7:58   ` Jonathan Cameron
@ 2019-10-16 13:43     ` Andrea Merello
  2019-10-17 12:35       ` Jonathan Cameron
  0 siblings, 1 reply; 13+ messages in thread
From: Andrea Merello @ 2019-10-16 13:43 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: patrick.havelange, paresh.chaudhary, pmeerw, lars, knaack.h,
	Matthew Weber, Colin King, linux-iio

Il giorno dom 6 ott 2019 alle ore 09:58 Jonathan Cameron
<jic23@kernel.org> ha scritto:
>
> On Mon, 23 Sep 2019 14:17:14 +0200
> Andrea Merello <andrea.merello@gmail.com> wrote:
>
> > The sensor support various thermocouple types (e.g. J, K, N, ...). The
> > driver allows to configure this parameter using a DT property.
> >
> > This is useful when i.e. the thermocouple is physically tied to the sensor
> > and it is usually not removed, or when it is at least known in advace
>
> advance

OK

> > which sensor will be connected to the circuit.
> >
> > However, if the user can randomly connect any kind of thermocouples (i.e.
> > the device exposes a connector, and the user is free to connect its own
> > sensors), it would be more appropriate to provide a mechanism to
> > dynamically switch from one thermocouple type to another. This can be i.e.
> > handled in userspace by a GUI, a configuration file or a program that
> > detects the thermocouple type by reading a GPIO, or a eeprom on the probe,
> > or whatever.
> >
> > This patch adds a IIO attribute that can be used to override, at run-time,
> > the DT-provided setting (which serves as default).
> >
> > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
> For now this is device specific ABI so you need to have an entry in
> Documentation/ABI/testing/sysfs-bus-iio-max31856

OK

> Or we could consider this generic enough to put it in a file
> covering other thermocouple to digital sensors.

Yes, theoretically thermocouple-type is a generic thing that isn't
bound to this specific driver/chip. Currently the others IIO
thermocouple drivers don't need this because they supports chips that
handle just a specific thermocouple type, but if you want to make this
API generic for the future then I can go this way.. It seems
reasonable to me indeed.

> Thanks,
>
> Jonathan
>
> > ---
> >  drivers/iio/temperature/max31856.c | 44 ++++++++++++++++++++++++++++++
> >  1 file changed, 44 insertions(+)
> >
> > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > index 8b2e0102fa5c..588e791c79a3 100644
> > --- a/drivers/iio/temperature/max31856.c
> > +++ b/drivers/iio/temperature/max31856.c
> > @@ -6,6 +6,7 @@
> >   * Copyright (C) 2018-2019 Rockwell Collins
> >   */
> >
> > +#include <linux/ctype.h>
> >  #include <linux/module.h>
> >  #include <linux/init.h>
> >  #include <linux/err.h>
> > @@ -70,6 +71,10 @@ struct max31856_data {
> >       int averaging;
> >  };
> >
> > +const char max31856_tc_types[] = {
> > +     'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
> > +};
> > +
> >  static int max31856_read(struct max31856_data *data, u8 reg,
> >                        u8 val[], unsigned int read_size)
> >  {
> > @@ -336,16 +341,55 @@ static ssize_t set_averaging(struct device *dev,
> >       return len;
> >  }
> >
> > +static ssize_t show_tc_type(struct device *dev,
> > +                         struct device_attribute *attr,
> > +                         char *buf)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +
> > +     return sprintf(buf, "%c\n", max31856_tc_types[data->thermocouple_type]);
> > +}
> > +
> > +static ssize_t set_tc_type(struct device *dev,
> > +                        struct device_attribute *attr,
> > +                        const char *buf,
> > +                        size_t len)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     struct max31856_data *data = iio_priv(indio_dev);
> > +     char tmp;
> > +     int tc_type = -1;
> > +     int i;
> > +
> > +     if (sscanf(buf, "%c\n", &tmp) != 1)
> > +             return -EINVAL;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
> > +             if (max31856_tc_types[i] == toupper(tmp)) {
> > +                     tc_type = i;
> > +                     break;
> > +             }
> > +     }
> > +     if (tc_type < 0)
> > +             return -EINVAL;
> > +     data->thermocouple_type = tc_type;
> > +     max31856_init(data);
> > +     return len;
> > +}
> > +
> >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> >  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> >  static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
> > +static IIO_DEVICE_ATTR(thermocouple_type, 0644, show_tc_type, set_tc_type, 0);
> >
> >  static struct attribute *max31856_attributes[] = {
> >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> >       &iio_dev_attr_fault_oc.dev_attr.attr,
> >       &iio_dev_attr_filter.dev_attr.attr,
> >       &iio_dev_attr_averaging.dev_attr.attr,
> > +     &iio_dev_attr_thermocouple_type.dev_attr.attr,
> >       NULL,
> >  };
> >
>

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

* Re: [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency
  2019-10-16 13:14     ` Andrea Merello
@ 2019-10-17 12:32       ` Jonathan Cameron
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-17 12:32 UTC (permalink / raw)
  To: Andrea Merello
  Cc: Jonathan Cameron, patrick.havelange, paresh.chaudhary, pmeerw,
	lars, knaack.h, Matthew Weber, Colin King, linux-iio

On Wed, 16 Oct 2019 15:14:20 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> Il giorno dom 6 ott 2019 alle ore 09:54 Jonathan Cameron
> <jic23@kernel.org> ha scritto:
> >
> > On Mon, 23 Sep 2019 14:17:12 +0200
> > Andrea Merello <andrea.merello@gmail.com> wrote:
> >  
> > > This sensor has an embedded notch filter for reducing interferences caused
> > > by the power mains. This filter can be tuned to reject either 50Hz or 60Hz
> > > (and harmonics).
> > >
> > > Currently the said setting is left alone (the sensor defaults to 60Hz).
> > > This patch introduces a IIO attribute that allows the user to set the said
> > > filter to the desired frequency.
> > >
> > > NOTE: this has been intentionally not tied to any DT property to allow
> > > the configuration of this setting from userspace, e.g. with a GUI or by
> > > reading a configuration file, or maybe reading a GPIO tied to a physical
> > > switch or accessing some device that can autodetect the line frequency.
> > >
> > > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>  
> > This one is not something that can be expect to be known from the setup
> > of the device as it will depend on local mains frequency.
> >
> > So fine, to have it as a userspace control, but the name is too generic.
> > We already have a number of filter attributes and we should try to
> > work out how to bring it inline with them.  
> 
> Sure
> 
> > in_X_filter_low_pass_3db_frequency
> > in_X_filter_high_pass_3db_frequency
> >
> > So would,
> > in_X_filter_notch_center_frequency work?
> > ( I suppose we should use the American spelling ;)  
> 
> Yes, it seems OK in this case. I will produce a V2 with this modification.
> 
> > This kind of ignores the harmonics aspect but at least documents the
> > main frequency being blocked.  
> 
> I think this is perfectly fine: the user wants to set the notch filter
> center frequency to either 60Hz or 50Hz to match the line frequency,
> then she/he expects the filter to simply "work" somehow; IMO the
> harmonic thing does not needed to be explicit.
> 
> > There is a slight complexity that we have devices that have dual
> > notchfilters (50 and 60Hz) and ones where you can turn it off entirely.
> >
> > I suppose no value would count as off and we could perhaps use a list
> > for both on at the same time (though that's a bit horrible).  
> 
> IMHO it seems reasonable. Maybe for all-off and both-on conditions we
> could also use magic strings like i.e. "all" and "off".

I go with 'maybe' on that one.  Need to think about whether that is just
a partial solution as we will probably find a device with 3 options that only
supports any 2 at one time.  That would still need a more complex interface.

Will think on this.

Jonathan

> 
> > > ---
> > >  drivers/iio/temperature/max31856.c | 49 ++++++++++++++++++++++++++++++
> > >  1 file changed, 49 insertions(+)
> > >
> > > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > > index 73ed550e3fc9..d12613f7ba3c 100644
> > > --- a/drivers/iio/temperature/max31856.c
> > > +++ b/drivers/iio/temperature/max31856.c
> > > @@ -23,6 +23,7 @@
> > >  #define MAX31856_CR0_1SHOT         BIT(6)
> > >  #define MAX31856_CR0_OCFAULT       BIT(4)
> > >  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
> > > +#define MAX31856_CR0_FILTER_50HZ   BIT(0)
> > >  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
> > >  #define MAX31856_FAULT_OVUV        BIT(1)
> > >  #define MAX31856_FAULT_OPEN        BIT(0)
> > > @@ -63,6 +64,7 @@ static const struct iio_chan_spec max31856_channels[] = {
> > >  struct max31856_data {
> > >       struct spi_device *spi;
> > >       u32 thermocouple_type;
> > > +     bool filter_50hz;
> > >  };
> > >
> > >  static int max31856_read(struct max31856_data *data, u8 reg,
> > > @@ -123,6 +125,11 @@ static int max31856_init(struct max31856_data *data)
> > >       reg_cr0_val &= ~MAX31856_CR0_1SHOT;
> > >       reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
> > >
> > > +     if (data->filter_50hz)
> > > +             reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
> > > +     else
> > > +             reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
> > > +
> > >       return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
> > >  }
> > >
> > > @@ -249,12 +256,53 @@ static ssize_t show_fault_oc(struct device *dev,
> > >       return show_fault(dev, MAX31856_FAULT_OPEN, buf);
> > >  }
> > >
> > > +static ssize_t show_filter(struct device *dev,
> > > +                        struct device_attribute *attr,
> > > +                        char *buf)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +
> > > +     return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
> > > +}
> > > +
> > > +static ssize_t set_filter(struct device *dev,
> > > +                       struct device_attribute *attr,
> > > +                       const char *buf,
> > > +                       size_t len)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +     unsigned int freq;
> > > +     int ret;
> > > +
> > > +     ret = kstrtouint(buf, 10, &freq);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     switch (freq) {
> > > +     case 50:
> > > +             data->filter_50hz = true;
> > > +             break;
> > > +     case 60:
> > > +             data->filter_50hz = false;
> > > +             break;
> > > +     default:
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     max31856_init(data);
> > > +     return len;
> > > +}
> > > +
> > >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> > >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> > > +static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> > >
> > >  static struct attribute *max31856_attributes[] = {
> > >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> > >       &iio_dev_attr_fault_oc.dev_attr.attr,
> > > +     &iio_dev_attr_filter.dev_attr.attr,
> > >       NULL,
> > >  };
> > >
> > > @@ -280,6 +328,7 @@ static int max31856_probe(struct spi_device *spi)
> > >
> > >       data = iio_priv(indio_dev);
> > >       data->spi = spi;
> > > +     data->filter_50hz = false;
> > >
> > >       spi_set_drvdata(spi, indio_dev);
> > >  
> >  



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

* Re: [PATCH 2/3] iio: max31856: add support for configuring the HW averaging
  2019-10-16 13:33     ` Andrea Merello
@ 2019-10-17 12:34       ` Jonathan Cameron
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-17 12:34 UTC (permalink / raw)
  To: Andrea Merello
  Cc: Jonathan Cameron, patrick.havelange, paresh.chaudhary, pmeerw,
	lars, knaack.h, Matthew Weber, Colin King, linux-iio

On Wed, 16 Oct 2019 15:33:42 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> Il giorno dom 6 ott 2019 alle ore 09:55 Jonathan Cameron
> <jic23@kernel.org> ha scritto:
> >
> > On Mon, 23 Sep 2019 14:17:13 +0200
> > Andrea Merello <andrea.merello@gmail.com> wrote:
> >  
> > > This sensor can perform samples averaging in hardware, but currently the
> > > driver leaves this setting alone (default is no averaging).
> > >
> > > This patch introduces a new IIO attribute that allows the user to set the
> > > averaging as desired (the HW supports averaging of 2, 5, 8 or 16 samples)
> > >
> > > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>  
> >
> > Sounds like oversampling combined with a lower sampling frequency, so
> > there is standard ABI for that.  
> 
> OK. Do you refer to "oversampling_ratio"?
> 
> The datasheet says this applies to thermocouple measure, but by doing
> some testing with real HW, it seems that this setting affects both
> thermocouple and cold-junction measures, so I guess it shouldn't be in
> the form "in_temp_raw_oversampling_ratio"; does this sound right to
> you?
Ah yes. oversampling_ratio it is.  I should read our Docs :)

I think
in_temp_oversampling_ratio will be generated if you use the info_mask_shared_by_type
to do this.

_raw is just another type of information about the channel, rather than
part of the channel naming.

Thanks,

Jonathan

> 
> > Jonathan
> >  
> > > ---
> > >  drivers/iio/temperature/max31856.c | 43 ++++++++++++++++++++++++++++++
> > >  1 file changed, 43 insertions(+)
> > >
> > > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > > index d12613f7ba3c..8b2e0102fa5c 100644
> > > --- a/drivers/iio/temperature/max31856.c
> > > +++ b/drivers/iio/temperature/max31856.c
> > > @@ -24,6 +24,8 @@
> > >  #define MAX31856_CR0_OCFAULT       BIT(4)
> > >  #define MAX31856_CR0_OCFAULT_MASK  GENMASK(5, 4)
> > >  #define MAX31856_CR0_FILTER_50HZ   BIT(0)
> > > +#define MAX31856_AVERAGING_MASK    GENMASK(6, 4)
> > > +#define MAX31856_AVERAGING_SHIFT   4
> > >  #define MAX31856_TC_TYPE_MASK      GENMASK(3, 0)
> > >  #define MAX31856_FAULT_OVUV        BIT(1)
> > >  #define MAX31856_FAULT_OPEN        BIT(0)
> > > @@ -65,6 +67,7 @@ struct max31856_data {
> > >       struct spi_device *spi;
> > >       u32 thermocouple_type;
> > >       bool filter_50hz;
> > > +     int averaging;
> > >  };
> > >
> > >  static int max31856_read(struct max31856_data *data, u8 reg,
> > > @@ -109,6 +112,10 @@ static int max31856_init(struct max31856_data *data)
> > >
> > >       reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
> > >       reg_cr1_val |= data->thermocouple_type;
> > > +
> > > +     reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
> > > +     reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
> > > +
> > >       ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
> > >       if (ret)
> > >               return ret;
> > > @@ -295,14 +302,50 @@ static ssize_t set_filter(struct device *dev,
> > >       return len;
> > >  }
> > >
> > > +static ssize_t show_averaging(struct device *dev,
> > > +                           struct device_attribute *attr,
> > > +                           char *buf)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +
> > > +     return sprintf(buf, "%d\n", 1 << data->averaging);
> > > +}
> > > +
> > > +static ssize_t set_averaging(struct device *dev,
> > > +                          struct device_attribute *attr,
> > > +                          const char *buf,
> > > +                          size_t len)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +     unsigned int nsamples;
> > > +     int shift;
> > > +     int ret;
> > > +
> > > +     ret = kstrtouint(buf, 10, &nsamples);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     shift = fls(nsamples) - 1;
> > > +     if (nsamples > 16 || BIT(shift) != nsamples)
> > > +             return -EINVAL;
> > > +
> > > +     data->averaging = shift;
> > > +     max31856_init(data);
> > > +     return len;
> > > +}
> > > +
> > >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> > >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> > >  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> > > +static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
> > >
> > >  static struct attribute *max31856_attributes[] = {
> > >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> > >       &iio_dev_attr_fault_oc.dev_attr.attr,
> > >       &iio_dev_attr_filter.dev_attr.attr,
> > > +     &iio_dev_attr_averaging.dev_attr.attr,
> > >       NULL,
> > >  };
> > >  
> >  



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

* Re: [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type
  2019-10-16 13:43     ` Andrea Merello
@ 2019-10-17 12:35       ` Jonathan Cameron
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2019-10-17 12:35 UTC (permalink / raw)
  To: Andrea Merello
  Cc: Jonathan Cameron, patrick.havelange, paresh.chaudhary, pmeerw,
	lars, knaack.h, Matthew Weber, Colin King, linux-iio

On Wed, 16 Oct 2019 15:43:18 +0200
Andrea Merello <andrea.merello@gmail.com> wrote:

> Il giorno dom 6 ott 2019 alle ore 09:58 Jonathan Cameron
> <jic23@kernel.org> ha scritto:
> >
> > On Mon, 23 Sep 2019 14:17:14 +0200
> > Andrea Merello <andrea.merello@gmail.com> wrote:
> >  
> > > The sensor support various thermocouple types (e.g. J, K, N, ...). The
> > > driver allows to configure this parameter using a DT property.
> > >
> > > This is useful when i.e. the thermocouple is physically tied to the sensor
> > > and it is usually not removed, or when it is at least known in advace  
> >
> > advance  
> 
> OK
> 
> > > which sensor will be connected to the circuit.
> > >
> > > However, if the user can randomly connect any kind of thermocouples (i.e.
> > > the device exposes a connector, and the user is free to connect its own
> > > sensors), it would be more appropriate to provide a mechanism to
> > > dynamically switch from one thermocouple type to another. This can be i.e.
> > > handled in userspace by a GUI, a configuration file or a program that
> > > detects the thermocouple type by reading a GPIO, or a eeprom on the probe,
> > > or whatever.
> > >
> > > This patch adds a IIO attribute that can be used to override, at run-time,
> > > the DT-provided setting (which serves as default).
> > >
> > > Signed-off-by: Andrea Merello <andrea.merello@gmail.com>  
> > For now this is device specific ABI so you need to have an entry in
> > Documentation/ABI/testing/sysfs-bus-iio-max31856  
> 
> OK
> 
> > Or we could consider this generic enough to put it in a file
> > covering other thermocouple to digital sensors.  
> 
> Yes, theoretically thermocouple-type is a generic thing that isn't
> bound to this specific driver/chip. Currently the others IIO
> thermocouple drivers don't need this because they supports chips that
> handle just a specific thermocouple type, but if you want to make this
> API generic for the future then I can go this way.. It seems
> reasonable to me indeed.
> 

Lets do it then ;)  We might want to add a read only attrs to the
other drivers to make them self describing.

Thanks,

Jonathan

> > Thanks,
> >
> > Jonathan
> >  
> > > ---
> > >  drivers/iio/temperature/max31856.c | 44 ++++++++++++++++++++++++++++++
> > >  1 file changed, 44 insertions(+)
> > >
> > > diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
> > > index 8b2e0102fa5c..588e791c79a3 100644
> > > --- a/drivers/iio/temperature/max31856.c
> > > +++ b/drivers/iio/temperature/max31856.c
> > > @@ -6,6 +6,7 @@
> > >   * Copyright (C) 2018-2019 Rockwell Collins
> > >   */
> > >
> > > +#include <linux/ctype.h>
> > >  #include <linux/module.h>
> > >  #include <linux/init.h>
> > >  #include <linux/err.h>
> > > @@ -70,6 +71,10 @@ struct max31856_data {
> > >       int averaging;
> > >  };
> > >
> > > +const char max31856_tc_types[] = {
> > > +     'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
> > > +};
> > > +
> > >  static int max31856_read(struct max31856_data *data, u8 reg,
> > >                        u8 val[], unsigned int read_size)
> > >  {
> > > @@ -336,16 +341,55 @@ static ssize_t set_averaging(struct device *dev,
> > >       return len;
> > >  }
> > >
> > > +static ssize_t show_tc_type(struct device *dev,
> > > +                         struct device_attribute *attr,
> > > +                         char *buf)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +
> > > +     return sprintf(buf, "%c\n", max31856_tc_types[data->thermocouple_type]);
> > > +}
> > > +
> > > +static ssize_t set_tc_type(struct device *dev,
> > > +                        struct device_attribute *attr,
> > > +                        const char *buf,
> > > +                        size_t len)
> > > +{
> > > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > > +     struct max31856_data *data = iio_priv(indio_dev);
> > > +     char tmp;
> > > +     int tc_type = -1;
> > > +     int i;
> > > +
> > > +     if (sscanf(buf, "%c\n", &tmp) != 1)
> > > +             return -EINVAL;
> > > +
> > > +     for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
> > > +             if (max31856_tc_types[i] == toupper(tmp)) {
> > > +                     tc_type = i;
> > > +                     break;
> > > +             }
> > > +     }
> > > +     if (tc_type < 0)
> > > +             return -EINVAL;
> > > +     data->thermocouple_type = tc_type;
> > > +     max31856_init(data);
> > > +     return len;
> > > +}
> > > +
> > >  static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
> > >  static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
> > >  static IIO_DEVICE_ATTR(filter, 0644, show_filter, set_filter, 0);
> > >  static IIO_DEVICE_ATTR(averaging, 0644, show_averaging, set_averaging, 0);
> > > +static IIO_DEVICE_ATTR(thermocouple_type, 0644, show_tc_type, set_tc_type, 0);
> > >
> > >  static struct attribute *max31856_attributes[] = {
> > >       &iio_dev_attr_fault_ovuv.dev_attr.attr,
> > >       &iio_dev_attr_fault_oc.dev_attr.attr,
> > >       &iio_dev_attr_filter.dev_attr.attr,
> > >       &iio_dev_attr_averaging.dev_attr.attr,
> > > +     &iio_dev_attr_thermocouple_type.dev_attr.attr,
> > >       NULL,
> > >  };
> > >  
> >  



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

end of thread, back to index

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-23 12:17 [PATCH 0/3] iio: max31856: provide more configuration options Andrea Merello
2019-09-23 12:17 ` [PATCH 1/3] iio: max31856: add option for setting mains filter rejection frequency Andrea Merello
2019-10-06  7:54   ` Jonathan Cameron
2019-10-16 13:14     ` Andrea Merello
2019-10-17 12:32       ` Jonathan Cameron
2019-09-23 12:17 ` [PATCH 2/3] iio: max31856: add support for configuring the HW averaging Andrea Merello
2019-10-06  7:55   ` Jonathan Cameron
2019-10-16 13:33     ` Andrea Merello
2019-10-17 12:34       ` Jonathan Cameron
2019-09-23 12:17 ` [PATCH 3/3] iio: max31856: add support for runtime-configuring the thermocouple type Andrea Merello
2019-10-06  7:58   ` Jonathan Cameron
2019-10-16 13:43     ` Andrea Merello
2019-10-17 12:35       ` Jonathan Cameron

Linux-IIO Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-iio/0 linux-iio/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-iio linux-iio/ https://lore.kernel.org/linux-iio \
		linux-iio@vger.kernel.org linux-iio@archiver.kernel.org
	public-inbox-index linux-iio

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-iio


AGPL code for this site: git clone https://public-inbox.org/ public-inbox