diff options
Diffstat (limited to 'drivers/iio/imu/adis16480.c')
-rw-r--r-- | drivers/iio/imu/adis16480.c | 562 |
1 files changed, 449 insertions, 113 deletions
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index fe520194a837..727e0a11eac1 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, }; @@ -1246,18 +1562,11 @@ static int adis16480_config_irq_pin(struct adis16480 *st) { struct device *dev = &st->adis.spi->dev; struct fwnode_handle *fwnode = dev_fwnode(dev); - struct irq_data *desc; enum adis16480_int_pin pin; unsigned int irq_type; uint16_t val; int i, irq = 0; - desc = irq_get_irq_data(st->adis.spi->irq); - if (!desc) { - dev_err(dev, "Could not find IRQ %d\n", irq); - return -EINVAL; - } - /* Disable data ready since the default after reset is on */ val = ADIS16480_DRDY_EN(0); @@ -1285,7 +1594,7 @@ static int adis16480_config_irq_pin(struct adis16480 *st) * configured as positive or negative, corresponding to * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. */ - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(st->adis.spi->irq); if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ val |= ADIS16480_DRDY_POL(1); } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { @@ -1414,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; @@ -1427,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) @@ -1492,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 }, @@ -1500,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); @@ -1508,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" }, @@ -1516,6 +1846,12 @@ 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); @@ -1533,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"); |