[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-iio
Subject:    Re: [PATCH 1/4] staging:iio:adis16400: Fix adis16334 sampling frequency control
From:       Jonathan Cameron <jic23 () kernel ! org>
Date:       2012-10-31 11:06:36
Message-ID: 5091063C.3060302 () kernel ! org
[Download RAW message or body]

On 10/30/2012 10:26 AM, Lars-Peter Clausen wrote:
> Setting the sampling frequency for the adis16334 differs from the other devices.
> This patch introduces two new callback functions to the adis16400 chip_info
> struct which are used to specify how to read and write the current sample rate.
> The patch also introduces the proper implementations for these callbacks for the
> adis16334.
> 
> Related to this is that the adis16334 has no slow mode and so we do not limit
> the SPI clock rate to 300kHz during initialization. The patch adds a new flag
> for devices which do have a slow mode.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
All 4 added to fixes-togreg branch of iio.git
They are a little more invasive that I'd normally like, but they
are fixing real problems that could cause the new driver not to work
(other than the duplicate entry removal and I could not be bothered
to separate that one out)


> ---
>  drivers/staging/iio/imu/adis16400.h      |  11 ++-
>  drivers/staging/iio/imu/adis16400_core.c | 122 +++++++++++++++++++++++--------
>  2 files changed, 101 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h
> index 77c601d..07a6aea 100644
> --- a/drivers/staging/iio/imu/adis16400.h
> +++ b/drivers/staging/iio/imu/adis16400.h
> @@ -123,6 +123,9 @@
>  /* SLP_CNT */
>  #define ADIS16400_SLP_CNT_POWER_OFF	(1<<8)
>  
> +#define ADIS16334_RATE_DIV_SHIFT 8
> +#define ADIS16334_RATE_INT_CLK BIT(0)
> +
>  #define ADIS16400_MAX_TX 24
>  #define ADIS16400_MAX_RX 24
>  
> @@ -130,8 +133,10 @@
>  #define ADIS16400_SPI_BURST	(u32)(1000 * 1000)
>  #define ADIS16400_SPI_FAST	(u32)(2000 * 1000)
>  
> -#define ADIS16400_HAS_PROD_ID 1
> -#define ADIS16400_NO_BURST 2
> +#define ADIS16400_HAS_PROD_ID		BIT(0)
> +#define ADIS16400_NO_BURST		BIT(1)
> +#define ADIS16400_HAS_SLOW_MODE		BIT(2)
> +
>  struct adis16400_chip_info {
>  	const struct iio_chan_spec *channels;
>  	const int num_channels;
> @@ -142,6 +147,8 @@ struct adis16400_chip_info {
>  	int temp_scale_nano;
>  	int temp_offset;
>  	unsigned long default_scan_mask;
> +	int (*set_freq)(struct iio_dev *indio_dev, unsigned int freq);
> +	int (*get_freq)(struct iio_dev *indio_dev);
>  };
>  
>  /**
> diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
> index 3144a7b..4d03bdc 100644
> --- a/drivers/staging/iio/imu/adis16400_core.c
> +++ b/drivers/staging/iio/imu/adis16400_core.c
> @@ -161,10 +161,39 @@ error_ret:
>  	return ret;
>  }
>  
> -static int adis16400_get_freq(struct iio_dev *indio_dev)
> +static int adis16334_get_freq(struct iio_dev *indio_dev)
>  {
> +	int ret;
>  	u16 t;
> +
> +	ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t);
> +	if (ret < 0)
> +		return ret;
> +
> +	t >>= ADIS16334_RATE_DIV_SHIFT;
> +
> +	return (8192 >> t) / 10;
> +}
> +
> +static int adis16334_set_freq(struct iio_dev *indio_dev, unsigned int freq)
> +{
> +	unsigned int t;
> +
> +	t = ilog2(8192 / (freq * 10));
> +
> +	if (t > 0x31)
> +		t = 0x31;
> +
> +	t <<= ADIS16334_RATE_DIV_SHIFT;
> +	t |= ADIS16334_RATE_INT_CLK;
> +
> +	return adis16400_spi_write_reg_16(indio_dev, ADIS16400_SMPL_PRD, t);
> +}
> +
> +static int adis16400_get_freq(struct iio_dev *indio_dev)
> +{
>  	int sps, ret;
> +	u16 t;
>  
>  	ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t);
>  	if (ret < 0)
> @@ -175,13 +204,33 @@ static int adis16400_get_freq(struct iio_dev *indio_dev)
>  	return sps;
>  }
>  
> +static int adis16400_set_freq(struct iio_dev *indio_dev, unsigned int freq)
> +{
> +	struct adis16400_state *st = iio_priv(indio_dev);
> +	unsigned int t;
> +
> +	t = 1638 / freq;
> +	if (t > 0)
> +		t--;
> +	t &= ADIS16400_SMPL_PRD_DIV_MASK;
> +	if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A)
> +		st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +	else
> +		st->us->max_speed_hz = ADIS16400_SPI_FAST;
> +
> +	return adis16400_spi_write_reg_8(indio_dev,
> +			ADIS16400_SMPL_PRD, t);
> +}
> +
>  static ssize_t adis16400_read_frequency(struct device *dev,
>  		struct device_attribute *attr,
>  		char *buf)
>  {
>  	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct adis16400_state *st = iio_priv(indio_dev);
>  	int ret, len = 0;
> -	ret = adis16400_get_freq(indio_dev);
> +
> +	ret = st->variant->get_freq(indio_dev);
>  	if (ret < 0)
>  		return ret;
>  	len = sprintf(buf, "%d SPS\n", ret);
> @@ -229,7 +278,6 @@ static ssize_t adis16400_write_frequency(struct device *dev,
>  	struct adis16400_state *st = iio_priv(indio_dev);
>  	long val;
>  	int ret;
> -	u8 t;
>  
>  	ret = strict_strtol(buf, 10, &val);
>  	if (ret)
> @@ -239,18 +287,7 @@ static ssize_t adis16400_write_frequency(struct device *dev,
>  
>  	mutex_lock(&indio_dev->mlock);
>  
> -	t = (1638 / val);
> -	if (t > 0)
> -		t--;
> -	t &= ADIS16400_SMPL_PRD_DIV_MASK;
> -	if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A)
> -		st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> -	else
> -		st->us->max_speed_hz = ADIS16400_SPI_FAST;
> -
> -	ret = adis16400_spi_write_reg_8(indio_dev,
> -			ADIS16400_SMPL_PRD,
> -			t);
> +	st->variant->set_freq(indio_dev, val);
>  
>  	/* Also update the filter */
>  	mutex_unlock(&indio_dev->mlock);
> @@ -380,8 +417,11 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
>  	u16 prod_id, smp_prd;
>  	struct adis16400_state *st = iio_priv(indio_dev);
>  
> -	/* use low spi speed for init */
> -	st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +	/* use low spi speed for init if the device has a slow mode */
> +	if (st->variant->flags & ADIS16400_HAS_SLOW_MODE)
> +		st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +	else
> +		st->us->max_speed_hz = ADIS16400_SPI_FAST;
>  	st->us->mode = SPI_MODE_3;
>  	spi_setup(st->us);
>  
> @@ -422,11 +462,16 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
>  		       st->us->chip_select, st->us->irq);
>  	}
>  	/* use high spi speed if possible */
> -	ret = adis16400_spi_read_reg_16(indio_dev,
> -					ADIS16400_SMPL_PRD, &smp_prd);
> -	if (!ret && (smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) {
> -		st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> -		spi_setup(st->us);
> +	if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) {
> +		ret = adis16400_spi_read_reg_16(indio_dev,
> +						ADIS16400_SMPL_PRD, &smp_prd);
> +		if (ret)
> +			goto err_ret;
> +
> +		if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) {
> +			st->us->max_speed_hz = ADIS16400_SPI_FAST;
> +			spi_setup(st->us);
> +		}
>  	}
>  
>  err_ret:
> @@ -503,7 +548,7 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
>  		mutex_lock(&indio_dev->mlock);
>  		st->filt_int = val;
>  		/* Work out update to current value */
> -		sps = adis16400_get_freq(indio_dev);
> +		sps = st->variant->get_freq(indio_dev);
>  		if (sps < 0) {
>  			mutex_unlock(&indio_dev->mlock);
>  			return sps;
> @@ -601,7 +646,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
>  			mutex_unlock(&indio_dev->mlock);
>  			return ret;
>  		}
> -		ret = adis16400_get_freq(indio_dev);
> +		val16 = st->variant->get_freq(indio_dev);
>  		if (ret > 0)
>  			*val = ret/adis16400_3db_divisors[val16 & 0x03];
>  		*val2 = 0;
> @@ -1060,6 +1105,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
>  	[ADIS16300] = {
>  		.channels = adis16300_channels,
>  		.num_channels = ARRAY_SIZE(adis16300_channels),
> +		.flags = ADIS16400_HAS_SLOW_MODE,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = 5884,
>  		.temp_scale_nano = 140000000, /* 0.14 C */
> @@ -1070,6 +1116,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
>  		(1 << ADIS16400_SCAN_TEMP) | (1 << ADIS16400_SCAN_ADC_0) |
>  		(1 << ADIS16300_SCAN_INCLI_X) | (1 << ADIS16300_SCAN_INCLI_Y) |
>  		(1 << 14),
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16334] = {
>  		.channels = adis16334_channels,
> @@ -1082,6 +1130,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
>  		(1 << ADIS16400_SCAN_GYRO_Y) | (1 << ADIS16400_SCAN_GYRO_Z) |
>  		(1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_ACC_Y) |
>  		(1 << ADIS16400_SCAN_ACC_Z),
> +		.set_freq = adis16334_set_freq,
> +		.get_freq = adis16334_get_freq,
>  	},
>  	[ADIS16350] = {
>  		.channels = adis16350_channels,
> @@ -1091,62 +1141,74 @@ static struct adis16400_chip_info adis16400_chips[] = {
>  		.temp_scale_nano = 145300000, /* 0.1453 C */
>  		.temp_offset = 25000000 / 145300, /* 25 C = 0x00 */
>  		.default_scan_mask = 0x7FF,
> -		.flags = ADIS16400_NO_BURST,
> +		.flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16360] = {
>  		.channels = adis16350_channels,
>  		.num_channels = ARRAY_SIZE(adis16350_channels),
> -		.flags = ADIS16400_HAS_PROD_ID,
> +		.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
>  		.product_id = 0x3FE8,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
>  		.temp_scale_nano = 136000000, /* 0.136 C */
>  		.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
>  		.default_scan_mask = 0x7FF,
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16362] = {
>  		.channels = adis16350_channels,
>  		.num_channels = ARRAY_SIZE(adis16350_channels),
> -		.flags = ADIS16400_HAS_PROD_ID,
> +		.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
>  		.product_id = 0x3FEA,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */
>  		.temp_scale_nano = 136000000, /* 0.136 C */
>  		.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
>  		.default_scan_mask = 0x7FF,
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16364] = {
>  		.channels = adis16350_channels,
>  		.num_channels = ARRAY_SIZE(adis16350_channels),
> -		.flags = ADIS16400_HAS_PROD_ID,
> +		.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
>  		.product_id = 0x3FEC,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
>  		.temp_scale_nano = 136000000, /* 0.136 C */
>  		.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
>  		.default_scan_mask = 0x7FF,
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16365] = {
>  		.channels = adis16350_channels,
>  		.num_channels = ARRAY_SIZE(adis16350_channels),
> -		.flags = ADIS16400_HAS_PROD_ID,
> +		.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
>  		.product_id = 0x3FED,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
>  		.temp_scale_nano = 136000000, /* 0.136 C */
>  		.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
>  		.default_scan_mask = 0x7FF,
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	},
>  	[ADIS16400] = {
>  		.channels = adis16400_channels,
>  		.num_channels = ARRAY_SIZE(adis16400_channels),
> -		.flags = ADIS16400_HAS_PROD_ID,
> +		.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
>  		.product_id = 0x4015,
>  		.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
>  		.accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
>  		.default_scan_mask = 0xFFF,
>  		.temp_scale_nano = 140000000, /* 0.14 C */
>  		.temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
> +		.set_freq = adis16400_set_freq,
> +		.get_freq = adis16400_get_freq,
>  	}
>  };
>  
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic