diff mbox series

[v2,8/8] drivers: iio: imu: Add support for adis1657x family

Message ID 20240508131310.880479-9-ramona.bolboaca13@gmail.com (mailing list archive)
State Changes Requested
Headers show
Series adis16501 and adis1657x support | expand

Commit Message

Ramona Gradinariu May 8, 2024, 1:13 p.m. UTC
Add support for ADIS1657X family devices in already exiting ADIS16475
driver.

Signed-off-by: Ramona Gradinariu <ramona.bolboaca13@gmail.com>
---
changes in v2:
 - various fields renaming
 - added inline value setting instead of using extra variable
 - use min_t function instead of if condition followed by assignment
 - added new chip info structure for devices which support fifo
 - rewrote the !! operations to increase readability
 - added missing entries for adis1657x devices in adis16475_ids
 drivers/iio/imu/adis16475.c | 552 +++++++++++++++++++++++++++++++++---
 1 file changed, 510 insertions(+), 42 deletions(-)

--
2.34.1

Comments

kernel test robot May 10, 2024, 11:24 p.m. UTC | #1
Hi Ramona,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[cannot apply to linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ramona-Gradinariu/dt-bindings-iio-imu-Add-ADIS16501-compatibles/20240508-211559
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/20240508131310.880479-9-ramona.bolboaca13%40gmail.com
patch subject: [PATCH v2 8/8] drivers: iio: imu: Add support for adis1657x family
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20240511/202405110735.khNaHnAJ-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240511/202405110735.khNaHnAJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405110735.khNaHnAJ-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/iio/imu/adis16475.c:16:
   include/linux/iio/imu/adis.h:530:60: warning: 'struct iio_dev_attr' declared inside parameter list will not be visible outside of this definition or declaration
     530 |                                               const struct iio_dev_attr **buffer_attrs);
         |                                                            ^~~~~~~~~~~~
   drivers/iio/imu/adis16475.c: In function 'adis16475_probe':
>> drivers/iio/imu/adis16475.c:1959:69: error: passing argument 5 of 'devm_adis_setup_buffer_and_trigger_with_attrs' from incompatible pointer type [-Werror=incompatible-pointer-types]
    1959 |                                                                     adis16475_fifo_attributes);
         |                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~
         |                                                                     |
         |                                                                     const struct attribute **
   include/linux/iio/imu/adis.h:530:75: note: expected 'const struct iio_dev_attr **' but argument is of type 'const struct attribute **'
     530 |                                               const struct iio_dev_attr **buffer_attrs);
         |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/devm_adis_setup_buffer_and_trigger_with_attrs +1959 drivers/iio/imu/adis16475.c

  1912	
  1913	
  1914	static int adis16475_probe(struct spi_device *spi)
  1915	{
  1916		struct iio_dev *indio_dev;
  1917		struct adis16475 *st;
  1918		int ret;
  1919	
  1920		indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
  1921		if (!indio_dev)
  1922			return -ENOMEM;
  1923	
  1924		st = iio_priv(indio_dev);
  1925	
  1926		st->info = spi_get_device_match_data(spi);
  1927		if (!st->info)
  1928			return -EINVAL;
  1929	
  1930		ret = adis_init(&st->adis, indio_dev, spi, &st->info->adis_data);
  1931		if (ret)
  1932			return ret;
  1933	
  1934		indio_dev->name = st->info->name;
  1935		indio_dev->channels = st->info->channels;
  1936		indio_dev->num_channels = st->info->num_channels;
  1937		if (st->info->flags & ADIS16475_HAS_FIFO)
  1938			indio_dev->info = &adis16575_info;
  1939		else
  1940			indio_dev->info = &adis16475_info;
  1941		indio_dev->modes = INDIO_DIRECT_MODE;
  1942	
  1943		ret = __adis_initial_startup(&st->adis);
  1944		if (ret)
  1945			return ret;
  1946	
  1947		ret = adis16475_config_irq_pin(st);
  1948		if (ret)
  1949			return ret;
  1950	
  1951		ret = adis16475_config_sync_mode(st);
  1952		if (ret)
  1953			return ret;
  1954	
  1955		if (st->info->flags & ADIS16475_HAS_FIFO) {
  1956			ret = devm_adis_setup_buffer_and_trigger_with_attrs(&st->adis, indio_dev,
  1957									    adis16475_trigger_handler_with_fifo,
  1958									    &adis16475_buffer_ops,
> 1959									    adis16475_fifo_attributes);
  1960			if (ret)
  1961				return ret;
  1962			/* Update overflow behavior to always overwrite the oldest sample. */
  1963			ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
  1964					       ADIS16575_OVERFLOW_MASK, (u16)ADIS16575_OVERWRITE_OLDEST);
  1965		} else {
  1966			ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
  1967								 adis16475_trigger_handler);
  1968		}
  1969		if (ret)
  1970			return ret;
  1971	
  1972		ret = devm_iio_device_register(&spi->dev, indio_dev);
  1973		if (ret)
  1974			return ret;
  1975	
  1976		adis16475_debugfs_init(indio_dev);
  1977	
  1978		return 0;
  1979	}
  1980
Jonathan Cameron May 11, 2024, 1:24 p.m. UTC | #2
On Sat, 11 May 2024 07:24:05 +0800
kernel test robot <lkp@intel.com> wrote:

> Hi Ramona,
> 
> kernel test robot noticed the following build errors:
> 
> [auto build test ERROR on jic23-iio/togreg]
> [cannot apply to linus/master v6.9-rc7 next-20240510]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Ramona-Gradinariu/dt-bindings-iio-imu-Add-ADIS16501-compatibles/20240508-211559
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
> patch link:    https://lore.kernel.org/r/20240508131310.880479-9-ramona.bolboaca13%40gmail.com
> patch subject: [PATCH v2 8/8] drivers: iio: imu: Add support for adis1657x family
> config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20240511/202405110735.khNaHnAJ-lkp@intel.com/config)
> compiler: m68k-linux-gcc (GCC) 13.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240511/202405110735.khNaHnAJ-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202405110735.khNaHnAJ-lkp@intel.com/
> 
> All errors (new ones prefixed by >>):
> 
>    In file included from drivers/iio/imu/adis16475.c:16:
>    include/linux/iio/imu/adis.h:530:60: warning: 'struct iio_dev_attr' declared inside parameter list will not be visible outside of this definition or declaration
>      530 |                                               const struct iio_dev_attr **buffer_attrs);
>          |                                                            ^~~~~~~~~~~~
>    drivers/iio/imu/adis16475.c: In function 'adis16475_probe':
> >> drivers/iio/imu/adis16475.c:1959:69: error: passing argument 5 of 'devm_adis_setup_buffer_and_trigger_with_attrs' from incompatible pointer type [-Werror=incompatible-pointer-types]  
>     1959 |                                                                     adis16475_fifo_attributes);
>          |                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~
>          |                                                                     |
>          |                                                                     const struct attribute **
>    include/linux/iio/imu/adis.h:530:75: note: expected 'const struct iio_dev_attr **' but argument is of type 'const struct attribute **'
>      530 |                                               const struct iio_dev_attr **buffer_attrs);
>          |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
>    cc1: some warnings being treated as errors
> 
> 
This does need to include linux/iio/sysfs.h

> vim +/devm_adis_setup_buffer_and_trigger_with_attrs +1959 drivers/iio/imu/adis16475.c
> 
>   1912	
>   1913	
>   1914	static int adis16475_probe(struct spi_device *spi)
>   1915	{
>   1916		struct iio_dev *indio_dev;
>   1917		struct adis16475 *st;
>   1918		int ret;
>   1919	
>   1920		indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
>   1921		if (!indio_dev)
>   1922			return -ENOMEM;
>   1923	
>   1924		st = iio_priv(indio_dev);
>   1925	
>   1926		st->info = spi_get_device_match_data(spi);
>   1927		if (!st->info)
>   1928			return -EINVAL;
>   1929	
>   1930		ret = adis_init(&st->adis, indio_dev, spi, &st->info->adis_data);
>   1931		if (ret)
>   1932			return ret;
>   1933	
>   1934		indio_dev->name = st->info->name;
>   1935		indio_dev->channels = st->info->channels;
>   1936		indio_dev->num_channels = st->info->num_channels;
>   1937		if (st->info->flags & ADIS16475_HAS_FIFO)
>   1938			indio_dev->info = &adis16575_info;
>   1939		else
>   1940			indio_dev->info = &adis16475_info;
>   1941		indio_dev->modes = INDIO_DIRECT_MODE;
>   1942	
>   1943		ret = __adis_initial_startup(&st->adis);
>   1944		if (ret)
>   1945			return ret;
>   1946	
>   1947		ret = adis16475_config_irq_pin(st);
>   1948		if (ret)
>   1949			return ret;
>   1950	
>   1951		ret = adis16475_config_sync_mode(st);
>   1952		if (ret)
>   1953			return ret;
>   1954	
>   1955		if (st->info->flags & ADIS16475_HAS_FIFO) {
>   1956			ret = devm_adis_setup_buffer_and_trigger_with_attrs(&st->adis, indio_dev,
>   1957									    adis16475_trigger_handler_with_fifo,
>   1958									    &adis16475_buffer_ops,
> > 1959									    adis16475_fifo_attributes);  
>   1960			if (ret)
>   1961				return ret;
>   1962			/* Update overflow behavior to always overwrite the oldest sample. */
>   1963			ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
>   1964					       ADIS16575_OVERFLOW_MASK, (u16)ADIS16575_OVERWRITE_OLDEST);
>   1965		} else {
>   1966			ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
>   1967								 adis16475_trigger_handler);
>   1968		}
>   1969		if (ret)
>   1970			return ret;
>   1971	
>   1972		ret = devm_iio_device_register(&spi->dev, indio_dev);
>   1973		if (ret)
>   1974			return ret;
>   1975	
>   1976		adis16475_debugfs_init(indio_dev);
>   1977	
>   1978		return 0;
>   1979	}
>   1980	
>
Jonathan Cameron May 11, 2024, 1:54 p.m. UTC | #3
On Wed,  8 May 2024 16:13:10 +0300
Ramona Gradinariu <ramona.bolboaca13@gmail.com> wrote:

> Add support for ADIS1657X family devices in already exiting ADIS16475
> driver.
> 
> Signed-off-by: Ramona Gradinariu <ramona.bolboaca13@gmail.com>
Hi Ramona

A few things in here that I put in the v1 review that I did earlier today
(so way after you sent this out!) Please check that though as I may
not have repeated all comments.

Also, a question on races.

Jonathan

> ---
> changes in v2:
>  - various fields renaming
>  - added inline value setting instead of using extra variable
>  - use min_t function instead of if condition followed by assignment
>  - added new chip info structure for devices which support fifo
>  - rewrote the !! operations to increase readability
>  - added missing entries for adis1657x devices in adis16475_ids
>  drivers/iio/imu/adis16475.c | 552 +++++++++++++++++++++++++++++++++---
>  1 file changed, 510 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
> index c589f214259b..706ae2611b8f 100644
> --- a/drivers/iio/imu/adis16475.c
> +++ b/drivers/iio/imu/adis16475.c
> @@ -14,6 +14,7 @@
>  #include <linux/iio/buffer.h>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/imu/adis.h>
> +#include <linux/iio/sysfs.h>
>  #include <linux/iio/trigger_consumer.h>
>  #include <linux/irq.h>
>  #include <linux/lcm.h>
> @@ -52,6 +53,8 @@
>  				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x)
>  #define ADIS16475_SYNC_MODE_MASK	GENMASK(4, 2)
>  #define ADIS16475_SYNC_MODE(x)		FIELD_PREP(ADIS16475_SYNC_MODE_MASK, x)
> +#define ADIS16575_SYNC_4KHZ_MASK	BIT(11)
> +#define ADIS16575_SYNC_4KHZ(x)		FIELD_PREP(ADIS16575_SYNC_4KHZ_MASK, x)
>  #define ADIS16475_REG_UP_SCALE		0x62
>  #define ADIS16475_REG_DEC_RATE		0x64
>  #define ADIS16475_REG_GLOB_CMD		0x68
> @@ -65,15 +68,32 @@
>  #define ADIS16500_BURST32_MASK		BIT(9)
>  #define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BURST32_MASK, x)
>  /* number of data elements in burst mode */
> -#define ADIS16475_BURST32_MAX_DATA	32
> +#define ADIS16475_BURST32_MAX_DATA_NO_TS32	32
> +#define ADIS16575_BURST32_DATA_TS32		34
>  #define ADIS16475_BURST_MAX_DATA	20
>  #define ADIS16475_MAX_SCAN_DATA		20
>  /* spi max speed in brust mode */
>  #define ADIS16475_BURST_MAX_SPEED	1000000
> +#define ADIS16575_BURST_MAX_SPEED	8000000
>  #define ADIS16475_LSB_DEC_MASK		0
>  #define ADIS16475_LSB_FIR_MASK		1
>  #define ADIS16500_BURST_DATA_SEL_0_CHN_MASK	GENMASK(5, 0)
>  #define ADIS16500_BURST_DATA_SEL_1_CHN_MASK	GENMASK(12, 7)
> +#define ADIS16575_MAX_FIFO_WM		511
> +#define ADIS16475_REG_FIFO_CTRL		0x5A
> +#define ADIS16575_WM_LVL_MASK		GENMASK(15, 4)
> +#define ADIS16575_WM_LVL(x)		FIELD_PREP(ADIS16575_WM_LVL_MASK, x)
> +#define ADIS16575_WM_POL_MASK		BIT(3)
> +#define ADIS16575_WM_POL(x)		FIELD_PREP(ADIS16575_WM_POL_MASK, x)
> +#define ADIS16575_WM_EN_MASK		BIT(2)
> +#define ADIS16575_WM_EN(x)		FIELD_PREP(ADIS16575_WM_EN_MASK, x)
> +#define ADIS16575_OVERFLOW_MASK		BIT(1)
> +#define ADIS16575_STOP_ENQUEUE		FIELD_PREP(ADIS16575_OVERFLOW_MASK, 0)
> +#define ADIS16575_OVERWRITE_OLDEST	FIELD_PREP(ADIS16575_OVERFLOW_MASK, 1)
> +#define ADIS16575_FIFO_EN_MASK		BIT(0)
> +#define ADIS16575_FIFO_EN(x)		FIELD_PREP(ADIS16575_FIFO_EN_MASK, x)
> +#define ADIS16575_FIFO_FLUSH_CMD	BIT(5)
> +#define ADIS16575_REG_FIFO_CNT		0x3C
> 
>  enum {
>  	ADIS16475_SYNC_DIRECT = 1,
> @@ -95,6 +115,9 @@ struct adis16475_chip_info {
>  	const char *name;
>  #define ADIS16475_HAS_BURST32		BIT(0)
>  #define ADIS16475_HAS_BURST_DELTA_DATA	BIT(1)
> +#define ADIS16475_HAS_TIMESTAMP32	BIT(2)
> +#define ADIS16475_NEEDS_BURST_REQUEST	BIT(3)
> +#define ADIS16475_HAS_FIFO		BIT(4)
>  	const long flags;
>  	u32 num_channels;
>  	u32 gyro_max_val;
> @@ -116,6 +139,7 @@ struct adis16475 {
>  	bool burst32;
>  	unsigned long lsb_flag;
>  	u16 sync_mode;
> +	u16 fifo_watermark;
>  	/* Alignment needed for the timestamp */
>  	__be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8);
>  };
> @@ -442,6 +466,124 @@ static int adis16475_set_filter(struct adis16475 *st, const u32 filter)
>  	return 0;
>  }
> 
> +static ssize_t adis16475_get_fifo_enabled(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	int ret;
> +	u16 val;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%d\n", (u16)FIELD_GET(ADIS16575_FIFO_EN_MASK, val));

Change the format to %lu an drop the cast.

> +}
> +
> +static ssize_t adis16475_get_fifo_watermark(struct device *dev,
> +					    struct device_attribute *attr,
> +					    char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	int ret;
> +	u16 val;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%d\n", (u16)FIELD_GET(ADIS16575_WM_LVL_MASK, val) + 1);
As above.

> +}
> +
> +static ssize_t hwfifo_watermark_min_show(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	return sysfs_emit(buf, "%s\n", "1");
	return sysfs_emit(buf, "1\n");
or
	return sysfs_emit(buf, "%u\n", 1);

> +}
> +
> +static ssize_t hwfifo_watermark_max_show(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	return sysfs_emit(buf, "%s\n", __stringify(ADIS16575_MAX_FIFO_WM));

Why use macro when you can just use %ul?

> +}
> +
> +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
> +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
> +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
> +		       adis16475_get_fifo_watermark, NULL, 0);
> +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
> +		       adis16475_get_fifo_enabled, NULL, 0);
> +
> +static const struct attribute *adis16475_fifo_attributes[] = {
> +	&iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
> +	&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
> +	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
> +	&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
> +	NULL
> +};
> +
> +static int adis16475_buffer_postenable(struct iio_dev *indio_dev)
> +{
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	struct adis *adis = &st->adis;
> +
> +	return adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
> +				ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(1));
> +}
> +
> +static int adis16475_buffer_postdisable(struct iio_dev *indio_dev)
> +{
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	struct adis *adis = &st->adis;
> +	int ret;
> +
> +	adis_dev_lock(&st->adis);
> +
> +	ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
> +				 ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0));
> +	if (ret)
> +		goto unlock;
> +
> +	ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
> +				  ADIS16575_FIFO_FLUSH_CMD);
> +
> +unlock:
> +	adis_dev_unlock(&st->adis);
> +	return ret;
> +}
> +
> +static const struct iio_buffer_setup_ops adis16475_buffer_ops = {
> +	.postenable = adis16475_buffer_postenable,
> +	.postdisable = adis16475_buffer_postdisable,
> +};
> +
> +static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val)
> +{
> +	struct adis16475 *st  = iio_priv(indio_dev);
> +	int ret;
> +	u16 wm_lvl;
> +
> +	adis_dev_lock(&st->adis);
> +
> +	val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM);
> +
> +	wm_lvl = ADIS16575_WM_LVL(val - 1);
> +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl);
> +	if (ret)
> +		goto unlock;
> +
> +	st->fifo_watermark = val;
> +
> +unlock:
> +	adis_dev_unlock(&st->adis);
> +	return ret;
> +}
> +
>  static const u32 adis16475_calib_regs[] = {
>  	[ADIS16475_SCAN_GYRO_X] = ADIS16475_REG_X_GYRO_BIAS_L,
>  	[ADIS16475_SCAN_GYRO_Y] = ADIS16475_REG_Y_GYRO_BIAS_L,
> @@ -673,6 +815,12 @@ enum adis16475_variant {
>  	ADIS16507_1,
>  	ADIS16507_2,
>  	ADIS16507_3,
> +	ADIS16575_2,
> +	ADIS16575_3,
> +	ADIS16576_2,
> +	ADIS16576_3,
> +	ADIS16577_2,
> +	ADIS16577_3,
>  };
> 
>  enum {
> @@ -730,6 +878,12 @@ static const struct adis16475_sync adis16475_sync_mode[] = {
>  	{ ADIS16475_SYNC_PULSE, 1000, 2100 },
>  };
> 
> +static const struct adis16475_sync adis16575_sync_mode[] = {
> +	{ ADIS16475_SYNC_OUTPUT },
> +	{ ADIS16475_SYNC_DIRECT, 1900, 4100 },
> +	{ ADIS16475_SYNC_SCALED, 1, 400 },
> +};
> +
>  static const struct adis_timeout adis16475_timeouts = {
>  	.reset_ms = 200,
>  	.sw_reset_ms = 200,
> @@ -759,7 +913,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16470, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16475_1] = {
> @@ -778,7 +932,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16475_2] = {
> @@ -797,7 +951,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16475_3] = {
> @@ -816,7 +970,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16477_1] = {
> @@ -836,7 +990,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16477_2] = {
> @@ -856,7 +1010,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16477_3] = {
> @@ -876,7 +1030,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16465_1] = {
> @@ -895,7 +1049,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16465_2] = {
> @@ -914,7 +1068,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16465_3] = {
> @@ -933,7 +1087,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16467_1] = {
> @@ -952,7 +1106,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16467_2] = {
> @@ -971,7 +1125,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16467_3] = {
> @@ -990,7 +1144,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.sync = adis16475_sync_mode,
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
>  		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16500] = {
> @@ -1011,7 +1165,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16501] = {
> @@ -1032,7 +1186,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16505_1] = {
> @@ -1053,7 +1207,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16505_2] = {
> @@ -1074,7 +1228,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16505_3] = {
> @@ -1095,7 +1249,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16507_1] = {
> @@ -1116,7 +1270,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16507_2] = {
> @@ -1137,7 +1291,7 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
>  	[ADIS16507_3] = {
> @@ -1158,9 +1312,153 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
>  		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
>  		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
>  		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
> -					    ADIS16475_BURST32_MAX_DATA,
> +					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
>  					    ADIS16475_BURST_MAX_SPEED),
>  	},
> +	[ADIS16575_2] = {
> +		.name = "adis16575-2",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 8,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
> +		.deltvel_max_val = 100,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
> +	[ADIS16575_3] = {
> +		.name = "adis16575-3",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 8,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
> +		.deltvel_max_val = 100,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
> +	[ADIS16576_2] = {
> +		.name = "adis16576-2",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 40,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
> +		.deltvel_max_val = 125,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
> +	[ADIS16576_3] = {
> +		.name = "adis16576-3",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 40,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
> +		.deltvel_max_val = 125,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
> +	[ADIS16577_2] = {
> +		.name = "adis16577-2",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 40,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
> +		.deltvel_max_val = 400,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
> +	[ADIS16577_3] = {
> +		.name = "adis16577-3",
> +		.num_channels = ARRAY_SIZE(adis16477_channels),
> +		.channels = adis16477_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 40,
> +		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
> +		.temp_scale = 100,
> +		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
> +		.deltvel_max_val = 400,
> +		.int_clk = 4000,
> +		.max_dec = 3999,
> +		.sync = adis16575_sync_mode,
> +		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
> +		.flags = ADIS16475_HAS_BURST32 |
> +			 ADIS16475_HAS_BURST_DELTA_DATA |
> +			 ADIS16475_NEEDS_BURST_REQUEST |
> +			 ADIS16475_HAS_TIMESTAMP32 |
> +			 ADIS16475_HAS_FIFO,
> +		.adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
> +					    ADIS16575_BURST32_DATA_TS32,
> +					    ADIS16575_BURST_MAX_SPEED),
> +	},
>  };
> 
>  static int adis16475_update_scan_mode(struct iio_dev *indio_dev,
> @@ -1195,15 +1493,19 @@ static const struct iio_info adis16475_info = {
>  	.debugfs_reg_access = adis_debugfs_reg_access,
>  };
> 
> +static const struct iio_info adis16575_info = {
> +	.read_raw = &adis16475_read_raw,
> +	.write_raw = &adis16475_write_raw,
> +	.update_scan_mode = adis16475_update_scan_mode,
> +	.debugfs_reg_access = adis_debugfs_reg_access,
> +	.hwfifo_set_watermark = adis16475_set_watermark,
> +};
> +
>  static bool adis16475_validate_crc(const u8 *buffer, u16 crc,
> -				   const bool burst32)
> +				   u16 burst_size, u16 start_idx)
>  {
>  	int i;
> -	/* extra 6 elements for low gyro and accel */
> -	const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA :
> -		ADIS16475_BURST_MAX_DATA;
> -
> -	for (i = 0; i < sz - 2; i++)
> +	for (i = start_idx; i < burst_size - 2; i++)
>  		crc -= buffer[i];
> 
>  	return crc == 0;
> @@ -1213,10 +1515,14 @@ static void adis16475_burst32_check(struct adis16475 *st)
>  {
>  	int ret;
>  	struct adis *adis = &st->adis;
> +	u8 timestamp32 = 0;
> 
>  	if (!(st->info->flags & ADIS16475_HAS_BURST32))
>  		return;
> 
> +	if (st->info->flags & ADIS16475_HAS_TIMESTAMP32)
> +		timestamp32 = 1;
> +
>  	if (st->lsb_flag && !st->burst32) {
>  		const u16 en = ADIS16500_BURST32(1);
> 
> @@ -1230,9 +1536,12 @@ static void adis16475_burst32_check(struct adis16475 *st)
>  		/*
>  		 * In 32-bit mode we need extra 2 bytes for all gyro
>  		 * and accel channels.
> +		 * If the device has 32-bit timestamp value we need 2 extra
> +		 * bytes for it.
>  		 */
> -		adis->burst_extra_len = 6 * sizeof(u16);
> -		adis->xfer[1].len += 6 * sizeof(u16);
> +		adis->burst_extra_len = (6 + timestamp32) * sizeof(u16);
> +		adis->xfer[1].len += (6 + timestamp32) * sizeof(u16);
> +
>  		dev_dbg(&adis->spi->dev, "Enable burst32 mode, xfer:%d",
>  			adis->xfer[1].len);
> 
> @@ -1248,7 +1557,7 @@ static void adis16475_burst32_check(struct adis16475 *st)
> 
>  		/* Remove the extra bits */
>  		adis->burst_extra_len = 0;
> -		adis->xfer[1].len -= 6 * sizeof(u16);
> +		adis->xfer[1].len -= (6 + timestamp32) * sizeof(u16);
>  		dev_dbg(&adis->spi->dev, "Disable burst32 mode, xfer:%d\n",
>  			adis->xfer[1].len);
>  	}
> @@ -1263,20 +1572,30 @@ static int adis16475_push_single_sample(struct iio_poll_func *pf)
>  	__be16 *buffer;
>  	u16 crc;
>  	bool valid;
> +	u8 crc_offset = 9;
> +	u16 burst_size = ADIS16475_BURST_MAX_DATA;
> +	u16 start_idx = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 2 : 0;
> +
>  	/* offset until the first element after gyro and accel */
>  	const u8 offset = st->burst32 ? 13 : 7;
> 
> +	if (st->burst32) {
> +		crc_offset = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 16 : 15;
> +		burst_size = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ?
> +			     ADIS16575_BURST32_DATA_TS32 : ADIS16475_BURST32_MAX_DATA_NO_TS32;
> +	}
> +
>  	ret = spi_sync(adis->spi, &adis->msg);
>  	if (ret)
> -		goto check_burst32;
> +		return ret;
> 
>  	buffer = adis->buffer;
> 
> -	crc = be16_to_cpu(buffer[offset + 2]);
> -	valid = adis16475_validate_crc(adis->buffer, crc, st->burst32);
> +	crc = be16_to_cpu(buffer[crc_offset]);
> +	valid = adis16475_validate_crc(adis->buffer, crc, burst_size, start_idx);
>  	if (!valid) {
>  		dev_err(&adis->spi->dev, "Invalid crc\n");
> -		goto check_burst32;
> +		return ret;
>  	}
> 
>  	for_each_set_bit(bit, indio_dev->active_scan_mask,
> @@ -1337,22 +1656,113 @@ static int adis16475_push_single_sample(struct iio_poll_func *pf)
>  	}
> 
>  	iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
> -check_burst32:
> +
> +	return 0;
> +}
> +
> +static irqreturn_t adis16475_trigger_handler(int irq, void *p)
> +{
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct adis16475 *st = iio_priv(indio_dev);
> +
> +	adis16475_push_single_sample(pf);
>  	/*
>  	 * We only check the burst mode at the end of the current capture since
>  	 * it takes a full data ready cycle for the device to update the burst
>  	 * array.
>  	 */
>  	adis16475_burst32_check(st);
> -	return ret;
> +
> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
>  }
> 
> -static irqreturn_t adis16475_trigger_handler(int irq, void *p)
> +static int adis16575_custom_burst_read(struct iio_poll_func *pf, u8 burst_req)
> +{
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	struct adis *adis = &st->adis;
> +	unsigned int burst_max_length;
> +	u8 *tx;
> +
> +	if (adis->data->burst_max_len)
> +		burst_max_length = adis->data->burst_max_len;
> +	else
> +		burst_max_length = adis->data->burst_len + adis->burst_extra_len;
> +
> +	tx = adis->buffer + burst_max_length;
> +	tx[0] = ADIS_READ_REG(burst_req);
As in v1 discussion, I'd like it to be more apparent that this
modification affects both cases. Perhaps wrap it up in a function call
adis16475_update_msg_for_burst()
or something like that.

> +
> +	if (burst_req)
> +		return spi_sync(adis->spi, &adis->msg);
> +
> +	return adis16475_push_single_sample(pf);
> +}
> +
> +/*
> + * This handler is meant to be used for devices which support burst readings
> + * from FIFO (namely devices from adis1657x family).
> + * In order to pop the FIFO the 0x68 0x00 FIFO pop burst request has to be sent.
> + * If the previous device command was not a FIFO pop burst request, the FIFO pop
> + * burst request will simply pop the FIFO without returning valid data.
> + * For the nth consecutive burst request, the

tidy up the line warping to be consistent.

> + * device will send the data popped with the (n-1)th consecutive burst request.
> + * In order to read the data which was popped previously, without popping the FIFO,
> + * the 0x00 0x00 burst request has to be sent.
> + * If after a 0x68 0x00 FIFO pop burst request, there is any other device access
> + * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped
> + * previously will be lost.
> + */
> +static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
>  {
>  	struct iio_poll_func *pf = p;
>  	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	struct adis *adis = &st->adis;
> +	int ret;
> +	u16 fifo_cnt, i;
> 
> -	adis16475_push_single_sample(pf);
> +	adis_dev_lock(&st->adis);
> +
> +	ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
> +	if (ret)
> +		goto unlock;
> +
> +	/*
> +	 * If no sample is available, nothing can be read. This can happen if
> +	 * a the used trigger has a higher frequency than the selected sample rate.
> +	 */
> +	if (!fifo_cnt)
> +		goto unlock;
> +
> +	/*
> +	 * First burst request - FIFO pop: popped data will be returned in the
> +	 * next burst request.
> +	 */
> +	ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd);
> +	if (ret)
> +		goto unlock;
> +
> +	for (i = 0; i < fifo_cnt - 1; i++) {
> +		ret = adis16475_push_single_sample(pf);
> +		if (ret)
> +			goto unlock;
> +	}
> +
My paranoid instincts for potential race conditions kick in.
Is this one of those annoying devices where the fifo interrupt will only occur
again if we successfully read enough data to get below the threshold?
Snag with no public datasheet is I can't just look it up!
If it's a level interrupt this won't be a problem.

If so the race is the following.
1. Interrupt happens, we read the number of entries in fifo.
2. We read out the fifo, but for some reason our read is slow... (contention on
   bus, CPU overheating, who knows).  The data fills up at roughly the
   same rate as we are reading.
3. We try to carry on but in reality the fifo contents never dropped below
   the watermark, so not more interrupts ever occur.

Solution normally is to put this read sequence in a while (fifo_cnt)
and reread that after you've done the burst read.  If there is more data
go around again.  That way we drive for definitely having gotten to zero
at some stage - and hence whatever the threshold is set to a new interrupt
will occur.

> +	/* FIFO read without popping */watermark
> +	ret = adis16575_custom_burst_read(pf, 0);
> +	if (ret)
> +		goto unlock;
> +
> +unlock:
> +	/*
> +	 * We only check the burst mode at the end of the current capture since
> +	 * reading data from registers will impact the FIFO reading.
> +	 */
> +	adis16475_burst32_check(st);
> +	adis_dev_unlock(&st->adis);
>  	iio_trigger_notify_done(indio_dev->trig);
> 
>  	return IRQ_HANDLED;
> @@ -1366,6 +1776,14 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
>  	u32 sync_mode;
>  	u16 max_sample_rate = st->info->int_clk + 100;
> 
> +	/* if available, enable 4khz internal clock */
> +	if (st->info->int_clk == 4000) {
> +		ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> +					 ADIS16575_SYNC_4KHZ_MASK, (u16)ADIS16575_SYNC_4KHZ(1));
> +		if (ret)
> +			return ret;
> +	}
> +
>  	/* default to internal clk */
>  	st->clk_freq = st->info->int_clk * 1000;
> 
> @@ -1472,6 +1890,23 @@ static int adis16475_config_irq_pin(struct adis16475 *st)
>  	 */
>  	usleep_range(250, 260);
> 
> +	/*
> +	 * If the device has FIFO support, configure the watermark polarity
> +	 * pin as well.
Should I think be
	configure the watermark pin polarity as well.
or
	configure the watermark pin polarity.

a "polarity pin" would be a special pin that controls the polarity that we are
configuring in some way rather than intention of configuring the polarity of
the watermark pin.

An fiddly example of English word order changing meaning :(

Rest of series looks good to me other than the minor build fixes.

Jonathan

> +	 */
> +	if (st->info->flags & ADIS16475_HAS_FIFO) {
> +		ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
> +				       ADIS16575_WM_POL_MASK, (u16)ADIS16575_WM_POL(polarity));
> +		if (ret)
> +			return ret;
> +
> +		/* Enable watermark interrupt pin. */
> +		ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
> +				       ADIS16575_WM_EN_MASK, (u16)ADIS16575_WM_EN(1));
> +		if (ret)
> +			return ret;
> +	}
> +
>  	return 0;
>  }
Ramona Gradinariu May 17, 2024, 8 a.m. UTC | #4
>> + * device will send the data popped with the (n-1)th consecutive burst request.
>> + * In order to read the data which was popped previously, without popping the FIFO,
>> + * the 0x00 0x00 burst request has to be sent.
>> + * If after a 0x68 0x00 FIFO pop burst request, there is any other device access
>> + * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped
>> + * previously will be lost.
>> + */
>> +static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
>>  {
>>  	struct iio_poll_func *pf = p;
>>  	struct iio_dev *indio_dev = pf->indio_dev;
>> +	struct adis16475 *st = iio_priv(indio_dev);
>> +	struct adis *adis = &st->adis;
>> +	int ret;
>> +	u16 fifo_cnt, i;
>>
>> -	adis16475_push_single_sample(pf);
>> +	adis_dev_lock(&st->adis);
>> +
>> +	ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
>> +	if (ret)
>> +		goto unlock;
>> +
>> +	/*
>> +	 * If no sample is available, nothing can be read. This can happen if
>> +	 * a the used trigger has a higher frequency than the selected sample rate.
>> +	 */
>> +	if (!fifo_cnt)
>> +		goto unlock;
>> +
>> +	/*
>> +	 * First burst request - FIFO pop: popped data will be returned in the
>> +	 * next burst request.
>> +	 */
>> +	ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd);
>> +	if (ret)
>> +		goto unlock;
>> +
>> +	for (i = 0; i < fifo_cnt - 1; i++) {
>> +		ret = adis16475_push_single_sample(pf);
>> +		if (ret)
>> +			goto unlock;
>> +	}
>> +
> My paranoid instincts for potential race conditions kick in.
> Is this one of those annoying devices where the fifo interrupt will only occur
> again if we successfully read enough data to get below the threshold?
> Snag with no public datasheet is I can't just look it up!
> If it's a level interrupt this won't be a problem.
>
> If so the race is the following.
> 1. Interrupt happens, we read the number of entries in fifo.
> 2. We read out the fifo, but for some reason our read is slow... (contention on
>    bus, CPU overheating, who knows).  The data fills up at roughly the
>    same rate as we are reading.
> 3. We try to carry on but in reality the fifo contents never dropped below
>    the watermark, so not more interrupts ever occur.
>
> Solution normally is to put this read sequence in a while (fifo_cnt)
> and reread that after you've done the burst read.  If there is more data
> go around again.  That way we drive for definitely having gotten to zero
> at some stage - and hence whatever the threshold is set to a new interrupt
> will occur.

Hello Jonathan,

Indeed the watermark interrupt is a level interrupt. However adis lib does not 
allow for level interrupts, so I had to create a new patch in v3 to handle it.
Until now I tested the watermark interrupt as and edge interrupt and I did not
see any issues, but indeed if the FIFO is not read fast enough the watermark pin 
will stay high (or low depending on the configured polarity), so the correct 
implementation is to use level interrupts for FIFO watermark interrupts.

Ramona G.
Jonathan Cameron May 19, 2024, 5:43 p.m. UTC | #5
On Fri, 17 May 2024 11:00:36 +0300
Ramona Gradinariu <ramona.bolboaca13@gmail.com> wrote:

> >> + * device will send the data popped with the (n-1)th consecutive burst request.
> >> + * In order to read the data which was popped previously, without popping the FIFO,
> >> + * the 0x00 0x00 burst request has to be sent.
> >> + * If after a 0x68 0x00 FIFO pop burst request, there is any other device access
> >> + * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped
> >> + * previously will be lost.
> >> + */
> >> +static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
> >>  {
> >>  	struct iio_poll_func *pf = p;
> >>  	struct iio_dev *indio_dev = pf->indio_dev;
> >> +	struct adis16475 *st = iio_priv(indio_dev);
> >> +	struct adis *adis = &st->adis;
> >> +	int ret;
> >> +	u16 fifo_cnt, i;
> >>
> >> -	adis16475_push_single_sample(pf);
> >> +	adis_dev_lock(&st->adis);
> >> +
> >> +	ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
> >> +	if (ret)
> >> +		goto unlock;
> >> +
> >> +	/*
> >> +	 * If no sample is available, nothing can be read. This can happen if
> >> +	 * a the used trigger has a higher frequency than the selected sample rate.
> >> +	 */
> >> +	if (!fifo_cnt)
> >> +		goto unlock;
> >> +
> >> +	/*
> >> +	 * First burst request - FIFO pop: popped data will be returned in the
> >> +	 * next burst request.
> >> +	 */
> >> +	ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd);
> >> +	if (ret)
> >> +		goto unlock;
> >> +
> >> +	for (i = 0; i < fifo_cnt - 1; i++) {
> >> +		ret = adis16475_push_single_sample(pf);
> >> +		if (ret)
> >> +			goto unlock;
> >> +	}
> >> +  
> > My paranoid instincts for potential race conditions kick in.
> > Is this one of those annoying devices where the fifo interrupt will only occur
> > again if we successfully read enough data to get below the threshold?
> > Snag with no public datasheet is I can't just look it up!
> > If it's a level interrupt this won't be a problem.
> >
> > If so the race is the following.
> > 1. Interrupt happens, we read the number of entries in fifo.
> > 2. We read out the fifo, but for some reason our read is slow... (contention on
> >    bus, CPU overheating, who knows).  The data fills up at roughly the
> >    same rate as we are reading.
> > 3. We try to carry on but in reality the fifo contents never dropped below
> >    the watermark, so not more interrupts ever occur.
> >
> > Solution normally is to put this read sequence in a while (fifo_cnt)
> > and reread that after you've done the burst read.  If there is more data
> > go around again.  That way we drive for definitely having gotten to zero
> > at some stage - and hence whatever the threshold is set to a new interrupt
> > will occur.  
> 
> Hello Jonathan,
> 
> Indeed the watermark interrupt is a level interrupt. However adis lib does not 
> allow for level interrupts, so I had to create a new patch in v3 to handle it.
> Until now I tested the watermark interrupt as and edge interrupt and I did not
> see any issues, but indeed if the FIFO is not read fast enough the watermark pin 
> will stay high (or low depending on the configured polarity), so the correct 
> implementation is to use level interrupts for FIFO watermark interrupts.
That is the easy way certainly!

Sounds good to me.

Jonathan

> 
> Ramona G.
> 
>
diff mbox series

Patch

diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index c589f214259b..706ae2611b8f 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -14,6 +14,7 @@ 
 #include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/imu/adis.h>
+#include <linux/iio/sysfs.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/irq.h>
 #include <linux/lcm.h>
@@ -52,6 +53,8 @@ 
 				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x)
 #define ADIS16475_SYNC_MODE_MASK	GENMASK(4, 2)
 #define ADIS16475_SYNC_MODE(x)		FIELD_PREP(ADIS16475_SYNC_MODE_MASK, x)
+#define ADIS16575_SYNC_4KHZ_MASK	BIT(11)
+#define ADIS16575_SYNC_4KHZ(x)		FIELD_PREP(ADIS16575_SYNC_4KHZ_MASK, x)
 #define ADIS16475_REG_UP_SCALE		0x62
 #define ADIS16475_REG_DEC_RATE		0x64
 #define ADIS16475_REG_GLOB_CMD		0x68
@@ -65,15 +68,32 @@ 
 #define ADIS16500_BURST32_MASK		BIT(9)
 #define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BURST32_MASK, x)
 /* number of data elements in burst mode */
-#define ADIS16475_BURST32_MAX_DATA	32
+#define ADIS16475_BURST32_MAX_DATA_NO_TS32	32
+#define ADIS16575_BURST32_DATA_TS32		34
 #define ADIS16475_BURST_MAX_DATA	20
 #define ADIS16475_MAX_SCAN_DATA		20
 /* spi max speed in brust mode */
 #define ADIS16475_BURST_MAX_SPEED	1000000
+#define ADIS16575_BURST_MAX_SPEED	8000000
 #define ADIS16475_LSB_DEC_MASK		0
 #define ADIS16475_LSB_FIR_MASK		1
 #define ADIS16500_BURST_DATA_SEL_0_CHN_MASK	GENMASK(5, 0)
 #define ADIS16500_BURST_DATA_SEL_1_CHN_MASK	GENMASK(12, 7)
+#define ADIS16575_MAX_FIFO_WM		511
+#define ADIS16475_REG_FIFO_CTRL		0x5A
+#define ADIS16575_WM_LVL_MASK		GENMASK(15, 4)
+#define ADIS16575_WM_LVL(x)		FIELD_PREP(ADIS16575_WM_LVL_MASK, x)
+#define ADIS16575_WM_POL_MASK		BIT(3)
+#define ADIS16575_WM_POL(x)		FIELD_PREP(ADIS16575_WM_POL_MASK, x)
+#define ADIS16575_WM_EN_MASK		BIT(2)
+#define ADIS16575_WM_EN(x)		FIELD_PREP(ADIS16575_WM_EN_MASK, x)
+#define ADIS16575_OVERFLOW_MASK		BIT(1)
+#define ADIS16575_STOP_ENQUEUE		FIELD_PREP(ADIS16575_OVERFLOW_MASK, 0)
+#define ADIS16575_OVERWRITE_OLDEST	FIELD_PREP(ADIS16575_OVERFLOW_MASK, 1)
+#define ADIS16575_FIFO_EN_MASK		BIT(0)
+#define ADIS16575_FIFO_EN(x)		FIELD_PREP(ADIS16575_FIFO_EN_MASK, x)
+#define ADIS16575_FIFO_FLUSH_CMD	BIT(5)
+#define ADIS16575_REG_FIFO_CNT		0x3C

 enum {
 	ADIS16475_SYNC_DIRECT = 1,
@@ -95,6 +115,9 @@  struct adis16475_chip_info {
 	const char *name;
 #define ADIS16475_HAS_BURST32		BIT(0)
 #define ADIS16475_HAS_BURST_DELTA_DATA	BIT(1)
+#define ADIS16475_HAS_TIMESTAMP32	BIT(2)
+#define ADIS16475_NEEDS_BURST_REQUEST	BIT(3)
+#define ADIS16475_HAS_FIFO		BIT(4)
 	const long flags;
 	u32 num_channels;
 	u32 gyro_max_val;
@@ -116,6 +139,7 @@  struct adis16475 {
 	bool burst32;
 	unsigned long lsb_flag;
 	u16 sync_mode;
+	u16 fifo_watermark;
 	/* Alignment needed for the timestamp */
 	__be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8);
 };
@@ -442,6 +466,124 @@  static int adis16475_set_filter(struct adis16475 *st, const u32 filter)
 	return 0;
 }

+static ssize_t adis16475_get_fifo_enabled(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct adis16475 *st = iio_priv(indio_dev);
+	int ret;
+	u16 val;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%d\n", (u16)FIELD_GET(ADIS16575_FIFO_EN_MASK, val));
+}
+
+static ssize_t adis16475_get_fifo_watermark(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct adis16475 *st = iio_priv(indio_dev);
+	int ret;
+	u16 val;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%d\n", (u16)FIELD_GET(ADIS16575_WM_LVL_MASK, val) + 1);
+}
+
+static ssize_t hwfifo_watermark_min_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return sysfs_emit(buf, "%s\n", "1");
+}
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return sysfs_emit(buf, "%s\n", __stringify(ADIS16575_MAX_FIFO_WM));
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
+		       adis16475_get_fifo_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+		       adis16475_get_fifo_enabled, NULL, 0);
+
+static const struct attribute *adis16475_fifo_attributes[] = {
+	&iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+	&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+	NULL
+};
+
+static int adis16475_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct adis16475 *st = iio_priv(indio_dev);
+	struct adis *adis = &st->adis;
+
+	return adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
+				ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(1));
+}
+
+static int adis16475_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct adis16475 *st = iio_priv(indio_dev);
+	struct adis *adis = &st->adis;
+	int ret;
+
+	adis_dev_lock(&st->adis);
+
+	ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
+				 ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0));
+	if (ret)
+		goto unlock;
+
+	ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
+				  ADIS16575_FIFO_FLUSH_CMD);
+
+unlock:
+	adis_dev_unlock(&st->adis);
+	return ret;
+}
+
+static const struct iio_buffer_setup_ops adis16475_buffer_ops = {
+	.postenable = adis16475_buffer_postenable,
+	.postdisable = adis16475_buffer_postdisable,
+};
+
+static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+	struct adis16475 *st  = iio_priv(indio_dev);
+	int ret;
+	u16 wm_lvl;
+
+	adis_dev_lock(&st->adis);
+
+	val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM);
+
+	wm_lvl = ADIS16575_WM_LVL(val - 1);
+	ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl);
+	if (ret)
+		goto unlock;
+
+	st->fifo_watermark = val;
+
+unlock:
+	adis_dev_unlock(&st->adis);
+	return ret;
+}
+
 static const u32 adis16475_calib_regs[] = {
 	[ADIS16475_SCAN_GYRO_X] = ADIS16475_REG_X_GYRO_BIAS_L,
 	[ADIS16475_SCAN_GYRO_Y] = ADIS16475_REG_Y_GYRO_BIAS_L,
@@ -673,6 +815,12 @@  enum adis16475_variant {
 	ADIS16507_1,
 	ADIS16507_2,
 	ADIS16507_3,
+	ADIS16575_2,
+	ADIS16575_3,
+	ADIS16576_2,
+	ADIS16576_3,
+	ADIS16577_2,
+	ADIS16577_3,
 };

 enum {
@@ -730,6 +878,12 @@  static const struct adis16475_sync adis16475_sync_mode[] = {
 	{ ADIS16475_SYNC_PULSE, 1000, 2100 },
 };

+static const struct adis16475_sync adis16575_sync_mode[] = {
+	{ ADIS16475_SYNC_OUTPUT },
+	{ ADIS16475_SYNC_DIRECT, 1900, 4100 },
+	{ ADIS16475_SYNC_SCALED, 1, 400 },
+};
+
 static const struct adis_timeout adis16475_timeouts = {
 	.reset_ms = 200,
 	.sw_reset_ms = 200,
@@ -759,7 +913,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16470, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16475_1] = {
@@ -778,7 +932,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16475_2] = {
@@ -797,7 +951,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16475_3] = {
@@ -816,7 +970,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16477_1] = {
@@ -836,7 +990,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16477_2] = {
@@ -856,7 +1010,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16477_3] = {
@@ -876,7 +1030,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16465_1] = {
@@ -895,7 +1049,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16465_2] = {
@@ -914,7 +1068,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16465_3] = {
@@ -933,7 +1087,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16467_1] = {
@@ -952,7 +1106,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16467_2] = {
@@ -971,7 +1125,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16467_3] = {
@@ -990,7 +1144,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.sync = adis16475_sync_mode,
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode),
 		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16500] = {
@@ -1011,7 +1165,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16501] = {
@@ -1032,7 +1186,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16505_1] = {
@@ -1053,7 +1207,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16505_2] = {
@@ -1074,7 +1228,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16505_3] = {
@@ -1095,7 +1249,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16507_1] = {
@@ -1116,7 +1270,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16507_2] = {
@@ -1137,7 +1291,7 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
 	[ADIS16507_3] = {
@@ -1158,9 +1312,153 @@  static const struct adis16475_chip_info adis16475_chip_info[] = {
 		.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
 		.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
 		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
-					    ADIS16475_BURST32_MAX_DATA,
+					    ADIS16475_BURST32_MAX_DATA_NO_TS32,
 					    ADIS16475_BURST_MAX_SPEED),
 	},
+	[ADIS16575_2] = {
+		.name = "adis16575-2",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 8,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
+		.deltvel_max_val = 100,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
+	[ADIS16575_3] = {
+		.name = "adis16575-3",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 8,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+		.deltvel_max_val = 100,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
+	[ADIS16576_2] = {
+		.name = "adis16576-2",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 40,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
+		.deltvel_max_val = 125,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
+	[ADIS16576_3] = {
+		.name = "adis16576-3",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 40,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+		.deltvel_max_val = 125,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
+	[ADIS16577_2] = {
+		.name = "adis16577-2",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 40,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(450),
+		.deltvel_max_val = 400,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
+	[ADIS16577_3] = {
+		.name = "adis16577-3",
+		.num_channels = ARRAY_SIZE(adis16477_channels),
+		.channels = adis16477_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 40,
+		.accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+		.temp_scale = 100,
+		.deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+		.deltvel_max_val = 400,
+		.int_clk = 4000,
+		.max_dec = 3999,
+		.sync = adis16575_sync_mode,
+		.num_sync = ARRAY_SIZE(adis16575_sync_mode),
+		.flags = ADIS16475_HAS_BURST32 |
+			 ADIS16475_HAS_BURST_DELTA_DATA |
+			 ADIS16475_NEEDS_BURST_REQUEST |
+			 ADIS16475_HAS_TIMESTAMP32 |
+			 ADIS16475_HAS_FIFO,
+		.adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
+					    ADIS16575_BURST32_DATA_TS32,
+					    ADIS16575_BURST_MAX_SPEED),
+	},
 };

 static int adis16475_update_scan_mode(struct iio_dev *indio_dev,
@@ -1195,15 +1493,19 @@  static const struct iio_info adis16475_info = {
 	.debugfs_reg_access = adis_debugfs_reg_access,
 };

+static const struct iio_info adis16575_info = {
+	.read_raw = &adis16475_read_raw,
+	.write_raw = &adis16475_write_raw,
+	.update_scan_mode = adis16475_update_scan_mode,
+	.debugfs_reg_access = adis_debugfs_reg_access,
+	.hwfifo_set_watermark = adis16475_set_watermark,
+};
+
 static bool adis16475_validate_crc(const u8 *buffer, u16 crc,
-				   const bool burst32)
+				   u16 burst_size, u16 start_idx)
 {
 	int i;
-	/* extra 6 elements for low gyro and accel */
-	const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA :
-		ADIS16475_BURST_MAX_DATA;
-
-	for (i = 0; i < sz - 2; i++)
+	for (i = start_idx; i < burst_size - 2; i++)
 		crc -= buffer[i];

 	return crc == 0;
@@ -1213,10 +1515,14 @@  static void adis16475_burst32_check(struct adis16475 *st)
 {
 	int ret;
 	struct adis *adis = &st->adis;
+	u8 timestamp32 = 0;

 	if (!(st->info->flags & ADIS16475_HAS_BURST32))
 		return;

+	if (st->info->flags & ADIS16475_HAS_TIMESTAMP32)
+		timestamp32 = 1;
+
 	if (st->lsb_flag && !st->burst32) {
 		const u16 en = ADIS16500_BURST32(1);

@@ -1230,9 +1536,12 @@  static void adis16475_burst32_check(struct adis16475 *st)
 		/*
 		 * In 32-bit mode we need extra 2 bytes for all gyro
 		 * and accel channels.
+		 * If the device has 32-bit timestamp value we need 2 extra
+		 * bytes for it.
 		 */
-		adis->burst_extra_len = 6 * sizeof(u16);
-		adis->xfer[1].len += 6 * sizeof(u16);
+		adis->burst_extra_len = (6 + timestamp32) * sizeof(u16);
+		adis->xfer[1].len += (6 + timestamp32) * sizeof(u16);
+
 		dev_dbg(&adis->spi->dev, "Enable burst32 mode, xfer:%d",
 			adis->xfer[1].len);

@@ -1248,7 +1557,7 @@  static void adis16475_burst32_check(struct adis16475 *st)

 		/* Remove the extra bits */
 		adis->burst_extra_len = 0;
-		adis->xfer[1].len -= 6 * sizeof(u16);
+		adis->xfer[1].len -= (6 + timestamp32) * sizeof(u16);
 		dev_dbg(&adis->spi->dev, "Disable burst32 mode, xfer:%d\n",
 			adis->xfer[1].len);
 	}
@@ -1263,20 +1572,30 @@  static int adis16475_push_single_sample(struct iio_poll_func *pf)
 	__be16 *buffer;
 	u16 crc;
 	bool valid;
+	u8 crc_offset = 9;
+	u16 burst_size = ADIS16475_BURST_MAX_DATA;
+	u16 start_idx = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 2 : 0;
+
 	/* offset until the first element after gyro and accel */
 	const u8 offset = st->burst32 ? 13 : 7;

+	if (st->burst32) {
+		crc_offset = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 16 : 15;
+		burst_size = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ?
+			     ADIS16575_BURST32_DATA_TS32 : ADIS16475_BURST32_MAX_DATA_NO_TS32;
+	}
+
 	ret = spi_sync(adis->spi, &adis->msg);
 	if (ret)
-		goto check_burst32;
+		return ret;

 	buffer = adis->buffer;

-	crc = be16_to_cpu(buffer[offset + 2]);
-	valid = adis16475_validate_crc(adis->buffer, crc, st->burst32);
+	crc = be16_to_cpu(buffer[crc_offset]);
+	valid = adis16475_validate_crc(adis->buffer, crc, burst_size, start_idx);
 	if (!valid) {
 		dev_err(&adis->spi->dev, "Invalid crc\n");
-		goto check_burst32;
+		return ret;
 	}

 	for_each_set_bit(bit, indio_dev->active_scan_mask,
@@ -1337,22 +1656,113 @@  static int adis16475_push_single_sample(struct iio_poll_func *pf)
 	}

 	iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
-check_burst32:
+
+	return 0;
+}
+
+static irqreturn_t adis16475_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct adis16475 *st = iio_priv(indio_dev);
+
+	adis16475_push_single_sample(pf);
 	/*
 	 * We only check the burst mode at the end of the current capture since
 	 * it takes a full data ready cycle for the device to update the burst
 	 * array.
 	 */
 	adis16475_burst32_check(st);
-	return ret;
+
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
 }

-static irqreturn_t adis16475_trigger_handler(int irq, void *p)
+static int adis16575_custom_burst_read(struct iio_poll_func *pf, u8 burst_req)
+{
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct adis16475 *st = iio_priv(indio_dev);
+	struct adis *adis = &st->adis;
+	unsigned int burst_max_length;
+	u8 *tx;
+
+	if (adis->data->burst_max_len)
+		burst_max_length = adis->data->burst_max_len;
+	else
+		burst_max_length = adis->data->burst_len + adis->burst_extra_len;
+
+	tx = adis->buffer + burst_max_length;
+	tx[0] = ADIS_READ_REG(burst_req);
+
+	if (burst_req)
+		return spi_sync(adis->spi, &adis->msg);
+
+	return adis16475_push_single_sample(pf);
+}
+
+/*
+ * This handler is meant to be used for devices which support burst readings
+ * from FIFO (namely devices from adis1657x family).
+ * In order to pop the FIFO the 0x68 0x00 FIFO pop burst request has to be sent.
+ * If the previous device command was not a FIFO pop burst request, the FIFO pop
+ * burst request will simply pop the FIFO without returning valid data.
+ * For the nth consecutive burst request, the
+ * device will send the data popped with the (n-1)th consecutive burst request.
+ * In order to read the data which was popped previously, without popping the FIFO,
+ * the 0x00 0x00 burst request has to be sent.
+ * If after a 0x68 0x00 FIFO pop burst request, there is any other device access
+ * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped
+ * previously will be lost.
+ */
+static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
+	struct adis16475 *st = iio_priv(indio_dev);
+	struct adis *adis = &st->adis;
+	int ret;
+	u16 fifo_cnt, i;

-	adis16475_push_single_sample(pf);
+	adis_dev_lock(&st->adis);
+
+	ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
+	if (ret)
+		goto unlock;
+
+	/*
+	 * If no sample is available, nothing can be read. This can happen if
+	 * a the used trigger has a higher frequency than the selected sample rate.
+	 */
+	if (!fifo_cnt)
+		goto unlock;
+
+	/*
+	 * First burst request - FIFO pop: popped data will be returned in the
+	 * next burst request.
+	 */
+	ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd);
+	if (ret)
+		goto unlock;
+
+	for (i = 0; i < fifo_cnt - 1; i++) {
+		ret = adis16475_push_single_sample(pf);
+		if (ret)
+			goto unlock;
+	}
+
+	/* FIFO read without popping */
+	ret = adis16575_custom_burst_read(pf, 0);
+	if (ret)
+		goto unlock;
+
+unlock:
+	/*
+	 * We only check the burst mode at the end of the current capture since
+	 * reading data from registers will impact the FIFO reading.
+	 */
+	adis16475_burst32_check(st);
+	adis_dev_unlock(&st->adis);
 	iio_trigger_notify_done(indio_dev->trig);

 	return IRQ_HANDLED;
@@ -1366,6 +1776,14 @@  static int adis16475_config_sync_mode(struct adis16475 *st)
 	u32 sync_mode;
 	u16 max_sample_rate = st->info->int_clk + 100;

+	/* if available, enable 4khz internal clock */
+	if (st->info->int_clk == 4000) {
+		ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+					 ADIS16575_SYNC_4KHZ_MASK, (u16)ADIS16575_SYNC_4KHZ(1));
+		if (ret)
+			return ret;
+	}
+
 	/* default to internal clk */
 	st->clk_freq = st->info->int_clk * 1000;

@@ -1472,6 +1890,23 @@  static int adis16475_config_irq_pin(struct adis16475 *st)
 	 */
 	usleep_range(250, 260);

+	/*
+	 * If the device has FIFO support, configure the watermark polarity
+	 * pin as well.
+	 */
+	if (st->info->flags & ADIS16475_HAS_FIFO) {
+		ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+				       ADIS16575_WM_POL_MASK, (u16)ADIS16575_WM_POL(polarity));
+		if (ret)
+			return ret;
+
+		/* Enable watermark interrupt pin. */
+		ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+				       ADIS16575_WM_EN_MASK, (u16)ADIS16575_WM_EN(1));
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }

@@ -1499,7 +1934,10 @@  static int adis16475_probe(struct spi_device *spi)
 	indio_dev->name = st->info->name;
 	indio_dev->channels = st->info->channels;
 	indio_dev->num_channels = st->info->num_channels;
-	indio_dev->info = &adis16475_info;
+	if (st->info->flags & ADIS16475_HAS_FIFO)
+		indio_dev->info = &adis16575_info;
+	else
+		indio_dev->info = &adis16475_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;

 	ret = __adis_initial_startup(&st->adis);
@@ -1514,8 +1952,20 @@  static int adis16475_probe(struct spi_device *spi)
 	if (ret)
 		return ret;

-	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
-						 adis16475_trigger_handler);
+	if (st->info->flags & ADIS16475_HAS_FIFO) {
+		ret = devm_adis_setup_buffer_and_trigger_with_attrs(&st->adis, indio_dev,
+								    adis16475_trigger_handler_with_fifo,
+								    &adis16475_buffer_ops,
+								    adis16475_fifo_attributes);
+		if (ret)
+			return ret;
+		/* Update overflow behavior to always overwrite the oldest sample. */
+		ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+				       ADIS16575_OVERFLOW_MASK, (u16)ADIS16575_OVERWRITE_OLDEST);
+	} else {
+		ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+							 adis16475_trigger_handler);
+	}
 	if (ret)
 		return ret;

@@ -1571,6 +2021,18 @@  static const struct of_device_id adis16475_of_match[] = {
 		.data = &adis16475_chip_info[ADIS16507_2] },
 	{ .compatible = "adi,adis16507-3",
 		.data = &adis16475_chip_info[ADIS16507_3] },
+	{ .compatible = "adi,adis16575-2",
+		.data = &adis16475_chip_info[ADIS16575_2] },
+	{ .compatible = "adi,adis16575-3",
+		.data = &adis16475_chip_info[ADIS16575_3] },
+	{ .compatible = "adi,adis16576-2",
+		.data = &adis16475_chip_info[ADIS16576_2] },
+	{ .compatible = "adi,adis16576-3",
+		.data = &adis16475_chip_info[ADIS16576_3] },
+	{ .compatible = "adi,adis16577-2",
+		.data = &adis16475_chip_info[ADIS16577_2] },
+	{ .compatible = "adi,adis16577-3",
+		.data = &adis16475_chip_info[ADIS16577_3] },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, adis16475_of_match);
@@ -1597,6 +2059,12 @@  static const struct spi_device_id adis16475_ids[] = {
 	{ "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] },
 	{ "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] },
 	{ "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] },
+	{ "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] },
+	{ "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] },
+	{ "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] },
+	{ "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] },
+	{ "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] },
+	{ "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, adis16475_ids);