ADIS16495 External sync and decimation filter

Hello Team, I was hoping to post this sooner, but I got involved into many assignments.

Recently running a support together with Mark Looney, we found one information in the set_freq (adis16480.c:380) function in the driver that it seems like in PPS Mode only the SYNC_SCALE register will be set and as far as I can tell, there is no way to set DEC_RATE. For the SYNC Mode, the reverse is true.

See below:

The issue here is that external sync and decimation filter are not exclusive of each other. The decimation filter is in the signal chain, in all modes. Do not be confused by DS statement where Airplane

This only states the data collection to the ADC is determined, but the ODR, can still be set using DEC_RATE.

Our customer patched the driver as follows, and it is working by now.

From e06a540cf9085f9f5ed8496bd612c099897e28b7 Mon Sep 17 00:00:00 2001
From: Lukas LIchtl
Date: Fri, 10 Jul 2020 12:15:15 +0200
Subject: [PATCH] patch pps mode to allow scaling and decimation

---
 drivers/iio/imu/adis16480.c | 63 +++++++++++++++++++++------------------------
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 08392c6..827e8e2 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -379,34 +379,26 @@ static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
 static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
 {
 	struct adis16480 *st = iio_priv(indio_dev);
-	unsigned int t, reg;
+	unsigned int t;
 
 	t =  val * 1000 + val2 / 1000;
 	if (t <= 0)
 		return -EINVAL;
 
 	/*
-	 * When using PPS mode, the rate of data collection is equal to the
-	 * product of the external clock frequency and the scale factor in the
-	 * SYNC_SCALE register.
-	 * When using sync mode, or internal clock, the output data rate is
-	 * equal with  the clock frequency divided by DEC_RATE + 1.
+         * The output data rate is equal to the clock frequency divided by
+	 * DEC_RATE + 1.
 	 */
-	if (st->clk_mode == ADIS16480_CLK_PPS) {
-		t = t / st->clk_freq;
-		reg = ADIS16495_REG_SYNC_SCALE;
-	} else {
-		t = st->clk_freq / t;
-		reg = ADIS16480_REG_DEC_RATE;
-	}
+        t = st->clk_freq / t;
 
 	if (t > st->chip_info->max_dec_rate)
 		t = st->chip_info->max_dec_rate;
 
-	if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS))
+	if (t != 0)
 		t--;
 
-	return adis_write_reg_16(&st->adis, reg, t);
+        printk("adis16480_set_freq: t=0x%x, clk_freq=0x%x", t, st->clk_freq);
+	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)
@@ -415,28 +407,14 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
 	uint16_t t;
 	int ret;
 	unsigned freq;
-	unsigned int reg;
-
-	if (st->clk_mode == ADIS16480_CLK_PPS)
-		reg = ADIS16495_REG_SYNC_SCALE;
-	else
-		reg = ADIS16480_REG_DEC_RATE;
 
-	ret = adis_read_reg_16(&st->adis, reg, &t);
+	ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * When using PPS mode, the rate of data collection is equal to the
-	 * product of the external clock frequency and the scale factor in the
-	 * SYNC_SCALE register.
-	 * When using sync mode, or internal clock, the output data rate is
-	 * equal with  the clock frequency divided by DEC_RATE + 1.
-	 */
-	if (st->clk_mode == ADIS16480_CLK_PPS)
-		freq = st->clk_freq * t;
-	else
-		freq = st->clk_freq / (t + 1);
+        printk("adis16480_get_freq: t=0x%x, clk_freq=0x%x", t, st->clk_freq);
+
+        freq = st->clk_freq / (t + 1);
 
 	*val = freq / 1000;
 	*val2 = (freq % 1000) * 1000;
@@ -1424,6 +1405,8 @@ static int adis16480_probe(struct spi_device *spi)
 	const struct spi_device_id *id = spi_get_device_id(spi);
 	struct iio_dev *indio_dev;
 	struct adis16480 *st;
+        unsigned int scale;
+        uint16_t val;
 	int ret;
 
 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1461,10 +1444,24 @@ static int adis16480_probe(struct spi_device *spi)
 
 		st->clk_freq = clk_get_rate(st->ext_clk);
 		st->clk_freq *= 1000; /* micro */
+
+                if (st->clk_mode == ADIS16480_CLK_PPS) {
+                        scale = st->chip_info->int_clk / st->clk_freq;
+                        st->clk_freq *= scale;
+                
+                        ret = adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, scale);
+                        if (ret)
+                                dev_err(&indio_dev->dev,
+                                        "Could not set SYNC_SCALE: %d\n", ret);
+                }
 	} else {
 		st->clk_freq = st->chip_info->int_clk;
 	}
 
+	ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val);
+	printk("ADIS16480_REG_FNCTIO_CTRL: adis16480_probe: 0x%x", val);
+        printk("adis16480_probe: st->clk_freq: 0x%x", st->clk_freq);
+
 	/* If burst mode is supported, enable it by default */
 	if (st->chip_info->burst) {
 		st->adis.burst = st->chip_info->burst;
-- 
1.8.3.1

See some example cases:

Case #1: Customer provides an external clock of 4000Hz
  • Set DEC_RATE = 0x03 to produce an ODR of 1000Hz or…
  • Set DEC_RATE = 0x13 to produce an ODR of 200Hz
 
Case #2: Customer provides an external clock of 1Hz, uses scaled sync mode:
  • Set SYNC_SCALE = 0x0FA0 (scale factor = 4000Hz, produces a 4000Hz internal processing rate)
  • Set DEC_RATE = 0x03 to produce an ODR of 1000Hz or…
  • Set DEC_RATE = 0x13 to produce an ODR of 200Hz

All of these should be possible.

Can you please check and advise?

Thank you!



Removed wrong statement from last paragraph
[edited by: JulianoCioffi at 8:16 PM (GMT 0) on 31 Jul 2020]