summaryrefslogtreecommitdiff
path: root/drivers/iio/imu/adis16480.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/imu/adis16480.c')
-rw-r--r--drivers/iio/imu/adis16480.c555
1 files changed, 449 insertions, 106 deletions
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index b40a55bba30c..543d5c4bfb11 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -104,11 +104,10 @@
*/
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
#define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C)
-#define ADIS16495_BURST_ID 0xA5A5
+#define ADIS16495_GYRO_ACCEL_BURST_ID 0xA5A5
+#define ADIS16545_DELTA_ANG_VEL_BURST_ID 0xC3C3
/* total number of segments in burst */
#define ADIS16495_BURST_MAX_DATA 20
-/* spi max speed in burst mode */
-#define ADIS16495_BURST_MAX_SPEED 6000000
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
@@ -134,6 +133,10 @@
#define ADIS16480_SYNC_MODE_MSK BIT(8)
#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
+#define ADIS16545_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
+#define ADIS16545_BURST_DATA_SEL_1_CHN_MASK GENMASK(16, 11)
+#define ADIS16545_BURST_DATA_SEL_MASK BIT(8)
+
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
@@ -142,11 +145,14 @@ struct adis16480_chip_info {
unsigned int accel_max_val;
unsigned int accel_max_scale;
unsigned int temp_scale;
+ unsigned int deltang_max_val;
+ unsigned int deltvel_max_val;
unsigned int int_clk;
unsigned int max_dec_rate;
const unsigned int *filter_freqs;
bool has_pps_clk_mode;
bool has_sleep_cnt;
+ bool has_burst_delta_data;
const struct adis_data adis_data;
};
@@ -170,6 +176,7 @@ struct adis16480 {
struct clk *ext_clk;
enum adis16480_clock_mode clk_mode;
unsigned int clk_freq;
+ u16 burst_id;
/* Alignment needed for the timestamp */
__be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
};
@@ -186,8 +193,6 @@ module_param(low_rate_allow, bool, 0444);
MODULE_PARM_DESC(low_rate_allow,
"Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)");
-#ifdef CONFIG_DEBUG_FS
-
static ssize_t adis16480_show_firmware_revision(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
@@ -297,11 +302,14 @@ static int adis16480_show_flash_count(void *arg, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(adis16480_flash_count_fops,
adis16480_show_flash_count, NULL, "%lld\n");
-static int adis16480_debugfs_init(struct iio_dev *indio_dev)
+static void adis16480_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16480 *adis16480 = iio_priv(indio_dev);
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return;
+
debugfs_create_file_unsafe("firmware_revision", 0400,
d, adis16480, &adis16480_firmware_revision_fops);
debugfs_create_file_unsafe("firmware_date", 0400,
@@ -312,19 +320,8 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev)
d, adis16480, &adis16480_product_id_fops);
debugfs_create_file_unsafe("flash_count", 0400,
d, adis16480, &adis16480_flash_count_fops);
-
- return 0;
}
-#else
-
-static int adis16480_debugfs_init(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-#endif
-
static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
{
struct adis16480 *st = iio_priv(indio_dev);
@@ -338,7 +335,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t == 0)
return -EINVAL;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
/*
* When using PPS mode, the input clock needs to be scaled so that we have an IMU
* sample rate between (optimally) 4000 and 4250. After this, we can use the
@@ -381,7 +378,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = scaled_rate;
}
@@ -393,10 +390,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t > st->chip_info->max_dec_rate)
t = st->chip_info->max_dec_rate;
- ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
-error:
- adis_dev_unlock(&st->adis);
- return ret;
+ return __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
}
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
@@ -406,23 +400,21 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
int ret;
unsigned int freq, sample_rate = st->clk_freq;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
if (st->clk_mode == ADIS16480_CLK_PPS) {
u16 sync_scale;
ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = st->clk_freq * sync_scale;
}
ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
if (ret)
- goto error;
-
- adis_dev_unlock(&st->adis);
+ return ret;
freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
@@ -430,9 +422,6 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
*val2 = (freq % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
-error:
- adis_dev_unlock(&st->adis);
- return ret;
}
enum {
@@ -447,6 +436,12 @@ enum {
ADIS16480_SCAN_MAGN_Z,
ADIS16480_SCAN_BARO,
ADIS16480_SCAN_TEMP,
+ ADIS16480_SCAN_DELTANG_X,
+ ADIS16480_SCAN_DELTANG_Y,
+ ADIS16480_SCAN_DELTANG_Z,
+ ADIS16480_SCAN_DELTVEL_X,
+ ADIS16480_SCAN_DELTVEL_Y,
+ ADIS16480_SCAN_DELTVEL_Z,
};
static const unsigned int adis16480_calibbias_regs[] = {
@@ -617,11 +612,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
- goto out_unlock;
+ return ret;
if (freq == 0) {
val &= ~enable_mask;
@@ -643,11 +638,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
val |= enable_mask;
}
- ret = __adis_write_reg_16(&st->adis, reg, val);
-out_unlock:
- adis_dev_unlock(&st->adis);
-
- return ret;
+ return __adis_write_reg_16(&st->adis, reg, val);
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
@@ -690,6 +681,14 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
*val = 131; /* 1310mbar = 131 kPa */
*val2 = 32767 << 16;
return IIO_VAL_FRACTIONAL;
+ case IIO_DELTA_ANGL:
+ *val = st->chip_info->deltang_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_DELTA_VELOCITY:
+ *val = st->chip_info->deltvel_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
@@ -763,6 +762,24 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
BIT(IIO_CHAN_INFO_CALIBSCALE), \
32)
+#define ADIS16480_DELTANG_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, ADIS16480_SCAN_DELTANG_ ## _mod, \
+ 0, 32)
+
+#define ADIS16480_DELTANG_CHANNEL_NO_SCAN(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, -1, 0, 32)
+
+#define ADIS16480_DELTVEL_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, ADIS16480_SCAN_DELTVEL_ ## _mod, \
+ 0, 32)
+
+#define ADIS16480_DELTVEL_CHANNEL_NO_SCAN(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, -1, 0, 32)
+
#define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
@@ -818,7 +835,13 @@ static const struct iio_chan_spec adis16480_channels[] = {
ADIS16480_MAGN_CHANNEL(Z),
ADIS16480_PRESSURE_CHANNEL(),
ADIS16480_TEMP_CHANNEL(),
- IIO_CHAN_SOFT_TIMESTAMP(11)
+ IIO_CHAN_SOFT_TIMESTAMP(11),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
static const struct iio_chan_spec adis16485_channels[] = {
@@ -829,14 +852,58 @@ static const struct iio_chan_spec adis16485_channels[] = {
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_TEMP_CHANNEL(),
- IIO_CHAN_SOFT_TIMESTAMP(7)
+ IIO_CHAN_SOFT_TIMESTAMP(7),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
+};
+
+static const struct iio_chan_spec adis16545_channels[] = {
+ ADIS16480_GYRO_CHANNEL(X),
+ ADIS16480_GYRO_CHANNEL(Y),
+ ADIS16480_GYRO_CHANNEL(Z),
+ ADIS16480_ACCEL_CHANNEL(X),
+ ADIS16480_ACCEL_CHANNEL(Y),
+ ADIS16480_ACCEL_CHANNEL(Z),
+ ADIS16480_TEMP_CHANNEL(),
+ ADIS16480_DELTANG_CHANNEL(X),
+ ADIS16480_DELTANG_CHANNEL(Y),
+ ADIS16480_DELTANG_CHANNEL(Z),
+ ADIS16480_DELTVEL_CHANNEL(X),
+ ADIS16480_DELTVEL_CHANNEL(Y),
+ ADIS16480_DELTVEL_CHANNEL(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(17),
+};
+
+static const struct iio_chan_spec adis16489_channels[] = {
+ ADIS16480_GYRO_CHANNEL(X),
+ ADIS16480_GYRO_CHANNEL(Y),
+ ADIS16480_GYRO_CHANNEL(Z),
+ ADIS16480_ACCEL_CHANNEL(X),
+ ADIS16480_ACCEL_CHANNEL(Y),
+ ADIS16480_ACCEL_CHANNEL(Z),
+ ADIS16480_PRESSURE_CHANNEL(),
+ ADIS16480_TEMP_CHANNEL(),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
enum adis16480_variant {
ADIS16375,
ADIS16480,
ADIS16485,
+ ADIS16486,
+ ADIS16487,
ADIS16488,
+ ADIS16489,
ADIS16490,
ADIS16495_1,
ADIS16495_2,
@@ -844,6 +911,12 @@ enum adis16480_variant {
ADIS16497_1,
ADIS16497_2,
ADIS16497_3,
+ ADIS16545_1,
+ ADIS16545_2,
+ ADIS16545_3,
+ ADIS16547_1,
+ ADIS16547_2,
+ ADIS16547_3
};
#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
@@ -872,33 +945,33 @@ static const char * const adis16480_status_error_msgs[] = {
static int adis16480_enable_irq(struct adis *adis, bool enable);
-#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \
-{ \
- .diag_stat_reg = ADIS16480_REG_DIAG_STS, \
- .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
- .prod_id_reg = ADIS16480_REG_PROD_ID, \
- .prod_id = (_prod_id), \
- .has_paging = true, \
- .read_delay = 5, \
- .write_delay = 5, \
- .self_test_mask = BIT(1), \
- .self_test_reg = ADIS16480_REG_GLOB_CMD, \
- .status_error_msgs = adis16480_status_error_msgs, \
- .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
- .enable_irq = adis16480_enable_irq, \
- .timeouts = (_timeouts), \
- .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
- .burst_len = (_burst_len), \
- .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \
+#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len, _burst_max_speed) \
+{ \
+ .diag_stat_reg = ADIS16480_REG_DIAG_STS, \
+ .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
+ .prod_id_reg = ADIS16480_REG_PROD_ID, \
+ .prod_id = (_prod_id), \
+ .has_paging = true, \
+ .read_delay = 5, \
+ .write_delay = 5, \
+ .self_test_mask = BIT(1), \
+ .self_test_reg = ADIS16480_REG_GLOB_CMD, \
+ .status_error_msgs = adis16480_status_error_msgs, \
+ .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
+ .enable_irq = adis16480_enable_irq, \
+ .timeouts = (_timeouts), \
+ .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
+ .burst_len = (_burst_len), \
+ .burst_max_speed_hz = _burst_max_speed \
}
static const struct adis_timeout adis16485_timeouts = {
@@ -925,6 +998,12 @@ static const struct adis_timeout adis16495_1_timeouts = {
.self_test_ms = 20,
};
+static const struct adis_timeout adis16545_timeouts = {
+ .reset_ms = 315,
+ .sw_reset_ms = 270,
+ .self_test_ms = 35,
+};
+
static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
@@ -940,11 +1019,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(180),
+ .deltvel_max_val = 100,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0, 0),
},
[ADIS16480] = {
.channels = adis16480_channels,
@@ -954,11 +1035,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
.accel_max_scale = 10,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0, 0),
},
[ADIS16485] = {
.channels = adis16485_channels,
@@ -968,11 +1051,45 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 50,
+ .int_clk = 2460000,
+ .max_dec_rate = 2048,
+ .has_sleep_cnt = true,
+ .filter_freqs = adis16480_def_filter_freqs,
+ .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0),
+ },
+ [ADIS16486] = {
+ .channels = adis16485_channels,
+ .num_channels = ARRAY_SIZE(adis16485_channels),
+ .gyro_max_val = 22500 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
+ .accel_max_scale = 18,
+ .temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
+ .int_clk = 2460000,
+ .max_dec_rate = 2048,
+ .has_sleep_cnt = true,
+ .filter_freqs = adis16480_def_filter_freqs,
+ .adis_data = ADIS16480_DATA(16486, &adis16480_timeouts, 0, 0),
+ },
+ [ADIS16487] = {
+ .channels = adis16485_channels,
+ .num_channels = ARRAY_SIZE(adis16485_channels),
+ .gyro_max_val = 22500 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
+ .accel_max_scale = 5,
+ .temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 50,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16487, &adis16485_timeouts, 0, 0),
},
[ADIS16488] = {
.channels = adis16480_channels,
@@ -982,11 +1099,29 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0),
+ },
+ [ADIS16489] = {
+ .channels = adis16489_channels,
+ .num_channels = ARRAY_SIZE(adis16489_channels),
+ .gyro_max_val = 22500 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
+ .accel_max_scale = 18,
+ .temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
+ .int_clk = 2460000,
+ .max_dec_rate = 2048,
+ .has_sleep_cnt = true,
+ .filter_freqs = adis16480_def_filter_freqs,
+ .adis_data = ADIS16480_DATA(16489, &adis16480_timeouts, 0, 0),
},
[ADIS16490] = {
.channels = adis16485_channels,
@@ -996,11 +1131,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
.accel_max_scale = 8,
.temp_scale = 14285, /* 14.285 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0, 0),
},
[ADIS16495_1] = {
.channels = adis16485_channels,
@@ -1010,13 +1147,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16495_2] = {
.channels = adis16485_channels,
@@ -1026,13 +1166,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16495_3] = {
.channels = adis16485_channels,
@@ -1042,13 +1185,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_1] = {
.channels = adis16485_channels,
@@ -1058,13 +1204,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_2] = {
.channels = adis16485_channels,
@@ -1074,13 +1223,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_3] = {
.channels = adis16485_channels,
@@ -1090,13 +1242,136 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
+ },
+ [ADIS16545_1] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16545_2] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 18000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16545_3] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_1] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_2] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 18000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_3] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
},
};
@@ -1122,41 +1397,38 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
struct adis16480 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
struct device *dev = &adis->spi->dev;
- int ret, bit, offset, i = 0;
+ int ret, bit, offset, i = 0, buff_offset = 0;
__be16 *buffer;
u32 crc;
bool valid;
- adis_dev_lock(adis);
- if (adis->current_page != 0) {
- adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
- adis->tx[1] = 0;
- ret = spi_write(adis->spi, adis->tx, 2);
+ adis_dev_auto_scoped_lock(adis) {
+ if (adis->current_page != 0) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = 0;
+ ret = spi_write(adis->spi, adis->tx, 2);
+ if (ret) {
+ dev_err(dev, "Failed to change device page: %d\n", ret);
+ goto irq_done;
+ }
+
+ adis->current_page = 0;
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
- dev_err(dev, "Failed to change device page: %d\n", ret);
- adis_dev_unlock(adis);
+ dev_err(dev, "Failed to read data: %d\n", ret);
goto irq_done;
}
-
- adis->current_page = 0;
- }
-
- ret = spi_sync(adis->spi, &adis->msg);
- if (ret) {
- dev_err(dev, "Failed to read data: %d\n", ret);
- adis_dev_unlock(adis);
- goto irq_done;
}
- adis_dev_unlock(adis);
-
/*
* After making the burst request, the response can have one or two
* 16-bit responses containing the BURST_ID depending on the sclk. If
* clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
* we have only one. To manage that variation, we use the transition from the
- * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
- * we not find this variation in the first 4 segments, then the data should
+ * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5/0xC3C3.
+ * If we not find this variation in the first 4 segments, then the data should
* not be valid.
*/
buffer = adis->buffer;
@@ -1164,7 +1436,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
u16 curr = be16_to_cpu(buffer[offset]);
u16 next = be16_to_cpu(buffer[offset + 1]);
- if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
+ if (curr == st->burst_id && next != st->burst_id) {
offset++;
break;
}
@@ -1182,7 +1454,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
goto irq_done;
}
- for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+ iio_for_each_active_channel(indio_dev, bit) {
/*
* When burst mode is used, temperature is the first data
* channel in the sequence, but the temperature scan index
@@ -1191,11 +1463,24 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
switch (bit) {
case ADIS16480_SCAN_TEMP:
st->data[i++] = buffer[offset + 1];
+ /*
+ * The temperature channel has 16-bit storage size.
+ * We need to perform the padding to have the buffer
+ * elements naturally aligned in case there are any
+ * 32-bit storage size channels enabled which are added
+ * in the buffer after the temprature data. In case
+ * there is no data being added after the temperature
+ * data, the padding is harmless.
+ */
+ st->data[i++] = 0;
break;
+ case ADIS16480_SCAN_DELTANG_X ... ADIS16480_SCAN_DELTVEL_Z:
+ buff_offset = ADIS16480_SCAN_DELTANG_X;
+ fallthrough;
case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
/* The lower register data is sequenced first */
- st->data[i++] = buffer[2 * bit + offset + 3];
- st->data[i++] = buffer[2 * bit + offset + 2];
+ st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 3];
+ st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 2];
break;
}
}
@@ -1207,10 +1492,41 @@ irq_done:
return IRQ_HANDLED;
}
+static const unsigned long adis16545_channel_masks[] = {
+ ADIS16545_BURST_DATA_SEL_0_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
+ ADIS16545_BURST_DATA_SEL_1_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
+ 0,
+};
+
+static int adis16480_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ u16 en;
+ int ret;
+ struct adis16480 *st = iio_priv(indio_dev);
+
+ if (st->chip_info->has_burst_delta_data) {
+ if (*scan_mask & ADIS16545_BURST_DATA_SEL_0_CHN_MASK) {
+ en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 0);
+ st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
+ } else {
+ en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 1);
+ st->burst_id = ADIS16545_DELTA_ANG_VEL_BURST_ID;
+ }
+
+ ret = __adis_update_bits(&st->adis, ADIS16480_REG_CONFIG,
+ ADIS16545_BURST_DATA_SEL_MASK, en);
+ if (ret)
+ return ret;
+ }
+
+ return adis_update_scan_mode(indio_dev, scan_mask);
+}
+
static const struct iio_info adis16480_info = {
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
- .update_scan_mode = adis_update_scan_mode,
+ .update_scan_mode = &adis16480_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
@@ -1407,6 +1723,8 @@ static int adis16480_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
+ if (st->chip_info->has_burst_delta_data)
+ indio_dev->available_scan_masks = adis16545_channel_masks;
indio_dev->info = &adis16480_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1420,6 +1738,13 @@ static int adis16480_probe(struct spi_device *spi)
if (ret)
return ret;
+ /*
+ * By default, use burst id for gyroscope and accelerometer data.
+ * This is the only option for devices which do not offer delta angle
+ * and delta velocity burst readings.
+ */
+ st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
+
if (st->chip_info->has_sleep_cnt) {
ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev);
if (ret)
@@ -1485,7 +1810,10 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16375", ADIS16375 },
{ "adis16480", ADIS16480 },
{ "adis16485", ADIS16485 },
+ { "adis16486", ADIS16486 },
+ { "adis16487", ADIS16487 },
{ "adis16488", ADIS16488 },
+ { "adis16489", ADIS16489 },
{ "adis16490", ADIS16490 },
{ "adis16495-1", ADIS16495_1 },
{ "adis16495-2", ADIS16495_2 },
@@ -1493,6 +1821,12 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16497-1", ADIS16497_1 },
{ "adis16497-2", ADIS16497_2 },
{ "adis16497-3", ADIS16497_3 },
+ { "adis16545-1", ADIS16545_1 },
+ { "adis16545-2", ADIS16545_2 },
+ { "adis16545-3", ADIS16545_3 },
+ { "adis16547-1", ADIS16547_1 },
+ { "adis16547-2", ADIS16547_2 },
+ { "adis16547-3", ADIS16547_3 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16480_ids);
@@ -1501,7 +1835,10 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16375" },
{ .compatible = "adi,adis16480" },
{ .compatible = "adi,adis16485" },
+ { .compatible = "adi,adis16486" },
+ { .compatible = "adi,adis16487" },
{ .compatible = "adi,adis16488" },
+ { .compatible = "adi,adis16489" },
{ .compatible = "adi,adis16490" },
{ .compatible = "adi,adis16495-1" },
{ .compatible = "adi,adis16495-2" },
@@ -1509,7 +1846,13 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16497-1" },
{ .compatible = "adi,adis16497-2" },
{ .compatible = "adi,adis16497-3" },
- { },
+ { .compatible = "adi,adis16545-1" },
+ { .compatible = "adi,adis16545-2" },
+ { .compatible = "adi,adis16545-3" },
+ { .compatible = "adi,adis16547-1" },
+ { .compatible = "adi,adis16547-2" },
+ { .compatible = "adi,adis16547-3" },
+ { }
};
MODULE_DEVICE_TABLE(of, adis16480_of_match);
@@ -1526,4 +1869,4 @@ module_spi_driver(adis16480_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_ADISLIB);
+MODULE_IMPORT_NS("IIO_ADISLIB");