iio: adc: ad7124: add 3db filter
diff mbox series

Message ID 20200122085414.16950-1-alexandru.tachici@analog.com
State New
Headers show
Series
  • iio: adc: ad7124: add 3db filter
Related show

Commit Message

Alexandru Tachici Jan. 22, 2020, 8:54 a.m. UTC
This patch adds the LOW_PASS_FILTER_3DB_FREQUENCY attribute
in iio_chan_spec for each channel. The used filters are sinc3
or sinc4. The filter type with the highest output data rate
is used when setting a low pass frequency in the channel's sysfs.

Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>
---
 drivers/iio/adc/ad7124.c | 69 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

Comments

Jonathan Cameron Feb. 2, 2020, 4:22 p.m. UTC | #1
On Wed, 22 Jan 2020 10:54:14 +0200
Alexandru Tachici <alexandru.tachici@analog.com> wrote:

> This patch adds the LOW_PASS_FILTER_3DB_FREQUENCY attribute
> in iio_chan_spec for each channel. The used filters are sinc3
> or sinc4. The filter type with the highest output data rate
> is used when setting a low pass frequency in the channel's sysfs.
> 
> Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>

Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

thanks,

Jonathan

> ---
>  drivers/iio/adc/ad7124.c | 69 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 68 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
> index 52f45b13da4a..8f48c0581f02 100644
> --- a/drivers/iio/adc/ad7124.c
> +++ b/drivers/iio/adc/ad7124.c
> @@ -70,6 +70,11 @@
>  /* AD7124_FILTER_X */
>  #define AD7124_FILTER_FS_MSK		GENMASK(10, 0)
>  #define AD7124_FILTER_FS(x)		FIELD_PREP(AD7124_FILTER_FS_MSK, x)
> +#define AD7124_FILTER_TYPE_MSK		GENMASK(23, 21)
> +#define AD7124_FILTER_TYPE_SEL(x)	FIELD_PREP(AD7124_FILTER_TYPE_MSK, x)
> +
> +#define AD7124_SINC3_FILTER 2
> +#define AD7124_SINC4_FILTER 0
>  
>  enum ad7124_ids {
>  	ID_AD7124_4,
> @@ -119,6 +124,7 @@ struct ad7124_channel_config {
>  	unsigned int vref_mv;
>  	unsigned int pga_bits;
>  	unsigned int odr;
> +	unsigned int filter_type;
>  };
>  
>  struct ad7124_state {
> @@ -138,7 +144,8 @@ static const struct iio_chan_spec ad7124_channel_template = {
>  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
>  		BIT(IIO_CHAN_INFO_SCALE) |
>  		BIT(IIO_CHAN_INFO_OFFSET) |
> -		BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> +		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
>  	.scan_type = {
>  		.sign = 'u',
>  		.realbits = 24,
> @@ -281,6 +288,58 @@ static int ad7124_set_channel_gain(struct ad7124_state *st,
>  	return 0;
>  }
>  
> +static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
> +				      unsigned int channel)
> +{
> +	unsigned int fadc;
> +
> +	fadc = st->channel_config[channel].odr;
> +
> +	switch (st->channel_config[channel].filter_type) {
> +	case AD7124_SINC3_FILTER:
> +		return DIV_ROUND_CLOSEST(fadc * 230, 1000);
> +	case AD7124_SINC4_FILTER:
> +		return DIV_ROUND_CLOSEST(fadc * 262, 1000);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int ad7124_set_3db_filter_freq(struct ad7124_state *st,
> +				      unsigned int channel,
> +				      unsigned int freq)
> +{
> +	unsigned int sinc4_3db_odr;
> +	unsigned int sinc3_3db_odr;
> +	unsigned int new_filter;
> +	unsigned int new_odr;
> +
> +	sinc4_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 230);
> +	sinc3_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 262);
> +
> +	if (sinc4_3db_odr > sinc3_3db_odr) {
> +		new_filter = AD7124_SINC3_FILTER;
> +		new_odr = sinc4_3db_odr;
> +	} else {
> +		new_filter = AD7124_SINC4_FILTER;
> +		new_odr = sinc3_3db_odr;
> +	}
> +
> +	if (st->channel_config[channel].filter_type != new_filter) {
> +		int ret;
> +
> +		st->channel_config[channel].filter_type = new_filter;
> +		ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
> +					    AD7124_FILTER_TYPE_MSK,
> +					    AD7124_FILTER_TYPE_SEL(new_filter),
> +					    3);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return ad7124_set_channel_odr(st, channel, new_odr);
> +}
> +
>  static int ad7124_read_raw(struct iio_dev *indio_dev,
>  			   struct iio_chan_spec const *chan,
>  			   int *val, int *val2, long info)
> @@ -322,6 +381,9 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
>  	case IIO_CHAN_INFO_SAMP_FREQ:
>  		*val = st->channel_config[chan->address].odr;
>  
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> +		*val = ad7124_get_3db_filter_freq(st, chan->scan_index);
>  		return IIO_VAL_INT;
>  	default:
>  		return -EINVAL;
> @@ -355,6 +417,11 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
>  		gain = DIV_ROUND_CLOSEST(res, val2);
>  
>  		return ad7124_set_channel_gain(st, chan->address, gain);
> +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> +		if (val2 != 0)
> +			return -EINVAL;
> +
> +		return ad7124_set_3db_filter_freq(st, chan->address, val);
>  	default:
>  		return -EINVAL;
>  	}

Patch
diff mbox series

diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 52f45b13da4a..8f48c0581f02 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -70,6 +70,11 @@ 
 /* AD7124_FILTER_X */
 #define AD7124_FILTER_FS_MSK		GENMASK(10, 0)
 #define AD7124_FILTER_FS(x)		FIELD_PREP(AD7124_FILTER_FS_MSK, x)
+#define AD7124_FILTER_TYPE_MSK		GENMASK(23, 21)
+#define AD7124_FILTER_TYPE_SEL(x)	FIELD_PREP(AD7124_FILTER_TYPE_MSK, x)
+
+#define AD7124_SINC3_FILTER 2
+#define AD7124_SINC4_FILTER 0
 
 enum ad7124_ids {
 	ID_AD7124_4,
@@ -119,6 +124,7 @@  struct ad7124_channel_config {
 	unsigned int vref_mv;
 	unsigned int pga_bits;
 	unsigned int odr;
+	unsigned int filter_type;
 };
 
 struct ad7124_state {
@@ -138,7 +144,8 @@  static const struct iio_chan_spec ad7124_channel_template = {
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 		BIT(IIO_CHAN_INFO_SCALE) |
 		BIT(IIO_CHAN_INFO_OFFSET) |
-		BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
 	.scan_type = {
 		.sign = 'u',
 		.realbits = 24,
@@ -281,6 +288,58 @@  static int ad7124_set_channel_gain(struct ad7124_state *st,
 	return 0;
 }
 
+static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
+				      unsigned int channel)
+{
+	unsigned int fadc;
+
+	fadc = st->channel_config[channel].odr;
+
+	switch (st->channel_config[channel].filter_type) {
+	case AD7124_SINC3_FILTER:
+		return DIV_ROUND_CLOSEST(fadc * 230, 1000);
+	case AD7124_SINC4_FILTER:
+		return DIV_ROUND_CLOSEST(fadc * 262, 1000);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ad7124_set_3db_filter_freq(struct ad7124_state *st,
+				      unsigned int channel,
+				      unsigned int freq)
+{
+	unsigned int sinc4_3db_odr;
+	unsigned int sinc3_3db_odr;
+	unsigned int new_filter;
+	unsigned int new_odr;
+
+	sinc4_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 230);
+	sinc3_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 262);
+
+	if (sinc4_3db_odr > sinc3_3db_odr) {
+		new_filter = AD7124_SINC3_FILTER;
+		new_odr = sinc4_3db_odr;
+	} else {
+		new_filter = AD7124_SINC4_FILTER;
+		new_odr = sinc3_3db_odr;
+	}
+
+	if (st->channel_config[channel].filter_type != new_filter) {
+		int ret;
+
+		st->channel_config[channel].filter_type = new_filter;
+		ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
+					    AD7124_FILTER_TYPE_MSK,
+					    AD7124_FILTER_TYPE_SEL(new_filter),
+					    3);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ad7124_set_channel_odr(st, channel, new_odr);
+}
+
 static int ad7124_read_raw(struct iio_dev *indio_dev,
 			   struct iio_chan_spec const *chan,
 			   int *val, int *val2, long info)
@@ -322,6 +381,9 @@  static int ad7124_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		*val = st->channel_config[chan->address].odr;
 
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		*val = ad7124_get_3db_filter_freq(st, chan->scan_index);
 		return IIO_VAL_INT;
 	default:
 		return -EINVAL;
@@ -355,6 +417,11 @@  static int ad7124_write_raw(struct iio_dev *indio_dev,
 		gain = DIV_ROUND_CLOSEST(res, val2);
 
 		return ad7124_set_channel_gain(st, chan->address, gain);
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (val2 != 0)
+			return -EINVAL;
+
+		return ad7124_set_3db_filter_freq(st, chan->address, val);
 	default:
 		return -EINVAL;
 	}