[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