Commit ea2ccb3e authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Jonathan Cameron

staging:iio:adis16400: Fix adis16334 sampling frequency control

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: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 15358a7f
......@@ -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);
};
/**
......
......@@ -161,10 +161,39 @@ static int adis16400_spi_read_reg_16(struct iio_dev *indio_dev,
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,
}
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment