Re: [PATCH] staging: iio: ad7780: Add gain & filter gpio support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mi, 2018-11-21 at 16:04 -0200, Giuliano Belinassi wrote:
> Previously, the AD7780 driver only supported gpio for the 'powerdown'
> pin. This commit adds suppport for the 'gain' and 'filter' pin.
Hey,

Comments inline.
> 
> Signed-off-by: Giuliano Belinassi <giuliano.belinassi@xxxxxx>
> ---
>  drivers/staging/iio/adc/ad7780.c       | 61 ++++++++++++++++++++++++--
>  include/linux/iio/adc/ad_sigma_delta.h |  5 +++
>  2 files changed, 62 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/staging/iio/adc/ad7780.c
> b/drivers/staging/iio/adc/ad7780.c
> index c4a85789c2db..69794f06dbcd 100644
> --- a/drivers/staging/iio/adc/ad7780.c
> +++ b/drivers/staging/iio/adc/ad7780.c
> @@ -39,6 +39,9 @@
>  #define AD7170_PATTERN		(AD7780_PAT0 | AD7170_PAT2)
>  #define AD7170_PATTERN_MASK	(AD7780_PAT0 | AD7780_PAT1 |
> AD7170_PAT2)
>  
> +#define AD7780_GAIN_GPIO	0
> +#define AD7780_FILTER_GPIO	1
> +
>  struct ad7780_chip_info {
>  	struct iio_chan_spec	channel;
>  	unsigned int		pattern_mask;
> @@ -50,6 +53,8 @@ struct ad7780_state {
>  	const struct ad7780_chip_info	*chip_info;
>  	struct regulator		*reg;
>  	struct gpio_desc		*powerdown_gpio;
> +	struct gpio_desc		*gain_gpio;
> +	struct gpio_desc		*filter_gpio;
>  	unsigned int	gain;
>  
>  	struct ad_sigma_delta sd;
> @@ -115,18 +120,51 @@ static int ad7780_read_raw(struct iio_dev
> *indio_dev,
>  	return -EINVAL;
>  }
>  
> +static int ad7780_write_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan,
> +			    int val,
> +			    int val2,
> +			    long m)
> +{
> +	struct ad7780_state *st = iio_priv(indio_dev);
> +
> +	if (m != IIO_CHAN_INFO_RAW)
> +		return -EINVAL;
> +
> +	if (st->chip_info->is_ad778x) {
> +		switch(val) {
> +		case AD7780_GAIN_GPIO:

I think that instead of setting the gain directly, we should use
the IIO_CHAN_INFO_SCALE attribute. At page 12 of the ad7780 datasheet there
is a formula from which the output code can be calculated:
Code = 2^(N − 1)
× [(AIN × Gain /VREF) + 1]. So, by setting the scale from user space, the
driver can calculate the correct gain by using the formula above. Also, it
would be useful to introduce scale available.
Furthermore, there is a new
ad7124 adc driver which does this exact thing. Take a look here: https://gi
thub.com/analogdevicesinc/linux/blob/master/drivers/iio/adc/ad7124.c#L337.

> +			gpiod_set_value(st->gain_gpio, val2);
> +		break;
> +		case AD7780_FILTER_GPIO:

The attribute that should be used to configure the filter gpio is
IIO_CHAN_INFO_SAMP_FREQ. So, we should have 10 Hz and 16.7 Hz available
sampling frequencies. If from user space the 10 Hz sampling freq is
requested, then we set the FILTER pin high, while for 16.7 Hz the FILTER
pin will be low.

> +			gpiod_set_value(st->filter_gpio, val2);
> +		break;
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
>  				     unsigned int raw_sample)
>  {
>  	struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
>  	const struct ad7780_chip_info *chip_info = st->chip_info;
> +	int val;
>  
>  	if ((raw_sample & AD7780_ERR) ||
>  	    ((raw_sample & chip_info->pattern_mask) != chip_info-
> >pattern))
>  		return -EIO;
>  
>  	if (chip_info->is_ad778x) {
> -		if (raw_sample & AD7780_GAIN)
> +		val = raw_sample & AD7780_GAIN;
> +
> +		if (val != gpiod_get_value(st->gain_gpio))
> +			return -EIO;
> +
> +		if (val)
>  			st->gain = 1;
>  		else
>  			st->gain = 128;
> @@ -141,18 +179,20 @@ static const struct ad_sigma_delta_info
> ad7780_sigma_delta_info = {
>  	.has_registers = false,
>  };
>  
> -#define AD7780_CHANNEL(bits, wordsize) \
> +#define AD7170_CHANNEL(bits, wordsize) \
>  	AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits)
> +#define AD7780_CHANNEL(bits, wordsize) \
> +	AD_SD_CHANNEL_GAIN_FILTER(1, 0, 0, bits, 32, wordsize - bits)
>  
>  static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
>  	[ID_AD7170] = {
> -		.channel = AD7780_CHANNEL(12, 24),
> +		.channel = AD7170_CHANNEL(12, 24),
>  		.pattern = AD7170_PATTERN,
>  		.pattern_mask = AD7170_PATTERN_MASK,
>  		.is_ad778x = false,
>  	},
>  	[ID_AD7171] = {
> -		.channel = AD7780_CHANNEL(16, 24),
> +		.channel = AD7170_CHANNEL(16, 24),
>  		.pattern = AD7170_PATTERN,
>  		.pattern_mask = AD7170_PATTERN_MASK,
>  		.is_ad778x = false,
> @@ -173,6 +213,7 @@ static const struct ad7780_chip_info
> ad7780_chip_info_tbl[] = {
>  
>  static const struct iio_info ad7780_info = {
>  	.read_raw = ad7780_read_raw,
> +	.write_raw = ad7780_write_raw,
>  };
>  
>  static int ad7780_probe(struct spi_device *spi)
> @@ -222,6 +263,18 @@ static int ad7780_probe(struct spi_device *spi)
>  		goto error_disable_reg;
>  	}
>  
> +	if (st->chip_info->is_ad778x) {
> +		st->gain_gpio = devm_gpiod_get_optional(&spi->dev,
> +							"gain",
> +							GPIOD_OUT_HIGH);
> +		if (IS_ERR(st->gain_gpio)) {
> +			ret = PTR_ERR(st->gain_gpio);
> +			dev_err(&spi->dev, "Failed to request gain GPIO:
> %d\n",
> +				ret);
> +			goto error_disable_reg;
> +		}
> +	}
> +
>  	ret = ad_sd_setup_buffer_and_trigger(indio_dev);
>  	if (ret)
>  		goto error_disable_reg;
> diff --git a/include/linux/iio/adc/ad_sigma_delta.h
> b/include/linux/iio/adc/ad_sigma_delta.h
> index 730ead1a46df..6cadab6fd5fd 100644
> --- a/include/linux/iio/adc/ad_sigma_delta.h
> +++ b/include/linux/iio/adc/ad_sigma_delta.h
> @@ -173,6 +173,11 @@ int ad_sd_validate_trigger(struct iio_dev
> *indio_dev, struct iio_trigger *trig);
>  	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
>  		_storagebits, _shift, NULL, IIO_VOLTAGE, 0)
>  
> +#define AD_SD_CHANNEL_GAIN_FILTER(_si, _channel, _address, _bits, \
> +	_storagebits, _shift) \
> +	__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
> +		_storagebits, _shift, NULL, IIO_VOLTAGE,
> BIT(IIO_CHAN_INFO_RAW))
> +
>  #define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \
>  	__AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \
>  		_storagebits, _shift, NULL, IIO_TEMP, \




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux