All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Support ADIS16475 and similar IMUs
@ 2020-02-25 12:41 Nuno Sá
  2020-02-25 12:41 ` [PATCH 1/5] iio: imu: adis: Add Managed device functions Nuno Sá
                   ` (4 more replies)
  0 siblings, 5 replies; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

This series adds support for the adis16475 and similar IMUs. This driver
will be the first user of some changes on the adis library. Hence, the
first three patches are related to the library:
 * Add anaged device functions for registering triggers with the library;
 * Updates the way `irq_mask` is passed to `request_irq()`;
 * It adds an update_bits() like API.

Nuno Sá (5):
  iio: imu: adis: Add Managed device functions
  iio: imu: adis: Add irq mask variable
  iio: adis: Add adis_update_bits() APIs
  iio: imu: Add support for adis16475
  dt-bindings: iio: Add adis16475 documentation

 .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
 .../bindings/iio/imu/adi,adis16475.yaml       |  130 ++
 MAINTAINERS                                   |    9 +
 drivers/iio/imu/Kconfig                       |   13 +
 drivers/iio/imu/Makefile                      |    1 +
 drivers/iio/imu/adis.c                        |   26 +
 drivers/iio/imu/adis16475.c                   | 1304 +++++++++++++++++
 drivers/iio/imu/adis_buffer.c                 |   34 +
 drivers/iio/imu/adis_trigger.c                |   63 +-
 include/linux/iio/imu/adis.h                  |   79 +
 10 files changed, 1662 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
 create mode 100644 Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
 create mode 100644 drivers/iio/imu/adis16475.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 1/5] iio: imu: adis: Add Managed device functions
  2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
@ 2020-02-25 12:41 ` Nuno Sá
  2020-03-03 20:38   ` Jonathan Cameron
  2020-02-25 12:41 ` [PATCH 2/5] iio: imu: adis: Add irq mask variable Nuno Sá
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

This patch adds support for a managed device version of
adis_setup_buffer_and_trigger. It works exactly as the original
one but it calls all the devm_iio_* functions to setup an iio
buffer and trigger. Hence we do not need to care about cleaning those
and we do not need to support a remove() callback for every driver using
the adis library.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/imu/adis_buffer.c  | 34 +++++++++++++++++++++++++++++
 drivers/iio/imu/adis_trigger.c | 39 +++++++++++++++++++++++++++++++---
 include/linux/iio/imu/adis.h   | 17 +++++++++++++++
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index 3f4dd5c00b03..296036a01d39 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -196,7 +196,41 @@ int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
+/**
+ * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for
+ *					  the managed adis device
+ * @adis: The adis device
+ * @indio_dev: The IIO device
+ * @trigger_handler: Optional trigger handler, may be NULL.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function perfoms exactly the same as adis_setup_buffer_and_trigger()
+ */
+int
+devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
+				   irqreturn_t (*trigger_handler)(int, void *))
+{
+	int ret;
+
+	if (!trigger_handler)
+		trigger_handler = adis_trigger_handler;
+
+	ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev,
+					      &iio_pollfunc_store_time,
+					      trigger_handler, NULL);
+	if (ret)
+		return ret;
+
+	if (adis->spi->irq) {
+		ret = devm_adis_probe_trigger(adis, indio_dev);
+		if (ret)
+			return ret;
+	}
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger);
 /**
  * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
  * @adis: The adis device.
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index 8b9cd02c0f9f..a07dcc365c18 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -27,6 +27,13 @@ static const struct iio_trigger_ops adis_trigger_ops = {
 	.set_trigger_state = &adis_data_rdy_trigger_set_state,
 };
 
+static inline void adis_trigger_setup(struct adis *adis)
+{
+	adis->trig->dev.parent = &adis->spi->dev;
+	adis->trig->ops = &adis_trigger_ops;
+	iio_trigger_set_drvdata(adis->trig, adis);
+}
+
 /**
  * adis_probe_trigger() - Sets up trigger for a adis device
  * @adis: The adis device
@@ -45,9 +52,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
 	if (adis->trig == NULL)
 		return -ENOMEM;
 
-	adis->trig->dev.parent = &adis->spi->dev;
-	adis->trig->ops = &adis_trigger_ops;
-	iio_trigger_set_drvdata(adis->trig, adis);
+	adis_trigger_setup(adis);
 
 	ret = request_irq(adis->spi->irq,
 			  &iio_trigger_generic_data_rdy_poll,
@@ -72,7 +77,35 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(adis_probe_trigger);
+/**
+ * devm_adis_probe_trigger() - Sets up trigger for a managed adis device
+ * @adis: The adis device
+ * @indio_dev: The IIO device
+ *
+ * Returns 0 on success or a negative error code
+ */
+int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
+{
+	int ret;
 
+	adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d",
+					    indio_dev->name, indio_dev->id);
+	if (!adis->trig)
+		return -ENOMEM;
+
+	adis_trigger_setup(adis);
+
+	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
+			       &iio_trigger_generic_data_rdy_poll,
+			       IRQF_TRIGGER_RISING,
+			       indio_dev->name,
+			       adis->trig);
+	if (ret)
+		return ret;
+
+	return devm_iio_trigger_register(&adis->spi->dev, adis->trig);
+}
+EXPORT_SYMBOL_GPL(devm_adis_probe_trigger);
 /**
  * adis_remove_trigger() - Remove trigger for a adis devices
  * @adis: The adis device
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index ac7cfd073804..741512b28aaa 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -419,11 +419,15 @@ struct adis_burst {
 	unsigned int	extra_len;
 };
 
+int
+devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
+				   irqreturn_t (*trigger_handler)(int, void *));
 int adis_setup_buffer_and_trigger(struct adis *adis,
 	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *));
 void adis_cleanup_buffer_and_trigger(struct adis *adis,
 	struct iio_dev *indio_dev);
 
+int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
 int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
 void adis_remove_trigger(struct adis *adis);
 
@@ -432,6 +436,13 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
 
 #else /* CONFIG_IIO_BUFFER */
 
+static inline int
+devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
+				   irqreturn_t (*trigger_handler)(int, void *))
+{
+	return 0;
+}
+
 static inline int adis_setup_buffer_and_trigger(struct adis *adis,
 	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *))
 {
@@ -443,6 +454,12 @@ static inline void adis_cleanup_buffer_and_trigger(struct adis *adis,
 {
 }
 
+static inline int devm_adis_probe_trigger(struct adis *adis,
+					  struct iio_dev *indio_dev)
+{
+	return 0;
+}
+
 static inline int adis_probe_trigger(struct adis *adis,
 	struct iio_dev *indio_dev)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 2/5] iio: imu: adis: Add irq mask variable
  2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
  2020-02-25 12:41 ` [PATCH 1/5] iio: imu: adis: Add Managed device functions Nuno Sá
@ 2020-02-25 12:41 ` Nuno Sá
  2020-03-03 20:40   ` Jonathan Cameron
  2020-02-25 12:41 ` [PATCH 3/5] iio: adis: Add adis_update_bits() APIs Nuno Sá
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

There are some ADIS devices that can configure the data ready pin
polarity. Hence, we cannot hardcode our IRQ mask as IRQF_TRIGGER_RISING
since we might want to have it as IRQF_TRIGGER_FALLING.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/imu/adis_trigger.c | 26 ++++++++++++++++++++++++--
 include/linux/iio/imu/adis.h   |  1 +
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index a07dcc365c18..ae5a4f66752f 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -34,6 +34,20 @@ static inline void adis_trigger_setup(struct adis *adis)
 	iio_trigger_set_drvdata(adis->trig, adis);
 }
 
+static inline int __adis_validate_irq_mask(struct adis *adis)
+{
+	if (!adis->irq_mask) {
+		adis->irq_mask = IRQF_TRIGGER_RISING;
+		return 0;
+	} else if (adis->irq_mask != IRQF_TRIGGER_RISING &&
+		   adis->irq_mask != IRQF_TRIGGER_FALLING) {
+		dev_err(&adis->spi->dev, "Invalid IRQ mask:%08lx\n",
+			adis->irq_mask);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 /**
  * adis_probe_trigger() - Sets up trigger for a adis device
  * @adis: The adis device
@@ -54,9 +68,13 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
 
 	adis_trigger_setup(adis);
 
+	ret = __adis_validate_irq_mask(adis);
+	if (ret)
+		return ret;
+
 	ret = request_irq(adis->spi->irq,
 			  &iio_trigger_generic_data_rdy_poll,
-			  IRQF_TRIGGER_RISING,
+			  adis->irq_mask,
 			  indio_dev->name,
 			  adis->trig);
 	if (ret)
@@ -95,9 +113,13 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
 
 	adis_trigger_setup(adis);
 
+	ret = __adis_validate_irq_mask(adis);
+	if (ret)
+		return ret;
+
 	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
 			       &iio_trigger_generic_data_rdy_poll,
-			       IRQF_TRIGGER_RISING,
+			       adis->irq_mask,
 			       indio_dev->name,
 			       adis->trig);
 	if (ret)
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index 741512b28aaa..b4c35d137e2a 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -84,6 +84,7 @@ struct adis {
 	struct spi_message	msg;
 	struct spi_transfer	*xfer;
 	unsigned int		current_page;
+	unsigned long		irq_mask;
 	void			*buffer;
 
 	uint8_t			tx[10] ____cacheline_aligned;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 3/5] iio: adis: Add adis_update_bits() APIs
  2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
  2020-02-25 12:41 ` [PATCH 1/5] iio: imu: adis: Add Managed device functions Nuno Sá
  2020-02-25 12:41 ` [PATCH 2/5] iio: imu: adis: Add irq mask variable Nuno Sá
@ 2020-02-25 12:41 ` Nuno Sá
  2020-03-03 20:48   ` Jonathan Cameron
  2020-02-25 12:41 ` [PATCH 4/5] iio: imu: Add support for adis16475 Nuno Sá
  2020-02-25 12:41 ` [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation Nuno Sá
  4 siblings, 1 reply; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

This patch adds a `regmap_update_bits()` like API to the ADIS library.
It provides locked and unlocked variant.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/iio/imu/adis.c       | 26 +++++++++++++++
 include/linux/iio/imu/adis.h | 61 ++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index a8afd01de4f3..fa0ee35d96f0 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -223,6 +223,32 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(__adis_read_reg);
+/**
+ * __adis_update_bits_base() - ADIS Update bits function - Unlocked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ * @size: Size of the register to update
+ *
+ * Updates the desired bits of @reg in accordance with @mask and @val.
+ */
+int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
+			    const u32 val, u8 size)
+{
+	int ret;
+	u32 __val;
+
+	ret = __adis_read_reg(adis, reg, &__val, size);
+	if (ret)
+		return ret;
+
+	__val &= ~mask;
+	__val |= val & mask;
+
+	return __adis_write_reg(adis, reg, __val, size);
+}
+EXPORT_SYMBOL_GPL(__adis_update_bits_base);
 
 #ifdef CONFIG_DEBUG_FS
 
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index b4c35d137e2a..07073f698718 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -303,6 +303,67 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
 	return ret;
 }
 
+int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
+			    const u32 val, u8 size);
+/**
+ * adis_update_bits_base() - ADIS Update bits function - Locked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ * @size: Size of the register to update
+ *
+ * Updates the desired bits of @reg in accordance with @mask and @val.
+ */
+static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
+					const u32 mask, const u32 val, u8 size)
+{
+	int ret;
+
+	mutex_lock(&adis->state_lock);
+	ret = __adis_update_bits_base(adis, reg, mask, val, size);
+	mutex_unlock(&adis->state_lock);
+	return ret;
+}
+
+/**
+ * adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ *
+ * This macro evaluates the sizeof of @val at compile time and calls
+ * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
+ * @val can lead to undesired behavior if the register to update is 16bit. Also
+ * note that a 64bit value will be treated as an integer. In the same way,
+ * a char is seen as a short.
+ */
+#define adis_update_bits(adis, reg, mask, val) ({			\
+	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
+		adis_update_bits_base(adis, reg, mask, val, 4),         \
+		adis_update_bits_base(adis, reg, mask, val, 2));	\
+})
+
+/**
+ * adis_update_bits() - Wrapper macro for adis_update_bits_base
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ *
+ * This macro evaluates the sizeof of @val at compile time and calls
+ * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
+ * @val can lead to undesired behavior if the register to update is 16bit. Also
+ * note that a 64bit value will be treated as an integer. In the same way,
+ * a char is seen as a short.
+ */
+#define __adis_update_bits(adis, reg, mask, val) ({			\
+	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
+		__adis_update_bits_base(adis, reg, mask, val, 4),	\
+		__adis_update_bits_base(adis, reg, mask, val, 2));	\
+})
+
 int adis_enable_irq(struct adis *adis, bool enable);
 int __adis_check_status(struct adis *adis);
 int __adis_initial_startup(struct adis *adis);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 4/5] iio: imu: Add support for adis16475
  2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
                   ` (2 preceding siblings ...)
  2020-02-25 12:41 ` [PATCH 3/5] iio: adis: Add adis_update_bits() APIs Nuno Sá
@ 2020-02-25 12:41 ` Nuno Sá
  2020-03-03 21:08   ` Jonathan Cameron
  2020-02-25 12:41 ` [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation Nuno Sá
  4 siblings, 1 reply; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

Support ADIS16475 and similar IMU devices. These devices are
a precision, miniature MEMS inertial measurement unit (IMU) that
includes a triaxial gyroscope and a triaxial accelerometer. Each
inertial sensor combines with signal conditioning that optimizes
dynamic performance.

The driver adds support for the following devices:
 * adis16470, adis16475, adis16477, adis16465, adis16467, adis16500,
   adis16505, adis16507.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
 MAINTAINERS                                   |    8 +
 drivers/iio/imu/Kconfig                       |   13 +
 drivers/iio/imu/Makefile                      |    1 +
 drivers/iio/imu/adis16475.c                   | 1304 +++++++++++++++++
 5 files changed, 1333 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
 create mode 100644 drivers/iio/imu/adis16475.c

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475 b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
new file mode 100644
index 000000000000..e2c3776035ea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
@@ -0,0 +1,7 @@
+What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_enable
+KernelVersion:
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Use the device burst read mode when reading buffered
+		data. This mode provides a way to read a batch of
+		output data registers, using a continuous stream of bits.
diff --git a/MAINTAINERS b/MAINTAINERS
index 8fa40c3eb72a..f11262f1f3bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1008,6 +1008,14 @@ W:	http://ez.analog.com/community/linux-device-drivers
 F:	drivers/iio/imu/adis16460.c
 F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
 
+ANALOG DEVICES INC ADIS16475 DRIVER
+M:	Nuno Sa <nuno.sa@analog.com>
+L:	linux-iio@vger.kernel.org
+W:	http://ez.analog.com/community/linux-device-drivers
+S:	Supported
+F:	drivers/iio/imu/adis16475.c
+F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
+
 ANALOG DEVICES INC ADM1177 DRIVER
 M:	Beniamin Bia <beniamin.bia@analog.com>
 M:	Michael Hennerich <Michael.Hennerich@analog.com>
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 60bb1029e759..fc4123d518bc 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -29,6 +29,19 @@ config ADIS16460
 	  To compile this driver as a module, choose M here: the module will be
 	  called adis16460.
 
+config ADIS16475
+	tristate "Analog Devices ADIS16475 and similar IMU driver"
+	depends on SPI
+	select IIO_ADIS_LIB
+	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+	help
+	  Say yes here to build support for Analog Devices ADIS16470, ADIS16475,
+	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial
+	  sensors.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called adis16475.
+
 config ADIS16480
 	tristate "Analog Devices ADIS16480 and similar IMU driver"
 	depends on SPI
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 5237fd4bc384..88b2c4555230 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -6,6 +6,7 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_ADIS16400) += adis16400.o
 obj-$(CONFIG_ADIS16460) += adis16460.o
+obj-$(CONFIG_ADIS16475) += adis16475.o
 obj-$(CONFIG_ADIS16480) += adis16480.o
 
 adis_lib-y += adis.o
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
new file mode 100644
index 000000000000..f7c637734ec8
--- /dev/null
+++ b/drivers/iio/imu/adis16475.c
@@ -0,0 +1,1304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADIS16475 IMU driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <asm/unaligned.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#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/module.h>
+#include <linux/spi/spi.h>
+
+#define ADIS16475_REG_DIAG_STAT		0x02
+#define ADIS16475_REG_X_GYRO_L		0x04
+#define ADIS16475_REG_Y_GYRO_L		0x08
+#define ADIS16475_REG_Z_GYRO_L		0x0C
+#define ADIS16475_REG_X_ACCEL_L		0x10
+#define ADIS16475_REG_Y_ACCEL_L		0x14
+#define ADIS16475_REG_Z_ACCEL_L		0x18
+#define ADIS16475_REG_TEMP_OUT		0x1c
+#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
+#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
+#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
+#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
+#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
+#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
+#define ADIS16475_REG_FILT_CTRL		0x5c
+#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
+#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FILT_CTRL_MASK, x)
+#define ADIS16475_REG_MSG_CTRL		0x60
+#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
+#define ADIS16475_MSG_CTRL_DR_POL(x) \
+				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x)
+#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
+#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EXT_CLK_MASK, x)
+#define ADIS16475_REG_UP_SCALE		0x62
+#define ADIS16475_REG_DEC_RATE		0x64
+#define ADIS16475_REG_GLOB_CMD		0x68
+#define ADIS16475_REG_FIRM_REV		0x6c
+#define ADIS16475_REG_FIRM_DM		0x6e
+#define ADIS16475_REG_FIRM_Y		0x70
+#define ADIS16475_REG_PROD_ID		0x72
+#define ADIS16475_REG_SERIAL_NUM	0x74
+#define ADIS16475_REG_FLASH_CNT		0x7c
+#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_BURST_MAX_DATA	10
+#define ADIS16475_MAX_SCAN_DATA		15
+
+enum clk_mode {
+	ADIS16475_CLK_DIRECT = 1,
+	ADIS16475_CLK_SCALED,
+	ADIS16475_CLK_OUTPUT,
+	ADIS16475_CLK_PULSE = 5,
+};
+
+struct adis16475_clks {
+	const char *name;
+	enum clk_mode clk_mode;
+	u16 min_rate;
+	u16 max_rate;
+};
+
+struct adis16475_chip_info {
+	const struct iio_chan_spec *channels;
+	const struct adis16475_clks *clks;
+	const struct adis_data adis_data;
+	u32 num_channels;
+	u32 gyro_max_val;
+	u32 gyro_max_scale;
+	u32 accel_max_val;
+	u32 accel_max_scale;
+	u32 temp_scale;
+	u32 int_clk;
+	u16 max_dec;
+	u8 num_clks;
+	bool has_burst32;
+};
+
+struct adis16475 {
+	const struct adis16475_chip_info *info;
+	struct adis adis;
+	u32 clk_freq;
+	u32 cached_spi_speed_hz;
+	bool burst32;
+};
+
+enum {
+	ADIS16475_SCAN_GYRO_X,
+	ADIS16475_SCAN_GYRO_Y,
+	ADIS16475_SCAN_GYRO_Z,
+	ADIS16475_SCAN_ACCEL_X,
+	ADIS16475_SCAN_ACCEL_Y,
+	ADIS16475_SCAN_ACCEL_Z,
+	ADIS16475_SCAN_TEMP,
+	ADIS16475_SCAN_DIAG_S_FLAGS,
+	ADIS16475_SCAN_CRC_FAILURE,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t adis16475_show_firmware_revision(struct file *file,
+						char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct adis16475 *st = file->private_data;
+	char buf[7];
+	size_t len;
+	u16 rev;
+	int ret;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV, &rev);
+	if (ret)
+		return ret;
+
+	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16475_firmware_revision_fops = {
+	.open = simple_open,
+	.read = adis16475_show_firmware_revision,
+	.llseek = default_llseek,
+	.owner = THIS_MODULE,
+};
+
+static ssize_t adis16475_show_firmware_date(struct file *file,
+					    char __user *userbuf,
+					    size_t count, loff_t *ppos)
+{
+	struct adis16475 *st = file->private_data;
+	u16 md, year;
+	char buf[12];
+	size_t len;
+	int ret;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
+	if (ret)
+		return ret;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
+	if (ret)
+		return ret;
+
+	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8, md & 0xff,
+		       year);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16475_firmware_date_fops = {
+	.open = simple_open,
+	.read = adis16475_show_firmware_date,
+	.llseek = default_llseek,
+	.owner = THIS_MODULE,
+};
+
+static int adis16475_show_serial_number(void *arg, u64 *val)
+{
+	struct adis16475 *st = arg;
+	u16 serial;
+	int ret;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM, &serial);
+	if (ret)
+		return ret;
+
+	*val = serial;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
+			adis16475_show_serial_number, NULL, "0x%.4llx\n");
+
+static int adis16475_show_product_id(void *arg, u64 *val)
+{
+	struct adis16475 *st = arg;
+	u16 prod_id;
+	int ret;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID, &prod_id);
+	if (ret)
+		return ret;
+
+	*val = prod_id;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
+			adis16475_show_product_id, NULL, "%llu\n");
+
+static int adis16475_show_flash_count(void *arg, u64 *val)
+{
+	struct adis16475 *st = arg;
+	u32 flash_count;
+	int ret;
+
+	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
+			       &flash_count);
+	if (ret)
+		return ret;
+
+	*val = flash_count;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
+			adis16475_show_flash_count, NULL, "%lld\n");
+
+static int adis16475_debugfs_init(struct iio_dev *indio_dev)
+{
+	struct adis16475 *st = iio_priv(indio_dev);
+
+	debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
+			    st, &adis16475_serial_number_fops);
+	debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, st,
+			    &adis16475_product_id_fops);
+	debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, st,
+			    &adis16475_flash_count_fops);
+	debugfs_create_file("firmware_revision", 0400,
+			    indio_dev->debugfs_dentry, st,
+			    &adis16475_firmware_revision_fops);
+	debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry,
+			    st, &adis16475_firmware_date_fops);
+	return 0;
+}
+#else
+static int adis16475_debugfs_init(struct iio_dev *indio_dev)
+{
+	return 0;
+}
+#endif
+
+static ssize_t adis16475_burst_mode_enable_get(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
+
+	return sprintf(buf, "%d\n", st->adis.burst->en);
+}
+
+static ssize_t adis16475_burst_mode_enable_set(struct device *dev,
+					       struct device_attribute *attr,
+					       const char *buf, size_t len)
+{
+	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
+	bool val;
+	int ret;
+
+	ret = kstrtobool(buf, &val);
+	if (ret)
+		return ret;
+
+	if (val)
+		/* 1MHz max in burst mode */
+		st->adis.spi->max_speed_hz = 1000000;
+	else
+		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
+
+	st->adis.burst->en = val;
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
+		       adis16475_burst_mode_enable_get,
+		       adis16475_burst_mode_enable_set, 0);
+
+static struct attribute *adis16475_attributes[] = {
+	&iio_dev_attr_burst_mode_enable.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group adis16495_attribute_group = {
+	.attrs = adis16475_attributes,
+};
+
+static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
+{
+	int ret;
+	u16 dec;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
+	if (ret)
+		return -EINVAL;
+
+	*freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1);
+
+	return 0;
+}
+
+static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
+{
+	u16 dec;
+
+	if (freq == 0 || freq > st->clk_freq)
+		return -EINVAL;
+
+	dec = DIV_ROUND_CLOSEST(st->clk_freq, freq);
+
+	if (dec)
+		dec--;
+
+	if (dec > st->info->max_dec)
+		dec = st->info->max_dec;
+
+	return adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec);
+}
+
+/* The values are approximated. */
+static const u32 adis16475_3db_freqs[] = {
+	[0] = 720, /* Filter disabled, full BW (~720Hz) */
+	[1] = 360,
+	[2] = 164,
+	[3] = 80,
+	[4] = 40,
+	[5] = 20,
+	[6] = 10,
+	[7] = 10, /* not a valid setting */
+};
+
+static int adis16475_get_filter(struct adis16475 *st, u32 *filter)
+{
+	u16 filter_sz;
+	int ret;
+	const int mask = ADIS16475_FILT_CTRL_MASK;
+
+	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL, &filter_sz);
+	if (ret)
+		return ret;
+
+	*filter = adis16475_3db_freqs[filter_sz & mask];
+
+	return 0;
+}
+
+static int adis16475_set_filter(struct adis16475 *st, const u32 filter)
+{
+	int i;
+
+	for (i = ARRAY_SIZE(adis16475_3db_freqs) - 1; i >= 1; i--) {
+		if (adis16475_3db_freqs[i] >= filter)
+			break;
+	}
+
+	return adis_write_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
+				 ADIS16475_FILT_CTRL(i));
+}
+
+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,
+	[ADIS16475_SCAN_GYRO_Z] = ADIS16475_REG_Z_GYRO_BIAS_L,
+	[ADIS16475_SCAN_ACCEL_X] = ADIS16475_REG_X_ACCEL_BIAS_L,
+	[ADIS16475_SCAN_ACCEL_Y] = ADIS16475_REG_Y_ACCEL_BIAS_L,
+	[ADIS16475_SCAN_ACCEL_Z] = ADIS16475_REG_Z_ACCEL_BIAS_L,
+};
+
+static int adis16475_read_raw(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan,
+			      int *val, int *val2, long info)
+{
+	struct adis16475 *st = iio_priv(indio_dev);
+	int ret;
+	u32 tmp;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		return adis_single_conversion(indio_dev, chan, 0, val);
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_ANGL_VEL:
+			*val = st->info->gyro_max_val;
+			*val2 = st->info->gyro_max_scale;
+			return IIO_VAL_FRACTIONAL;
+		case IIO_ACCEL:
+			*val = st->info->accel_max_val;
+			*val2 = st->info->accel_max_scale;
+			return IIO_VAL_FRACTIONAL;
+		case IIO_TEMP:
+			*val = st->info->temp_scale;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = adis_read_reg_32(&st->adis,
+				       adis16475_calib_regs[chan->scan_index],
+				       val);
+		break;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		ret = adis16475_get_filter(st, val);
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = adis16475_get_freq(st, &tmp);
+		if (ret)
+			return ret;
+
+		*val = tmp / 1000;
+		*val2 = (tmp % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	return IIO_VAL_INT;
+}
+
+static int adis16475_write_raw(struct iio_dev *indio_dev,
+			       const struct iio_chan_spec *chan,
+			       int val, int val2, long info)
+{
+	struct adis16475 *st = iio_priv(indio_dev);
+	u32 tmp;
+
+	switch (info) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		tmp = val * 1000 + val2 / 1000;
+		return adis16475_set_freq(st, tmp);
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return adis16475_set_filter(st, val);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		return adis_write_reg_32(&st->adis,
+					 adis16475_calib_regs[chan->scan_index],
+					 val);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define ADIS16475_MOD_CHAN(_type, _mod, _address, _si, _r_bits, _s_bits) \
+	{ \
+		.type = (_type), \
+		.modified = 1, \
+		.channel2 = (_mod), \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+			BIT(IIO_CHAN_INFO_CALIBBIAS), \
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+		.address = (_address), \
+		.scan_index = (_si), \
+		.scan_type = { \
+			.sign = 's', \
+			.realbits = (_r_bits), \
+			.storagebits = (_s_bits), \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
+#define ADIS16475_GYRO_CHANNEL(_mod) \
+	ADIS16475_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
+	ADIS16475_REG_ ## _mod ## _GYRO_L, ADIS16475_SCAN_GYRO_ ## _mod, 32, \
+	32)
+
+#define ADIS16475_ACCEL_CHANNEL(_mod) \
+	ADIS16475_MOD_CHAN(IIO_ACCEL, IIO_MOD_ ## _mod, \
+	ADIS16475_REG_ ## _mod ## _ACCEL_L, ADIS16475_SCAN_ACCEL_ ## _mod, 32, \
+	32)
+
+#define ADIS16475_TEMP_CHANNEL() { \
+		.type = IIO_TEMP, \
+		.indexed = 1, \
+		.channel = 0, \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+			BIT(IIO_CHAN_INFO_SCALE), \
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+		.address = ADIS16475_REG_TEMP_OUT, \
+		.scan_index = ADIS16475_SCAN_TEMP, \
+		.scan_type = { \
+			.sign = 's', \
+			.realbits = 16, \
+			.storagebits = 16, \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
+static const struct iio_chan_spec adis16475_channels[] = {
+	ADIS16475_GYRO_CHANNEL(X),
+	ADIS16475_GYRO_CHANNEL(Y),
+	ADIS16475_GYRO_CHANNEL(Z),
+	ADIS16475_ACCEL_CHANNEL(X),
+	ADIS16475_ACCEL_CHANNEL(Y),
+	ADIS16475_ACCEL_CHANNEL(Z),
+	ADIS16475_TEMP_CHANNEL(),
+	IIO_CHAN_SOFT_TIMESTAMP(9)
+};
+
+enum adis16475_variant {
+	ADIS16470,
+	ADIS16475_1,
+	ADIS16475_2,
+	ADIS16475_3,
+	ADIS16477_1,
+	ADIS16477_2,
+	ADIS16477_3,
+	ADIS16465_1,
+	ADIS16465_2,
+	ADIS16465_3,
+	ADIS16467_1,
+	ADIS16467_2,
+	ADIS16467_3,
+	ADIS16500,
+	ADIS16505_1,
+	ADIS16505_2,
+	ADIS16505_3,
+	ADIS16507_1,
+	ADIS16507_2,
+	ADIS16507_3,
+
+};
+
+enum {
+	ADIS16475_DIAG_STAT_DATA_PATH = 1,
+	ADIS16475_DIAG_STAT_FLASH_MEM,
+	ADIS16475_DIAG_STAT_SPI,
+	ADIS16475_DIAG_STAT_STANDBY,
+	ADIS16475_DIAG_STAT_SENSOR,
+	ADIS16475_DIAG_STAT_MEMORY,
+	ADIS16475_DIAG_STAT_CLK,
+};
+
+static const char * const adis16475_status_error_msgs[] = {
+	[ADIS16475_DIAG_STAT_DATA_PATH] = "Data Path Overrun",
+	[ADIS16475_DIAG_STAT_FLASH_MEM] = "Flash memory update failure",
+	[ADIS16475_DIAG_STAT_SPI] = "SPI communication error",
+	[ADIS16475_DIAG_STAT_STANDBY] = "Standby mode",
+	[ADIS16475_DIAG_STAT_SENSOR] = "Sensor failure",
+	[ADIS16475_DIAG_STAT_MEMORY] = "Memory failure",
+	[ADIS16475_DIAG_STAT_CLK] = "Clock error",
+};
+
+static int adis16475_enable_irq(struct adis *adis, bool enable)
+{
+	/*
+	 * There is no way to gate the data-ready signal internally inside the
+	 * ADIS16475. We can only control it's polarity...
+	 */
+	if (enable)
+		enable_irq(adis->spi->irq);
+	else
+		disable_irq(adis->spi->irq);
+
+	return 0;
+}
+
+#define ADIS16475_DATA(_prod_id, _timeouts)				\
+{									\
+	.msc_ctrl_reg = ADIS16475_REG_MSG_CTRL,				\
+	.glob_cmd_reg = ADIS16475_REG_GLOB_CMD,				\
+	.diag_stat_reg = ADIS16475_REG_DIAG_STAT,			\
+	.prod_id_reg = ADIS16475_REG_PROD_ID,				\
+	.prod_id = (_prod_id),						\
+	.self_test_mask = BIT(2),					\
+	.self_test_reg = ADIS16475_REG_GLOB_CMD,			\
+	.cs_change_delay = 16,						\
+	.read_delay = 5,						\
+	.write_delay = 5,						\
+	.status_error_msgs = adis16475_status_error_msgs,		\
+	.status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) |	\
+		BIT(ADIS16475_DIAG_STAT_FLASH_MEM) |			\
+		BIT(ADIS16475_DIAG_STAT_SPI) |				\
+		BIT(ADIS16475_DIAG_STAT_STANDBY) |			\
+		BIT(ADIS16475_DIAG_STAT_SENSOR) |			\
+		BIT(ADIS16475_DIAG_STAT_MEMORY) |			\
+		BIT(ADIS16475_DIAG_STAT_CLK),				\
+	.enable_irq = adis16475_enable_irq,				\
+	.timeouts = (_timeouts),					\
+}
+
+static const struct adis16475_clks adis16475_ext_clks[] = {
+	{ "sync", ADIS16475_CLK_OUTPUT, 1900, 2100 },
+	{ "direct-sync", ADIS16475_CLK_DIRECT, 1900, 2100 },
+	{ "scaled-sync", ADIS16475_CLK_SCALED, 1, 128 },
+	{ "pulse-sync", ADIS16475_CLK_PULSE, 1000, 2100 },
+};
+
+static const struct adis_timeout adis16475_timeouts = {
+	.reset_ms = 200,
+	.sw_reset_ms = 200,
+	.self_test_ms = 20,
+};
+
+static const struct adis_timeout adis1650x_timeouts = {
+	.reset_ms = 260,
+	.sw_reset_ms = 260,
+	.self_test_ms = 30,
+};
+
+static const struct adis16475_chip_info adis16475_chip_info[] = {
+	[ADIS16470] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16470, &adis16475_timeouts),
+	},
+	[ADIS16475_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+	},
+	[ADIS16475_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+	},
+	[ADIS16475_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+	},
+	[ADIS16477_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+	},
+	[ADIS16477_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+	},
+	[ADIS16477_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+	},
+	[ADIS16465_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+	},
+	[ADIS16465_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+	},
+	[ADIS16465_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+	},
+	[ADIS16467_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+	},
+	[ADIS16467_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+	},
+	[ADIS16467_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 1,
+		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
+		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+	},
+	[ADIS16500] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 392,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts),
+	},
+	[ADIS16505_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 78,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+	},
+	[ADIS16505_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 78,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+	},
+	[ADIS16505_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 78,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+	},
+	[ADIS16507_1] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
+		.accel_max_val = 392,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+	},
+	[ADIS16507_2] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+		.accel_max_val = 392,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+	},
+	[ADIS16507_3] = {
+		.num_channels = ARRAY_SIZE(adis16475_channels),
+		.channels = adis16475_channels,
+		.gyro_max_val = 1,
+		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+		.accel_max_val = 392,
+		.accel_max_scale = 32000 << 16,
+		.temp_scale = 100,
+		.int_clk = 2000,
+		.max_dec = 1999,
+		.clks = adis16475_ext_clks,
+		/* pulse sync not supported */
+		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
+		.has_burst32 = true,
+		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+	},
+};
+
+static const struct iio_info adis16475_info = {
+	.read_raw = &adis16475_read_raw,
+	.write_raw = &adis16475_write_raw,
+	.update_scan_mode = adis_update_scan_mode,
+	.attrs = &adis16495_attribute_group,
+	.debugfs_reg_access = adis_debugfs_reg_access,
+};
+
+static struct adis_burst adis16475_burst = {
+	.en = true,
+	.reg_cmd = ADIS16475_REG_GLOB_CMD,
+	/*
+	 * adis_update_scan_mode_burst() sets the burst length in respect with
+	 * the number of channels and allocates 16 bits for each. However,
+	 * adis1647x devices also need space for DIAG_STAT, DATA_CNTR or
+	 * TIME_STAMP (depending on the clock mode but for us these bytes are
+	 * don't care...) and CRC.
+	 */
+	.extra_len = 3 * sizeof(u16),
+};
+
+static u16 adis16475_validate_crc(const u8 *buffer, const u16 crc,
+				  const bool burst32)
+{
+	int i;
+	u16 __crc = 0;
+
+	/* extra 6 elements for low gyro and accel */
+	const u16 sz = burst32 ? ADIS16475_BURST_MAX_DATA + 6 :
+		ADIS16475_BURST_MAX_DATA;
+
+	for (i = 0; i < sz * 2 - 2; i++)
+		__crc += buffer[i];
+
+	return (__crc != crc);
+}
+
+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);
+	struct adis *adis = &st->adis;
+	int ret, bit, i = 0;
+	u16 crc, data[ADIS16475_MAX_SCAN_DATA], *buffer, crc_res;
+	/* offset until the first element after gyro and accel */
+	const u8 offset = st->burst32 ? 13 : 7;
+
+	ret = spi_sync(adis->spi, &adis->msg);
+	if (ret)
+		return ret;
+
+	buffer = (u16 *)adis->buffer;
+
+	if (!(adis->burst && adis->burst->en))
+		goto push_to_buffers;
+
+	/* We always validate the crc to at least print a message */
+	crc = get_unaligned_be16(&buffer[offset + 2]);
+	crc_res = adis16475_validate_crc((u8 *)adis->buffer, crc,
+					 st->burst32);
+	if (crc_res)
+		dev_err(&adis->spi->dev, "Invalid crc\n");
+
+	for_each_set_bit(bit, indio_dev->active_scan_mask,
+			 indio_dev->masklength) {
+		/*
+		 * When burst mode is used, system flags is the first data
+		 * channel in the sequence, but the scan index is 7.
+		 */
+		switch (bit) {
+		case ADIS16475_SCAN_TEMP:
+			data[i++] = get_unaligned(&buffer[offset]);
+			break;
+		case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
+			/*
+			 * The first 2 bytes on the received data are the
+			 * DIAG_STAT reg, hence the +1 offset here...
+			 */
+			if (st->burst32) {
+				/* upper 16 */
+				data[i++] = get_unaligned(&buffer[bit * 2 + 2]);
+				/* lower 16 */
+				data[i++] = get_unaligned(&buffer[bit * 2 + 1]);
+			} else {
+				data[i++] = get_unaligned(&buffer[bit + 1]);
+				/* lower not used */
+				data[i++] = 0;
+			}
+			break;
+		}
+	}
+
+	buffer = data;
+
+push_to_buffers:
+	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static void adis16475_disable_clk(void *data)
+{
+	clk_disable_unprepare((struct clk *)data);
+}
+
+static int adis16475_config_ext_clk(struct adis16475 *st)
+{
+	int ret;
+	int i;
+	struct device *dev = &st->adis.spi->dev;
+	const struct adis16475_clks *ext_clks = st->info->clks;
+
+	for (i = 0; i < st->info->num_clks; i++) {
+		u16 mode = ADIS16475_EXT_CLK(ext_clks[i].clk_mode);
+		struct clk *clk = devm_clk_get(dev, ext_clks[i].name);
+
+		if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT)
+			return PTR_ERR(clk);
+		else if (IS_ERR(clk))
+			continue;
+
+		ret = clk_prepare_enable(clk);
+		if (ret)
+			return ret;
+
+		ret = devm_add_action_or_reset(dev, adis16475_disable_clk, clk);
+		if (ret)
+			return ret;
+
+		st->clk_freq = clk_get_rate(clk);
+		if (st->clk_freq < ext_clks[i].min_rate ||
+		    st->clk_freq > ext_clks[i].max_rate) {
+			dev_err(dev,
+				"Clk rate:%u not in a valid range:[%u %u]\n",
+				st->clk_freq, ext_clks[i].min_rate,
+				ext_clks[i].max_rate);
+			return -EINVAL;
+		}
+
+		if (ext_clks[i].clk_mode == ADIS16475_CLK_SCALED) {
+			u16 up_scale;
+			u32 scaled_out_freq = 0;
+			/*
+			 * If we are in scaled mode, we must have an up_scale.
+			 * In scaled mode the allowable input clock range is
+			 * 1 Hz to 128 Hz, and the allowable output range is
+			 * 1900 to 2100 Hz. Hence, a scale must be given to
+			 * get the allowable output.
+			 */
+			device_property_read_u32(dev, "adi,scaled-output-hz",
+						 &scaled_out_freq);
+
+			if (scaled_out_freq < 1900 || scaled_out_freq > 2100) {
+				dev_err(dev,
+					"Invalid value:%u for adi,scaled-output-hz",
+					scaled_out_freq);
+				return -EINVAL;
+			}
+
+			up_scale = DIV_ROUND_CLOSEST(scaled_out_freq,
+						     st->clk_freq);
+
+			ret = __adis_write_reg_16(&st->adis,
+						  ADIS16475_CLK_SCALED,
+						  up_scale);
+			if (ret)
+				return ret;
+
+			st->clk_freq = scaled_out_freq;
+		}
+		/*
+		 * Keep in mind that the mask for the clk modes in adis1650*
+		 * chips is different (1100 instead of 11100). However, we
+		 * are not configuring BIT(4) in these chips and the default
+		 * value is 0, so we are fine in doing the below operations.
+		 * I'm keeping this for simplicity and avoiding extra variables
+		 * in chip_info.
+		 */
+		ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+					 ADIS16475_EXT_CLK_MASK, mode);
+		if (ret)
+			return ret;
+
+		usleep_range(250, 260);
+
+		break;
+	}
+
+	if (i == st->info->num_clks)
+		/* internal clk */
+		st->clk_freq = st->info->int_clk;
+
+	st->clk_freq *= 1000;
+
+	return 0;
+}
+
+static int adis16475_config_irq_pin(struct adis16475 *st)
+{
+	int ret;
+	struct irq_data *desc;
+	u32 irq_type;
+	u16 val = 0;
+	u8 polarity;
+	struct spi_device *spi = st->adis.spi;
+
+	desc = irq_get_irq_data(spi->irq);
+	if (!desc) {
+		dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq);
+		return -EINVAL;
+	}
+	/*
+	 * It is possible to configure the data ready polarity. Furthermore, we
+	 * need to update the adis struct if we want data ready as active low.
+	 */
+	irq_type = irqd_get_trigger_type(desc);
+	if (irq_type == IRQF_TRIGGER_RISING) {
+		polarity = 1;
+	} else if (irq_type == IRQF_TRIGGER_FALLING) {
+		polarity = 0;
+		st->adis.irq_mask = IRQF_TRIGGER_FALLING;
+	} else {
+		dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n",
+			irq_type);
+		return -EINVAL;
+	}
+
+	val = ADIS16475_MSG_CTRL_DR_POL(polarity);
+	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+				 ADIS16475_MSG_CTRL_DR_POL_MASK, val);
+	if (ret)
+		return ret;
+	/*
+	 * There is a delay writing to any bits written to the MSC_CTRL
+	 * register. It should not be bigger than 200us, so 250 should be more
+	 * than enough!
+	 */
+	usleep_range(250, 260);
+
+	return 0;
+}
+
+static int adis16475_burst_config(struct adis16475 *st)
+{
+	const u16 burst32 = ADIS16500_BURST32(1);
+	int ret;
+
+	st->burst32 = device_property_read_bool(&st->adis.spi->dev,
+						"adi,burst32-enable");
+	if (!st->burst32)
+		goto burst16;
+
+	if (!st->info->has_burst32) {
+		dev_err(&st->adis.spi->dev, "%s does not support burst32 mode\n",
+			spi_get_device_id(st->adis.spi)->name);
+		return -EINVAL;
+	}
+
+	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+				 ADIS16500_BURST32_MASK, burst32);
+	if (ret)
+		return ret;
+
+	usleep_range(250, 260);
+	/*
+	 * In 32bit mode we need extra 2 bytes for all gyro and accel
+	 * channels.
+	 */
+	adis16475_burst.extra_len += 6 * sizeof(u16);
+burst16:
+	st->adis.burst = &adis16475_burst;
+	/* it's enabled by default so spi max speed needs to be 1MHz */
+	st->cached_spi_speed_hz = st->adis.spi->max_speed_hz;
+	st->adis.spi->max_speed_hz = 1000000;
+
+	return 0;
+}
+
+static int adis16475_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct adis16475 *st;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	st->info = &adis16475_chip_info[id->driver_data];
+	spi_set_drvdata(spi, indio_dev);
+
+	ret = adis_init(&st->adis, indio_dev, spi, &st->info->adis_data);
+	if (ret)
+		return ret;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = id->name;
+	indio_dev->channels = st->info->channels;
+	indio_dev->num_channels = st->info->num_channels;
+	indio_dev->info = &adis16475_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = __adis_initial_startup(&st->adis);
+	if (ret)
+		return ret;
+
+	ret = adis16475_burst_config(st);
+	if (ret)
+		return ret;
+
+	ret = adis16475_config_irq_pin(st);
+	if (ret)
+		return ret;
+
+	ret = adis16475_config_ext_clk(st);
+	if (ret)
+		return ret;
+
+	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+						 adis16475_trigger_handler);
+	if (ret)
+		return ret;
+
+	adis16475_enable_irq(&st->adis, false);
+
+	ret = devm_iio_device_register(&spi->dev, indio_dev);
+	if (ret)
+		return ret;
+
+	adis16475_debugfs_init(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id adis16475_ids[] = {
+	{ "adis16470", ADIS16470 },
+	{ "adis16475-1", ADIS16475_1 },
+	{ "adis16475-2", ADIS16475_2 },
+	{ "adis16475-3", ADIS16475_3 },
+	{ "adis16477-1", ADIS16477_1 },
+	{ "adis16477-2", ADIS16477_2 },
+	{ "adis16477-3", ADIS16477_3 },
+	{ "adis16465-1", ADIS16465_1 },
+	{ "adis16465-2", ADIS16465_2 },
+	{ "adis16465-3", ADIS16465_3 },
+	{ "adis16467-1", ADIS16467_1 },
+	{ "adis16467-2", ADIS16467_2 },
+	{ "adis16467-3", ADIS16467_3 },
+	{ "adis16500", ADIS16500 },
+	{ "adis16505-1", ADIS16505_1 },
+	{ "adis16505-2", ADIS16505_2 },
+	{ "adis16505-3", ADIS16505_3 },
+	{ "adis16507-1", ADIS16507_1 },
+	{ "adis16507-2", ADIS16507_2 },
+	{ "adis16507-3", ADIS16507_3 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adis16475_ids);
+
+static const struct of_device_id adis16475_of_match[] = {
+	{ .compatible = "adi,adis16470" },
+	{ .compatible = "adi,adis16475-1" },
+	{ .compatible = "adi,adis16475-2" },
+	{ .compatible = "adi,adis16475-3" },
+	{ .compatible = "adi,adis16477-1" },
+	{ .compatible = "adi,adis16477-2" },
+	{ .compatible = "adi,adis16477-3" },
+	{ .compatible = "adi,adis16465-1" },
+	{ .compatible = "adi,adis16465-2" },
+	{ .compatible = "adi,adis16465-3" },
+	{ .compatible = "adi,adis16467-1" },
+	{ .compatible = "adi,adis16467-2" },
+	{ .compatible = "adi,adis16467-3" },
+	{ .compatible = "adi,adis16500" },
+	{ .compatible = "adi,adis16505-1" },
+	{ .compatible = "adi,adis16505-2" },
+	{ .compatible = "adi,adis16505-3" },
+	{ .compatible = "adi,adis16507-1" },
+	{ .compatible = "adi,adis16507-2" },
+	{ .compatible = "adi,adis16507-3" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adis16475_of_match);
+
+static struct spi_driver adis16475_driver = {
+	.driver = {
+		.name = "adis16475",
+		.of_match_table = adis16475_of_match,
+	},
+	.id_table = adis16475_ids,
+	.probe = adis16475_probe,
+};
+module_spi_driver(adis16475_driver);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
                   ` (3 preceding siblings ...)
  2020-02-25 12:41 ` [PATCH 4/5] iio: imu: Add support for adis16475 Nuno Sá
@ 2020-02-25 12:41 ` Nuno Sá
  2020-03-02 22:22   ` Rob Herring
  2020-03-03 21:10   ` Jonathan Cameron
  4 siblings, 2 replies; 31+ messages in thread
From: Nuno Sá @ 2020-02-25 12:41 UTC (permalink / raw)
  To: linux-iio, devicetree
  Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

Document the ADIS16475 device devicetree bindings.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 .../bindings/iio/imu/adi,adis16475.yaml       | 130 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 2 files changed, 131 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml

diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
new file mode 100644
index 000000000000..c0f2146e000c
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADIS16475 and similar IMUs
+
+maintainers:
+  - Nuno Sá <nuno.sa@analog.com>
+
+description: |
+  Analog Devices ADIS16475 and similar IMUs
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,adis16475-1
+      - adi,adis16475-2
+      - adi,adis16475-3
+      - adi,adis16477-1
+      - adi,adis16477-2
+      - adi,adis16477-3
+      - adi,adis16470
+      - adi,adis16465-1
+      - adi,adis16465-2
+      - adi,adis16465-3
+      - adi,adis16467-1
+      - adi,adis16467-2
+      - adi,adis16467-3
+      - adi,adis16500
+      - adi,adis16505-1
+      - adi,adis16505-2
+      - adi,adis16505-3
+      - adi,adis16507-1
+      - adi,adis16507-2
+      - adi,adis16507-3
+
+  reg:
+    maxItems: 1
+
+  spi-cpha: true
+
+  spi-cpol: true
+
+  spi-max-frequency:
+    maximum: 2000000
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    oneOf:
+      - const: sync
+      - const: direct-sync
+      - const: pulse-sync
+      - const: scaled-sync
+
+  reset-gpios:
+    description:
+      Must be the device tree identifier of the RESET pin. If specified,
+      it will be asserted during driver probe. As the line is active low,
+      it should be marked GPIO_ACTIVE_LOW.
+    maxItems: 1
+
+  adi,scaled-output-hz:
+    description:
+      This property must be present if the clock mode is scaled-sync through
+      clock-names property. In this mode, the input clock can have a range
+      of 1Hz to 128HZ which must be scaled to originate an allowable sample
+      rate. This property specifies that rate.
+    minimum: 1900
+    maximum: 2100
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - spi-cpha
+  - spi-cpol
+
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - adi,adis16500
+          - adi,adis16505-1
+          - adi,adis16505-2
+          - adi,adis16505-3
+          - adi,adis16507-1
+          - adi,adis16507-2
+          - adi,adis16507-3
+
+then:
+  properties:
+    clock-names:
+      oneOf:
+        - const: sync
+        - const: direct-sync
+        - const: scaled-sync
+
+    adi,burst32-enable:
+      description:
+        Enable burst32 mode. In this mode, a burst reading contains calibrated
+        gyroscope and accelerometer data in 32-bit format.
+      type: boolean
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            adis16475: adis16475-3@0 {
+                    compatible = "adi,adis16475-3";
+                    reg = <0>;
+                    spi-cpha;
+                    spi-cpol;
+                    spi-max-frequency = <2000000>;
+                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+                    interrupt-parent = <&gpio>;
+            };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index f11262f1f3bb..f8ccc92ab378 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1015,6 +1015,7 @@ W:	http://ez.analog.com/community/linux-device-drivers
 S:	Supported
 F:	drivers/iio/imu/adis16475.c
 F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
+F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
 
 ANALOG DEVICES INC ADM1177 DRIVER
 M:	Beniamin Bia <beniamin.bia@analog.com>
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-02-25 12:41 ` [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation Nuno Sá
@ 2020-03-02 22:22   ` Rob Herring
  2020-03-03  9:43     ` Sa, Nuno
  2020-03-03 21:10   ` Jonathan Cameron
  1 sibling, 1 reply; 31+ messages in thread
From: Rob Herring @ 2020-03-02 22:22 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald-Stadler, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, Feb 25, 2020 at 01:41:52PM +0100, Nuno Sá wrote:
> Document the ADIS16475 device devicetree bindings.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> ---
>  .../bindings/iio/imu/adi,adis16475.yaml       | 130 ++++++++++++++++++
>  MAINTAINERS                                   |   1 +
>  2 files changed, 131 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> new file mode 100644
> index 000000000000..c0f2146e000c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices ADIS16475 and similar IMUs
> +
> +maintainers:
> +  - Nuno Sá <nuno.sa@analog.com>
> +
> +description: |
> +  Analog Devices ADIS16475 and similar IMUs
> +  https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> +
> +properties:
> +  compatible:
> +    enum:
> +      - adi,adis16475-1
> +      - adi,adis16475-2
> +      - adi,adis16475-3
> +      - adi,adis16477-1
> +      - adi,adis16477-2
> +      - adi,adis16477-3
> +      - adi,adis16470
> +      - adi,adis16465-1
> +      - adi,adis16465-2
> +      - adi,adis16465-3
> +      - adi,adis16467-1
> +      - adi,adis16467-2
> +      - adi,adis16467-3
> +      - adi,adis16500
> +      - adi,adis16505-1
> +      - adi,adis16505-2
> +      - adi,adis16505-3
> +      - adi,adis16507-1
> +      - adi,adis16507-2
> +      - adi,adis16507-3
> +
> +  reg:
> +    maxItems: 1
> +
> +  spi-cpha: true
> +
> +  spi-cpol: true
> +
> +  spi-max-frequency:
> +    maximum: 2000000
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    oneOf:
> +      - const: sync
> +      - const: direct-sync
> +      - const: pulse-sync
> +      - const: scaled-sync

According to the datasheet I looked at, the input is called 'sync'. It 
looks like you are mixing operating mode and clock connection.

> +
> +  reset-gpios:
> +    description:
> +      Must be the device tree identifier of the RESET pin. If specified,
> +      it will be asserted during driver probe. As the line is active low,
> +      it should be marked GPIO_ACTIVE_LOW.
> +    maxItems: 1
> +
> +  adi,scaled-output-hz:
> +    description:
> +      This property must be present if the clock mode is scaled-sync through
> +      clock-names property. In this mode, the input clock can have a range
> +      of 1Hz to 128HZ which must be scaled to originate an allowable sample
> +      rate. This property specifies that rate.
> +    minimum: 1900
> +    maximum: 2100
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - spi-cpha
> +  - spi-cpol
> +
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        enum:
> +          - adi,adis16500
> +          - adi,adis16505-1
> +          - adi,adis16505-2
> +          - adi,adis16505-3
> +          - adi,adis16507-1
> +          - adi,adis16507-2
> +          - adi,adis16507-3
> +
> +then:
> +  properties:
> +    clock-names:
> +      oneOf:
> +        - const: sync
> +        - const: direct-sync
> +        - const: scaled-sync
> +
> +    adi,burst32-enable:
> +      description:
> +        Enable burst32 mode. In this mode, a burst reading contains calibrated
> +        gyroscope and accelerometer data in 32-bit format.
> +      type: boolean
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    spi {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            adis16475: adis16475-3@0 {
> +                    compatible = "adi,adis16475-3";
> +                    reg = <0>;
> +                    spi-cpha;
> +                    spi-cpol;
> +                    spi-max-frequency = <2000000>;
> +                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> +                    interrupt-parent = <&gpio>;
> +            };
> +    };
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f11262f1f3bb..f8ccc92ab378 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1015,6 +1015,7 @@ W:	http://ez.analog.com/community/linux-device-drivers
>  S:	Supported
>  F:	drivers/iio/imu/adis16475.c
>  F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> +F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>  
>  ANALOG DEVICES INC ADM1177 DRIVER
>  M:	Beniamin Bia <beniamin.bia@analog.com>
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-02 22:22   ` Rob Herring
@ 2020-03-03  9:43     ` Sa, Nuno
  2020-03-03  9:59       ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-03  9:43 UTC (permalink / raw)
  To: robh
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, jic23, devicetree, Hennerich, Michael

On Mon, 2020-03-02 at 16:22 -0600, Rob Herring wrote:
> On Tue, Feb 25, 2020 at 01:41:52PM +0100, Nuno Sá wrote:
> > Document the ADIS16475 device devicetree bindings.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > ---
> >  .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > ++++++++++++++++++
> >  MAINTAINERS                                   |   1 +
> >  2 files changed, 131 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > new file mode 100644
> > index 000000000000..c0f2146e000c
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > @@ -0,0 +1,130 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Analog Devices ADIS16475 and similar IMUs
> > +
> > +maintainers:
> > +  - Nuno Sá <nuno.sa@analog.com>
> > +
> > +description: |
> > +  Analog Devices ADIS16475 and similar IMUs
> > +  
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - adi,adis16475-1
> > +      - adi,adis16475-2
> > +      - adi,adis16475-3
> > +      - adi,adis16477-1
> > +      - adi,adis16477-2
> > +      - adi,adis16477-3
> > +      - adi,adis16470
> > +      - adi,adis16465-1
> > +      - adi,adis16465-2
> > +      - adi,adis16465-3
> > +      - adi,adis16467-1
> > +      - adi,adis16467-2
> > +      - adi,adis16467-3
> > +      - adi,adis16500
> > +      - adi,adis16505-1
> > +      - adi,adis16505-2
> > +      - adi,adis16505-3
> > +      - adi,adis16507-1
> > +      - adi,adis16507-2
> > +      - adi,adis16507-3
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  spi-cpha: true
> > +
> > +  spi-cpol: true
> > +
> > +  spi-max-frequency:
> > +    maximum: 2000000
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  clock-names:
> > +    oneOf:
> > +      - const: sync
> > +      - const: direct-sync
> > +      - const: pulse-sync
> > +      - const: scaled-sync
> 
> According to the datasheet I looked at, the input is called 'sync'.
> It 
> looks like you are mixing operating mode and clock connection.

The sync pin is where the external clock should be connected (when
available). I'm kinda of using the clock-name property as a way of
selecting the mode the user wants to use as done in other devices (
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt
). In the end, what we should have in the sync pin is an external clock
with the exception of the `sync` mode. I guess this one could be called
output-sync and, in this case, the sync pin is actually an output pin
pulsing when the internal processor collects data.

I'm ok in changing it if there's a better way of doing it... Do you
have any suggestion?

-Nuno Sá
> > +
> > +  reset-gpios:
> > +    description:
> > +      Must be the device tree identifier of the RESET pin. If
> > specified,
> > +      it will be asserted during driver probe. As the line is
> > active low,
> > +      it should be marked GPIO_ACTIVE_LOW.
> > +    maxItems: 1
> > +
> > +  adi,scaled-output-hz:
> > +    description:
> > +      This property must be present if the clock mode is scaled-
> > sync through
> > +      clock-names property. In this mode, the input clock can have
> > a range
> > +      of 1Hz to 128HZ which must be scaled to originate an
> > allowable sample
> > +      rate. This property specifies that rate.
> > +    minimum: 1900
> > +    maximum: 2100
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - spi-cpha
> > +  - spi-cpol
> > +
> > +if:
> > +  properties:
> > +    compatible:
> > +      contains:
> > +        enum:
> > +          - adi,adis16500
> > +          - adi,adis16505-1
> > +          - adi,adis16505-2
> > +          - adi,adis16505-3
> > +          - adi,adis16507-1
> > +          - adi,adis16507-2
> > +          - adi,adis16507-3
> > +
> > +then:
> > +  properties:
> > +    clock-names:
> > +      oneOf:
> > +        - const: sync
> > +        - const: direct-sync
> > +        - const: scaled-sync
> > +
> > +    adi,burst32-enable:
> > +      description:
> > +        Enable burst32 mode. In this mode, a burst reading
> > contains calibrated
> > +        gyroscope and accelerometer data in 32-bit format.
> > +      type: boolean
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    spi {
> > +            #address-cells = <1>;
> > +            #size-cells = <0>;
> > +
> > +            adis16475: adis16475-3@0 {
> > +                    compatible = "adi,adis16475-3";
> > +                    reg = <0>;
> > +                    spi-cpha;
> > +                    spi-cpol;
> > +                    spi-max-frequency = <2000000>;
> > +                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> > +                    interrupt-parent = <&gpio>;
> > +            };
> > +    };
> > +...
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f11262f1f3bb..f8ccc92ab378 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1015,6 +1015,7 @@ W:	
> > http://ez.analog.com/community/linux-device-drivers
> >  S:	Supported
> >  F:	drivers/iio/imu/adis16475.c
> >  F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > +F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> >  
> >  ANALOG DEVICES INC ADM1177 DRIVER
> >  M:	Beniamin Bia <beniamin.bia@analog.com>
> > -- 
> > 2.25.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-03  9:43     ` Sa, Nuno
@ 2020-03-03  9:59       ` Sa, Nuno
  2020-03-03 16:34         ` Rob Herring
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-03  9:59 UTC (permalink / raw)
  To: robh
  Cc: linux-iio, devicetree, mark.rutland, pmeerw, lars, Ardelean,
	Alexandru, jic23, knaack.h, Hennerich, Michael

On Tue, 2020-03-03 at 09:43 +0000, Sa, Nuno wrote:
> [External]
> 
> On Mon, 2020-03-02 at 16:22 -0600, Rob Herring wrote:
> > On Tue, Feb 25, 2020 at 01:41:52PM +0100, Nuno Sá wrote:
> > > Document the ADIS16475 device devicetree bindings.
> > > 
> > > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > > ---
> > >  .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > > ++++++++++++++++++
> > >  MAINTAINERS                                   |   1 +
> > >  2 files changed, 131 insertions(+)
> > >  create mode 100644
> > > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > 
> > > diff --git
> > > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > new file mode 100644
> > > index 000000000000..c0f2146e000c
> > > --- /dev/null
> > > +++
> > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > @@ -0,0 +1,130 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Analog Devices ADIS16475 and similar IMUs
> > > +
> > > +maintainers:
> > > +  - Nuno Sá <nuno.sa@analog.com>
> > > +
> > > +description: |
> > > +  Analog Devices ADIS16475 and similar IMUs
> > > +  
> > > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - adi,adis16475-1
> > > +      - adi,adis16475-2
> > > +      - adi,adis16475-3
> > > +      - adi,adis16477-1
> > > +      - adi,adis16477-2
> > > +      - adi,adis16477-3
> > > +      - adi,adis16470
> > > +      - adi,adis16465-1
> > > +      - adi,adis16465-2
> > > +      - adi,adis16465-3
> > > +      - adi,adis16467-1
> > > +      - adi,adis16467-2
> > > +      - adi,adis16467-3
> > > +      - adi,adis16500
> > > +      - adi,adis16505-1
> > > +      - adi,adis16505-2
> > > +      - adi,adis16505-3
> > > +      - adi,adis16507-1
> > > +      - adi,adis16507-2
> > > +      - adi,adis16507-3
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  spi-cpha: true
> > > +
> > > +  spi-cpol: true
> > > +
> > > +  spi-max-frequency:
> > > +    maximum: 2000000
> > > +
> > > +  interrupts:
> > > +    maxItems: 1
> > > +
> > > +  clocks:
> > > +    maxItems: 1
> > > +
> > > +  clock-names:
> > > +    oneOf:
> > > +      - const: sync
> > > +      - const: direct-sync
> > > +      - const: pulse-sync
> > > +      - const: scaled-sync
> > 
> > According to the datasheet I looked at, the input is called 'sync'.
> > It 
> > looks like you are mixing operating mode and clock connection.
> 
> The sync pin is where the external clock should be connected (when
> available). I'm kinda of using the clock-name property as a way of
> selecting the mode the user wants to use as done in other devices (
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt
> ). In the end, what we should have in the sync pin is an external
> clock
> with the exception of the `sync` mode. I guess this one could be
> called
> output-sync and, in this case, the sync pin is actually an output pin
> pulsing when the internal processor collects data.
> 
> I'm ok in changing it if there's a better way of doing it... Do you
> have any suggestion?
> 
> -Nuno Sá

So, you mean having the clock-name only as "sync" (or maybe even
removing it?) and having a dedicated property like clock-mode?

-Nuno Sá
> > > +
> > > +  reset-gpios:
> > > +    description:
> > > +      Must be the device tree identifier of the RESET pin. If
> > > specified,
> > > +      it will be asserted during driver probe. As the line is
> > > active low,
> > > +      it should be marked GPIO_ACTIVE_LOW.
> > > +    maxItems: 1
> > > +
> > > +  adi,scaled-output-hz:
> > > +    description:
> > > +      This property must be present if the clock mode is scaled-
> > > sync through
> > > +      clock-names property. In this mode, the input clock can
> > > have
> > > a range
> > > +      of 1Hz to 128HZ which must be scaled to originate an
> > > allowable sample
> > > +      rate. This property specifies that rate.
> > > +    minimum: 1900
> > > +    maximum: 2100
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - interrupts
> > > +  - spi-cpha
> > > +  - spi-cpol
> > > +
> > > +if:
> > > +  properties:
> > > +    compatible:
> > > +      contains:
> > > +        enum:
> > > +          - adi,adis16500
> > > +          - adi,adis16505-1
> > > +          - adi,adis16505-2
> > > +          - adi,adis16505-3
> > > +          - adi,adis16507-1
> > > +          - adi,adis16507-2
> > > +          - adi,adis16507-3
> > > +
> > > +then:
> > > +  properties:
> > > +    clock-names:
> > > +      oneOf:
> > > +        - const: sync
> > > +        - const: direct-sync
> > > +        - const: scaled-sync
> > > +
> > > +    adi,burst32-enable:
> > > +      description:
> > > +        Enable burst32 mode. In this mode, a burst reading
> > > contains calibrated
> > > +        gyroscope and accelerometer data in 32-bit format.
> > > +      type: boolean
> > > +
> > > +examples:
> > > +  - |
> > > +    #include <dt-bindings/interrupt-controller/irq.h>
> > > +    spi {
> > > +            #address-cells = <1>;
> > > +            #size-cells = <0>;
> > > +
> > > +            adis16475: adis16475-3@0 {
> > > +                    compatible = "adi,adis16475-3";
> > > +                    reg = <0>;
> > > +                    spi-cpha;
> > > +                    spi-cpol;
> > > +                    spi-max-frequency = <2000000>;
> > > +                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> > > +                    interrupt-parent = <&gpio>;
> > > +            };
> > > +    };
> > > +...
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index f11262f1f3bb..f8ccc92ab378 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -1015,6 +1015,7 @@ W:	
> > > http://ez.analog.com/community/linux-device-drivers
> > >  S:	Supported
> > >  F:	drivers/iio/imu/adis16475.c
> > >  F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > > +F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475
> > > .yaml
> > >  
> > >  ANALOG DEVICES INC ADM1177 DRIVER
> > >  M:	Beniamin Bia <beniamin.bia@analog.com>
> > > -- 
> > > 2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-03  9:59       ` Sa, Nuno
@ 2020-03-03 16:34         ` Rob Herring
  2020-03-04 17:25           ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Rob Herring @ 2020-03-03 16:34 UTC (permalink / raw)
  To: Sa, Nuno
  Cc: linux-iio, devicetree, mark.rutland, pmeerw, lars, Ardelean,
	Alexandru, jic23, knaack.h, Hennerich, Michael

On Tue, Mar 3, 2020 at 3:59 AM Sa, Nuno <Nuno.Sa@analog.com> wrote:
>
> On Tue, 2020-03-03 at 09:43 +0000, Sa, Nuno wrote:
> > [External]
> >
> > On Mon, 2020-03-02 at 16:22 -0600, Rob Herring wrote:
> > > On Tue, Feb 25, 2020 at 01:41:52PM +0100, Nuno Sá wrote:
> > > > Document the ADIS16475 device devicetree bindings.
> > > >
> > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > > > ---
> > > >  .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > > > ++++++++++++++++++
> > > >  MAINTAINERS                                   |   1 +
> > > >  2 files changed, 131 insertions(+)
> > > >  create mode 100644
> > > > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > >
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > new file mode 100644
> > > > index 000000000000..c0f2146e000c
> > > > --- /dev/null
> > > > +++
> > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > @@ -0,0 +1,130 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Analog Devices ADIS16475 and similar IMUs
> > > > +
> > > > +maintainers:
> > > > +  - Nuno Sá <nuno.sa@analog.com>
> > > > +
> > > > +description: |
> > > > +  Analog Devices ADIS16475 and similar IMUs
> > > > +
> > > > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    enum:
> > > > +      - adi,adis16475-1
> > > > +      - adi,adis16475-2
> > > > +      - adi,adis16475-3
> > > > +      - adi,adis16477-1
> > > > +      - adi,adis16477-2
> > > > +      - adi,adis16477-3
> > > > +      - adi,adis16470
> > > > +      - adi,adis16465-1
> > > > +      - adi,adis16465-2
> > > > +      - adi,adis16465-3
> > > > +      - adi,adis16467-1
> > > > +      - adi,adis16467-2
> > > > +      - adi,adis16467-3
> > > > +      - adi,adis16500
> > > > +      - adi,adis16505-1
> > > > +      - adi,adis16505-2
> > > > +      - adi,adis16505-3
> > > > +      - adi,adis16507-1
> > > > +      - adi,adis16507-2
> > > > +      - adi,adis16507-3
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  spi-cpha: true
> > > > +
> > > > +  spi-cpol: true
> > > > +
> > > > +  spi-max-frequency:
> > > > +    maximum: 2000000
> > > > +
> > > > +  interrupts:
> > > > +    maxItems: 1
> > > > +
> > > > +  clocks:
> > > > +    maxItems: 1
> > > > +
> > > > +  clock-names:
> > > > +    oneOf:
> > > > +      - const: sync
> > > > +      - const: direct-sync
> > > > +      - const: pulse-sync
> > > > +      - const: scaled-sync
> > >
> > > According to the datasheet I looked at, the input is called 'sync'.
> > > It
> > > looks like you are mixing operating mode and clock connection.
> >
> > The sync pin is where the external clock should be connected (when
> > available). I'm kinda of using the clock-name property as a way of
> > selecting the mode the user wants to use as done in other devices (
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt
> > ). In the end, what we should have in the sync pin is an external
> > clock
> > with the exception of the `sync` mode. I guess this one could be
> > called
> > output-sync and, in this case, the sync pin is actually an output pin
> > pulsing when the internal processor collects data.
> >
> > I'm ok in changing it if there's a better way of doing it... Do you
> > have any suggestion?
> >
> > -Nuno Sá
>
> So, you mean having the clock-name only as "sync" (or maybe even
> removing it?) and having a dedicated property like clock-mode?

Yes. Though it needs a vendor prefix: adi,clock-mode. Or perhaps adi,sync-mode?

Rob

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] iio: imu: adis: Add Managed device functions
  2020-02-25 12:41 ` [PATCH 1/5] iio: imu: adis: Add Managed device functions Nuno Sá
@ 2020-03-03 20:38   ` Jonathan Cameron
  2020-03-04 17:28     ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-03 20:38 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, 25 Feb 2020 13:41:48 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> This patch adds support for a managed device version of
> adis_setup_buffer_and_trigger. It works exactly as the original
> one but it calls all the devm_iio_* functions to setup an iio
> buffer and trigger. Hence we do not need to care about cleaning those
> and we do not need to support a remove() callback for every driver using
> the adis library.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>

A few trivial things inline.

I'm hoping the plan here is to replace all the existing non devm versions
and remove the non devm versions?

That way we don't end up with a near identical repeated block of code.

Thanks,

Jonathan


> ---
>  drivers/iio/imu/adis_buffer.c  | 34 +++++++++++++++++++++++++++++
>  drivers/iio/imu/adis_trigger.c | 39 +++++++++++++++++++++++++++++++---
>  include/linux/iio/imu/adis.h   | 17 +++++++++++++++
>  3 files changed, 87 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
> index 3f4dd5c00b03..296036a01d39 100644
> --- a/drivers/iio/imu/adis_buffer.c
> +++ b/drivers/iio/imu/adis_buffer.c
> @@ -196,7 +196,41 @@ int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);

blank line here.

> +/**
> + * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for
> + *					  the managed adis device
> + * @adis: The adis device
> + * @indio_dev: The IIO device
> + * @trigger_handler: Optional trigger handler, may be NULL.
> + *
> + * Returns 0 on success, a negative error code otherwise.
> + *
> + * This function perfoms exactly the same as adis_setup_buffer_and_trigger()
> + */
> +int
> +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
> +				   irqreturn_t (*trigger_handler)(int, void *))
> +{
> +	int ret;
> +
> +	if (!trigger_handler)
> +		trigger_handler = adis_trigger_handler;
> +
> +	ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev,
> +					      &iio_pollfunc_store_time,
> +					      trigger_handler, NULL);
> +	if (ret)
> +		return ret;
> +
> +	if (adis->spi->irq) {
> +		ret = devm_adis_probe_trigger(adis, indio_dev);
> +		if (ret)
> +			return ret;
> +	}
>  
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger);
>  /**
>   * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
>   * @adis: The adis device.
> diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
> index 8b9cd02c0f9f..a07dcc365c18 100644
> --- a/drivers/iio/imu/adis_trigger.c
> +++ b/drivers/iio/imu/adis_trigger.c
> @@ -27,6 +27,13 @@ static const struct iio_trigger_ops adis_trigger_ops = {
>  	.set_trigger_state = &adis_data_rdy_trigger_set_state,
>  };
>  
> +static inline void adis_trigger_setup(struct adis *adis)
> +{
> +	adis->trig->dev.parent = &adis->spi->dev;
> +	adis->trig->ops = &adis_trigger_ops;
> +	iio_trigger_set_drvdata(adis->trig, adis);
> +}
> +
>  /**
>   * adis_probe_trigger() - Sets up trigger for a adis device
>   * @adis: The adis device
> @@ -45,9 +52,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
>  	if (adis->trig == NULL)
>  		return -ENOMEM;
>  
> -	adis->trig->dev.parent = &adis->spi->dev;
> -	adis->trig->ops = &adis_trigger_ops;
> -	iio_trigger_set_drvdata(adis->trig, adis);
> +	adis_trigger_setup(adis);
>  
>  	ret = request_irq(adis->spi->irq,
>  			  &iio_trigger_generic_data_rdy_poll,
> @@ -72,7 +77,35 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(adis_probe_trigger);

Blank line here would help a tiny bit on readability.

> +/**
> + * devm_adis_probe_trigger() - Sets up trigger for a managed adis device
> + * @adis: The adis device
> + * @indio_dev: The IIO device
> + *
> + * Returns 0 on success or a negative error code
> + */
> +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
> +{
> +	int ret;
>  
> +	adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d",
> +					    indio_dev->name, indio_dev->id);
> +	if (!adis->trig)
> +		return -ENOMEM;
> +
> +	adis_trigger_setup(adis);
> +
> +	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
> +			       &iio_trigger_generic_data_rdy_poll,
> +			       IRQF_TRIGGER_RISING,
> +			       indio_dev->name,
> +			       adis->trig);
> +	if (ret)
> +		return ret;
> +
> +	return devm_iio_trigger_register(&adis->spi->dev, adis->trig);
> +}
> +EXPORT_SYMBOL_GPL(devm_adis_probe_trigger);
>  /**
>   * adis_remove_trigger() - Remove trigger for a adis devices
>   * @adis: The adis device
> diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
> index ac7cfd073804..741512b28aaa 100644
> --- a/include/linux/iio/imu/adis.h
> +++ b/include/linux/iio/imu/adis.h
> @@ -419,11 +419,15 @@ struct adis_burst {
>  	unsigned int	extra_len;
>  };
>  
> +int
> +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
> +				   irqreturn_t (*trigger_handler)(int, void *));
>  int adis_setup_buffer_and_trigger(struct adis *adis,
>  	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *));
>  void adis_cleanup_buffer_and_trigger(struct adis *adis,
>  	struct iio_dev *indio_dev);
>  
> +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
>  int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
>  void adis_remove_trigger(struct adis *adis);
>  
> @@ -432,6 +436,13 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
>  
>  #else /* CONFIG_IIO_BUFFER */
>  
> +static inline int
> +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
> +				   irqreturn_t (*trigger_handler)(int, void *))
> +{
> +	return 0;
> +}
> +
>  static inline int adis_setup_buffer_and_trigger(struct adis *adis,
>  	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *))
>  {
> @@ -443,6 +454,12 @@ static inline void adis_cleanup_buffer_and_trigger(struct adis *adis,
>  {
>  }
>  
> +static inline int devm_adis_probe_trigger(struct adis *adis,
> +					  struct iio_dev *indio_dev)
> +{
> +	return 0;
> +}
> +
>  static inline int adis_probe_trigger(struct adis *adis,
>  	struct iio_dev *indio_dev)
>  {


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] iio: imu: adis: Add irq mask variable
  2020-02-25 12:41 ` [PATCH 2/5] iio: imu: adis: Add irq mask variable Nuno Sá
@ 2020-03-03 20:40   ` Jonathan Cameron
  2020-03-04 17:29     ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-03 20:40 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, 25 Feb 2020 13:41:49 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> There are some ADIS devices that can configure the data ready pin
> polarity. Hence, we cannot hardcode our IRQ mask as IRQF_TRIGGER_RISING
> since we might want to have it as IRQF_TRIGGER_FALLING.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>

Missing docs for the addition to struct adis.

Otherwise, looks good to me.

thanks,

Jonathan

> ---
>  drivers/iio/imu/adis_trigger.c | 26 ++++++++++++++++++++++++--
>  include/linux/iio/imu/adis.h   |  1 +
>  2 files changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
> index a07dcc365c18..ae5a4f66752f 100644
> --- a/drivers/iio/imu/adis_trigger.c
> +++ b/drivers/iio/imu/adis_trigger.c
> @@ -34,6 +34,20 @@ static inline void adis_trigger_setup(struct adis *adis)
>  	iio_trigger_set_drvdata(adis->trig, adis);
>  }
>  
> +static inline int __adis_validate_irq_mask(struct adis *adis)
> +{
> +	if (!adis->irq_mask) {
> +		adis->irq_mask = IRQF_TRIGGER_RISING;
> +		return 0;
> +	} else if (adis->irq_mask != IRQF_TRIGGER_RISING &&
> +		   adis->irq_mask != IRQF_TRIGGER_FALLING) {
> +		dev_err(&adis->spi->dev, "Invalid IRQ mask:%08lx\n",
> +			adis->irq_mask);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
>  /**
>   * adis_probe_trigger() - Sets up trigger for a adis device
>   * @adis: The adis device
> @@ -54,9 +68,13 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
>  
>  	adis_trigger_setup(adis);
>  
> +	ret = __adis_validate_irq_mask(adis);
> +	if (ret)
> +		return ret;
> +
>  	ret = request_irq(adis->spi->irq,
>  			  &iio_trigger_generic_data_rdy_poll,
> -			  IRQF_TRIGGER_RISING,
> +			  adis->irq_mask,
>  			  indio_dev->name,
>  			  adis->trig);
>  	if (ret)
> @@ -95,9 +113,13 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
>  
>  	adis_trigger_setup(adis);
>  
> +	ret = __adis_validate_irq_mask(adis);
> +	if (ret)
> +		return ret;
> +
>  	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
>  			       &iio_trigger_generic_data_rdy_poll,
> -			       IRQF_TRIGGER_RISING,
> +			       adis->irq_mask,
>  			       indio_dev->name,
>  			       adis->trig);
>  	if (ret)
> diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
> index 741512b28aaa..b4c35d137e2a 100644
> --- a/include/linux/iio/imu/adis.h
> +++ b/include/linux/iio/imu/adis.h
> @@ -84,6 +84,7 @@ struct adis {
>  	struct spi_message	msg;
>  	struct spi_transfer	*xfer;
>  	unsigned int		current_page;
> +	unsigned long		irq_mask;

This structure has kernel-doc. Please add this new element.

>  	void			*buffer;
>  
>  	uint8_t			tx[10] ____cacheline_aligned;


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/5] iio: adis: Add adis_update_bits() APIs
  2020-02-25 12:41 ` [PATCH 3/5] iio: adis: Add adis_update_bits() APIs Nuno Sá
@ 2020-03-03 20:48   ` Jonathan Cameron
  2020-03-04 17:32     ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-03 20:48 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, 25 Feb 2020 13:41:50 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> This patch adds a `regmap_update_bits()` like API to the ADIS library.
> It provides locked and unlocked variant.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Mostly fine, but I wonder if we can avoid the need to have comments
on handling of 1 and 8 byte values by explicitly avoiding them happening.

Thanks,

Jonathan

> ---
>  drivers/iio/imu/adis.c       | 26 +++++++++++++++
>  include/linux/iio/imu/adis.h | 61 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 87 insertions(+)
> 
> diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
> index a8afd01de4f3..fa0ee35d96f0 100644
> --- a/drivers/iio/imu/adis.c
> +++ b/drivers/iio/imu/adis.c
> @@ -223,6 +223,32 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(__adis_read_reg);
> +/**
> + * __adis_update_bits_base() - ADIS Update bits function - Unlocked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + * @size: Size of the register to update
> + *
> + * Updates the desired bits of @reg in accordance with @mask and @val.
> + */
> +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
> +			    const u32 val, u8 size)
> +{
> +	int ret;
> +	u32 __val;
> +
> +	ret = __adis_read_reg(adis, reg, &__val, size);
> +	if (ret)
> +		return ret;
> +
> +	__val &= ~mask;
> +	__val |= val & mask;
> +
> +	return __adis_write_reg(adis, reg, __val, size);
> +}
> +EXPORT_SYMBOL_GPL(__adis_update_bits_base);
>  
>  #ifdef CONFIG_DEBUG_FS
>  
> diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
> index b4c35d137e2a..07073f698718 100644
> --- a/include/linux/iio/imu/adis.h
> +++ b/include/linux/iio/imu/adis.h
> @@ -303,6 +303,67 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
>  	return ret;
>  }
>  
> +int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
> +			    const u32 val, u8 size);
> +/**
> + * adis_update_bits_base() - ADIS Update bits function - Locked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + * @size: Size of the register to update
> + *
> + * Updates the desired bits of @reg in accordance with @mask and @val.
> + */
> +static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
> +					const u32 mask, const u32 val, u8 size)
> +{
> +	int ret;
> +
> +	mutex_lock(&adis->state_lock);
> +	ret = __adis_update_bits_base(adis, reg, mask, val, size);
> +	mutex_unlock(&adis->state_lock);
> +	return ret;
> +}
> +
> +/**
> + * adis_update_bits() - Wrapper macro for adis_update_bits_base - Locked version
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + *
> + * This macro evaluates the sizeof of @val at compile time and calls
> + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
> + * @val can lead to undesired behavior if the register to update is 16bit. Also
> + * note that a 64bit value will be treated as an integer. In the same way,
> + * a char is seen as a short.

Are these 'edge' conditions desirable?  If not can we use the compile
time checking tricks to trigger a build failure if they occur?
BUILD_BUG_ON(sizeof(val) == 1) etc.

> + */
> +#define adis_update_bits(adis, reg, mask, val) ({			\
> +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> +		adis_update_bits_base(adis, reg, mask, val, 4),         \
> +		adis_update_bits_base(adis, reg, mask, val, 2));	\
> +})
> +
> +/**
> + * adis_update_bits() - Wrapper macro for adis_update_bits_base
> + * @adis: The adis device
> + * @reg: The address of the lower of the two registers
> + * @mask: Bitmask to change
> + * @val: Value to be written
> + *
> + * This macro evaluates the sizeof of @val at compile time and calls
> + * adis_update_bits_base() accordingly. Be aware that using MACROS/DEFINES for
> + * @val can lead to undesired behavior if the register to update is 16bit. Also
> + * note that a 64bit value will be treated as an integer. In the same way,
> + * a char is seen as a short.
> + */
> +#define __adis_update_bits(adis, reg, mask, val) ({			\
> +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> +		__adis_update_bits_base(adis, reg, mask, val, 4),	\
> +		__adis_update_bits_base(adis, reg, mask, val, 2));	\
> +})
> +
>  int adis_enable_irq(struct adis *adis, bool enable);
>  int __adis_check_status(struct adis *adis);
>  int __adis_initial_startup(struct adis *adis);


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-02-25 12:41 ` [PATCH 4/5] iio: imu: Add support for adis16475 Nuno Sá
@ 2020-03-03 21:08   ` Jonathan Cameron
  2020-03-04 17:59     ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-03 21:08 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, 25 Feb 2020 13:41:51 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> Support ADIS16475 and similar IMU devices. These devices are
> a precision, miniature MEMS inertial measurement unit (IMU) that
> includes a triaxial gyroscope and a triaxial accelerometer. Each
> inertial sensor combines with signal conditioning that optimizes
> dynamic performance.
> 
> The driver adds support for the following devices:
>  * adis16470, adis16475, adis16477, adis16465, adis16467, adis16500,
>    adis16505, adis16507.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>

A few bits and pieces inline.

Thanks,

Jonathan


> ---
>  .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
>  MAINTAINERS                                   |    8 +
>  drivers/iio/imu/Kconfig                       |   13 +
>  drivers/iio/imu/Makefile                      |    1 +
>  drivers/iio/imu/adis16475.c                   | 1304 +++++++++++++++++
>  5 files changed, 1333 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
>  create mode 100644 drivers/iio/imu/adis16475.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475 b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> new file mode 100644
> index 000000000000..e2c3776035ea
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> @@ -0,0 +1,7 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_enable
> +KernelVersion:
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		Use the device burst read mode when reading buffered
> +		data. This mode provides a way to read a batch of
> +		output data registers, using a continuous stream of bits.

See comment on this below.  I'm not keen on this being exposed to userspace
because it will rarely have any idea how to set it.

> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8fa40c3eb72a..f11262f1f3bb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1008,6 +1008,14 @@ W:	http://ez.analog.com/community/linux-device-drivers
>  F:	drivers/iio/imu/adis16460.c
>  F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
>  
> +ANALOG DEVICES INC ADIS16475 DRIVER
> +M:	Nuno Sa <nuno.sa@analog.com>
> +L:	linux-iio@vger.kernel.org
> +W:	http://ez.analog.com/community/linux-device-drivers
> +S:	Supported
> +F:	drivers/iio/imu/adis16475.c
> +F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> +
>  ANALOG DEVICES INC ADM1177 DRIVER
>  M:	Beniamin Bia <beniamin.bia@analog.com>
>  M:	Michael Hennerich <Michael.Hennerich@analog.com>
> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> index 60bb1029e759..fc4123d518bc 100644
> --- a/drivers/iio/imu/Kconfig
> +++ b/drivers/iio/imu/Kconfig
> @@ -29,6 +29,19 @@ config ADIS16460
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called adis16460.
>  
> +config ADIS16475
> +	tristate "Analog Devices ADIS16475 and similar IMU driver"
> +	depends on SPI
> +	select IIO_ADIS_LIB
> +	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
> +	help
> +	  Say yes here to build support for Analog Devices ADIS16470, ADIS16475,
> +	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial
> +	  sensors.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called adis16475.
> +
>  config ADIS16480
>  	tristate "Analog Devices ADIS16480 and similar IMU driver"
>  	depends on SPI
> diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> index 5237fd4bc384..88b2c4555230 100644
> --- a/drivers/iio/imu/Makefile
> +++ b/drivers/iio/imu/Makefile
> @@ -6,6 +6,7 @@
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_ADIS16400) += adis16400.o
>  obj-$(CONFIG_ADIS16460) += adis16460.o
> +obj-$(CONFIG_ADIS16475) += adis16475.o
>  obj-$(CONFIG_ADIS16480) += adis16480.o
>  
>  adis_lib-y += adis.o
> diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
> new file mode 100644
> index 000000000000..f7c637734ec8
> --- /dev/null
> +++ b/drivers/iio/imu/adis16475.c
> @@ -0,0 +1,1304 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * ADIS16475 IMU driver
> + *
> + * Copyright 2019 Analog Devices Inc.
> + */
> +#include <asm/unaligned.h>
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#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/module.h>
> +#include <linux/spi/spi.h>
> +
> +#define ADIS16475_REG_DIAG_STAT		0x02
> +#define ADIS16475_REG_X_GYRO_L		0x04
> +#define ADIS16475_REG_Y_GYRO_L		0x08
> +#define ADIS16475_REG_Z_GYRO_L		0x0C
> +#define ADIS16475_REG_X_ACCEL_L		0x10
> +#define ADIS16475_REG_Y_ACCEL_L		0x14
> +#define ADIS16475_REG_Z_ACCEL_L		0x18
> +#define ADIS16475_REG_TEMP_OUT		0x1c
> +#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
> +#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
> +#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
> +#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
> +#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
> +#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
> +#define ADIS16475_REG_FILT_CTRL		0x5c
> +#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
> +#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FILT_CTRL_MASK, x)
> +#define ADIS16475_REG_MSG_CTRL		0x60
> +#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
> +#define ADIS16475_MSG_CTRL_DR_POL(x) \
> +				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x)
> +#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
> +#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EXT_CLK_MASK, x)
> +#define ADIS16475_REG_UP_SCALE		0x62
> +#define ADIS16475_REG_DEC_RATE		0x64
> +#define ADIS16475_REG_GLOB_CMD		0x68
> +#define ADIS16475_REG_FIRM_REV		0x6c
> +#define ADIS16475_REG_FIRM_DM		0x6e
> +#define ADIS16475_REG_FIRM_Y		0x70
> +#define ADIS16475_REG_PROD_ID		0x72
> +#define ADIS16475_REG_SERIAL_NUM	0x74
> +#define ADIS16475_REG_FLASH_CNT		0x7c
> +#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_BURST_MAX_DATA	10
> +#define ADIS16475_MAX_SCAN_DATA		15
> +
> +enum clk_mode {
> +	ADIS16475_CLK_DIRECT = 1,
> +	ADIS16475_CLK_SCALED,
> +	ADIS16475_CLK_OUTPUT,
> +	ADIS16475_CLK_PULSE = 5,
> +};
> +
> +struct adis16475_clks {
> +	const char *name;
> +	enum clk_mode clk_mode;
> +	u16 min_rate;
> +	u16 max_rate;
> +};
> +
> +struct adis16475_chip_info {
> +	const struct iio_chan_spec *channels;
> +	const struct adis16475_clks *clks;
> +	const struct adis_data adis_data;
> +	u32 num_channels;
> +	u32 gyro_max_val;
> +	u32 gyro_max_scale;
> +	u32 accel_max_val;
> +	u32 accel_max_scale;
> +	u32 temp_scale;
> +	u32 int_clk;
> +	u16 max_dec;
> +	u8 num_clks;
> +	bool has_burst32;
> +};
> +
> +struct adis16475 {
> +	const struct adis16475_chip_info *info;
> +	struct adis adis;
> +	u32 clk_freq;
> +	u32 cached_spi_speed_hz;
> +	bool burst32;
> +};
> +
> +enum {
> +	ADIS16475_SCAN_GYRO_X,
> +	ADIS16475_SCAN_GYRO_Y,
> +	ADIS16475_SCAN_GYRO_Z,
> +	ADIS16475_SCAN_ACCEL_X,
> +	ADIS16475_SCAN_ACCEL_Y,
> +	ADIS16475_SCAN_ACCEL_Z,
> +	ADIS16475_SCAN_TEMP,
> +	ADIS16475_SCAN_DIAG_S_FLAGS,
> +	ADIS16475_SCAN_CRC_FAILURE,
> +};
> +
> +#ifdef CONFIG_DEBUG_FS
> +static ssize_t adis16475_show_firmware_revision(struct file *file,
> +						char __user *userbuf,
> +						size_t count, loff_t *ppos)
> +{
> +	struct adis16475 *st = file->private_data;
> +	char buf[7];
> +	size_t len;
> +	u16 rev;
> +	int ret;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV, &rev);
> +	if (ret)
> +		return ret;
> +
> +	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
> +
> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> +}
> +
> +static const struct file_operations adis16475_firmware_revision_fops = {
> +	.open = simple_open,
> +	.read = adis16475_show_firmware_revision,
> +	.llseek = default_llseek,
> +	.owner = THIS_MODULE,
> +};
> +
> +static ssize_t adis16475_show_firmware_date(struct file *file,
> +					    char __user *userbuf,
> +					    size_t count, loff_t *ppos)
> +{
> +	struct adis16475 *st = file->private_data;
> +	u16 md, year;
> +	char buf[12];
> +	size_t len;
> +	int ret;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
> +	if (ret)
> +		return ret;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
> +	if (ret)
> +		return ret;
> +
> +	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8, md & 0xff,
> +		       year);
> +
> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> +}
> +
> +static const struct file_operations adis16475_firmware_date_fops = {
> +	.open = simple_open,
> +	.read = adis16475_show_firmware_date,
> +	.llseek = default_llseek,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int adis16475_show_serial_number(void *arg, u64 *val)
> +{
> +	struct adis16475 *st = arg;
> +	u16 serial;
> +	int ret;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM, &serial);
> +	if (ret)
> +		return ret;
> +
> +	*val = serial;
> +
> +	return 0;
> +}
> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
> +			adis16475_show_serial_number, NULL, "0x%.4llx\n");
> +
> +static int adis16475_show_product_id(void *arg, u64 *val)
> +{
> +	struct adis16475 *st = arg;
> +	u16 prod_id;
> +	int ret;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID, &prod_id);
> +	if (ret)
> +		return ret;
> +
> +	*val = prod_id;
> +
> +	return 0;
> +}
> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
> +			adis16475_show_product_id, NULL, "%llu\n");
> +
> +static int adis16475_show_flash_count(void *arg, u64 *val)
> +{
> +	struct adis16475 *st = arg;
> +	u32 flash_count;
> +	int ret;
> +
> +	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
> +			       &flash_count);
> +	if (ret)
> +		return ret;
> +
> +	*val = flash_count;
> +
> +	return 0;
> +}
> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
> +			adis16475_show_flash_count, NULL, "%lld\n");
> +
> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> +{
> +	struct adis16475 *st = iio_priv(indio_dev);
> +
> +	debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
> +			    st, &adis16475_serial_number_fops);
> +	debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, st,
> +			    &adis16475_product_id_fops);
> +	debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, st,
> +			    &adis16475_flash_count_fops);
> +	debugfs_create_file("firmware_revision", 0400,
> +			    indio_dev->debugfs_dentry, st,
> +			    &adis16475_firmware_revision_fops);
> +	debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry,
> +			    st, &adis16475_firmware_date_fops);
> +	return 0;
> +}
> +#else
> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> +{
> +	return 0;
> +}
> +#endif
> +
> +static ssize_t adis16475_burst_mode_enable_get(struct device *dev,
> +					       struct device_attribute *attr,
> +					       char *buf)
> +{
> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> +
> +	return sprintf(buf, "%d\n", st->adis.burst->en);
> +}
> +
> +static ssize_t adis16475_burst_mode_enable_set(struct device *dev,
> +					       struct device_attribute *attr,
> +					       const char *buf, size_t len)
> +{
> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> +	bool val;
> +	int ret;
> +
> +	ret = kstrtobool(buf, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val)
> +		/* 1MHz max in burst mode */
> +		st->adis.spi->max_speed_hz = 1000000;
> +	else
> +		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
> +
> +	st->adis.burst->en = val;
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
> +		       adis16475_burst_mode_enable_get,
> +		       adis16475_burst_mode_enable_set, 0);
> +
> +static struct attribute *adis16475_attributes[] = {
> +	&iio_dev_attr_burst_mode_enable.dev_attr.attr,

Hmm.  Normally we try to avoid exposing this and make the decision
automatically based on which channels are enabled.

If more cynical we decide that no one buys and expensive sensor only
to read a few of it's channels, so we turn on burst mode all the time :)

> +	NULL,
> +};
> +
> +static const struct attribute_group adis16495_attribute_group = {
> +	.attrs = adis16475_attributes,
> +};
> +
> +static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
> +{
> +	int ret;
> +	u16 dec;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
> +	if (ret)
> +		return -EINVAL;
> +
> +	*freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1);
> +
> +	return 0;
> +}
> +
> +static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
> +{
> +	u16 dec;
> +
> +	if (freq == 0 || freq > st->clk_freq)
> +		return -EINVAL;
> +
> +	dec = DIV_ROUND_CLOSEST(st->clk_freq, freq);
> +
> +	if (dec)
> +		dec--;
> +
> +	if (dec > st->info->max_dec)
> +		dec = st->info->max_dec;
> +
> +	return adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec);
> +}
> +
> +/* The values are approximated. */
> +static const u32 adis16475_3db_freqs[] = {
> +	[0] = 720, /* Filter disabled, full BW (~720Hz) */
> +	[1] = 360,
> +	[2] = 164,
> +	[3] = 80,
> +	[4] = 40,
> +	[5] = 20,
> +	[6] = 10,
> +	[7] = 10, /* not a valid setting */
> +};
> +
> +static int adis16475_get_filter(struct adis16475 *st, u32 *filter)
> +{
> +	u16 filter_sz;
> +	int ret;
> +	const int mask = ADIS16475_FILT_CTRL_MASK;
> +
> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL, &filter_sz);
> +	if (ret)
> +		return ret;
> +
> +	*filter = adis16475_3db_freqs[filter_sz & mask];
> +
> +	return 0;
> +}
> +
> +static int adis16475_set_filter(struct adis16475 *st, const u32 filter)
> +{
> +	int i;
> +
> +	for (i = ARRAY_SIZE(adis16475_3db_freqs) - 1; i >= 1; i--) {
> +		if (adis16475_3db_freqs[i] >= filter)
> +			break;
> +	}
> +
> +	return adis_write_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
> +				 ADIS16475_FILT_CTRL(i));
> +}
> +
> +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,
> +	[ADIS16475_SCAN_GYRO_Z] = ADIS16475_REG_Z_GYRO_BIAS_L,
> +	[ADIS16475_SCAN_ACCEL_X] = ADIS16475_REG_X_ACCEL_BIAS_L,
> +	[ADIS16475_SCAN_ACCEL_Y] = ADIS16475_REG_Y_ACCEL_BIAS_L,
> +	[ADIS16475_SCAN_ACCEL_Z] = ADIS16475_REG_Z_ACCEL_BIAS_L,
> +};
> +
> +static int adis16475_read_raw(struct iio_dev *indio_dev,
> +			      const struct iio_chan_spec *chan,
> +			      int *val, int *val2, long info)
> +{
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	int ret;
> +	u32 tmp;
> +
> +	switch (info) {
> +	case IIO_CHAN_INFO_RAW:
> +		return adis_single_conversion(indio_dev, chan, 0, val);
> +	case IIO_CHAN_INFO_SCALE:
> +		switch (chan->type) {
> +		case IIO_ANGL_VEL:
> +			*val = st->info->gyro_max_val;
> +			*val2 = st->info->gyro_max_scale;
> +			return IIO_VAL_FRACTIONAL;
> +		case IIO_ACCEL:
> +			*val = st->info->accel_max_val;
> +			*val2 = st->info->accel_max_scale;
> +			return IIO_VAL_FRACTIONAL;
> +		case IIO_TEMP:
> +			*val = st->info->temp_scale;
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_CALIBBIAS:
> +		ret = adis_read_reg_32(&st->adis,
> +				       adis16475_calib_regs[chan->scan_index],
> +				       val);
> +		break;
> +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> +		ret = adis16475_get_filter(st, val);
> +		break;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		ret = adis16475_get_freq(st, &tmp);
> +		if (ret)
> +			return ret;
> +
> +		*val = tmp / 1000;
> +		*val2 = (tmp % 1000) * 1000;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (ret)
> +		return ret;

Better to put this inline after each ret = section and return directly from those.
As it stands the code paths are rather inconsistent.

> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int adis16475_write_raw(struct iio_dev *indio_dev,
> +			       const struct iio_chan_spec *chan,
> +			       int val, int val2, long info)
> +{
> +	struct adis16475 *st = iio_priv(indio_dev);
> +	u32 tmp;
> +
> +	switch (info) {
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		tmp = val * 1000 + val2 / 1000;
> +		return adis16475_set_freq(st, tmp);
> +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> +		return adis16475_set_filter(st, val);
> +	case IIO_CHAN_INFO_CALIBBIAS:
> +		return adis_write_reg_32(&st->adis,
> +					 adis16475_calib_regs[chan->scan_index],
> +					 val);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +#define ADIS16475_MOD_CHAN(_type, _mod, _address, _si, _r_bits, _s_bits) \
> +	{ \
> +		.type = (_type), \
> +		.modified = 1, \
> +		.channel2 = (_mod), \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> +			BIT(IIO_CHAN_INFO_CALIBBIAS), \
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
> +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
> +		.address = (_address), \
> +		.scan_index = (_si), \
> +		.scan_type = { \
> +			.sign = 's', \
> +			.realbits = (_r_bits), \
> +			.storagebits = (_s_bits), \
> +			.endianness = IIO_BE, \
> +		}, \
> +	}
> +
> +#define ADIS16475_GYRO_CHANNEL(_mod) \
> +	ADIS16475_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
> +	ADIS16475_REG_ ## _mod ## _GYRO_L, ADIS16475_SCAN_GYRO_ ## _mod, 32, \
> +	32)
> +
> +#define ADIS16475_ACCEL_CHANNEL(_mod) \
> +	ADIS16475_MOD_CHAN(IIO_ACCEL, IIO_MOD_ ## _mod, \
> +	ADIS16475_REG_ ## _mod ## _ACCEL_L, ADIS16475_SCAN_ACCEL_ ## _mod, 32, \
> +	32)
> +
> +#define ADIS16475_TEMP_CHANNEL() { \
> +		.type = IIO_TEMP, \
> +		.indexed = 1, \
> +		.channel = 0, \
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> +			BIT(IIO_CHAN_INFO_SCALE), \
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
> +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
> +		.address = ADIS16475_REG_TEMP_OUT, \
> +		.scan_index = ADIS16475_SCAN_TEMP, \
> +		.scan_type = { \
> +			.sign = 's', \
> +			.realbits = 16, \
> +			.storagebits = 16, \
> +			.endianness = IIO_BE, \
> +		}, \
> +	}
> +
> +static const struct iio_chan_spec adis16475_channels[] = {
> +	ADIS16475_GYRO_CHANNEL(X),
> +	ADIS16475_GYRO_CHANNEL(Y),
> +	ADIS16475_GYRO_CHANNEL(Z),
> +	ADIS16475_ACCEL_CHANNEL(X),
> +	ADIS16475_ACCEL_CHANNEL(Y),
> +	ADIS16475_ACCEL_CHANNEL(Z),
> +	ADIS16475_TEMP_CHANNEL(),
> +	IIO_CHAN_SOFT_TIMESTAMP(9)
> +};
> +
> +enum adis16475_variant {
> +	ADIS16470,
> +	ADIS16475_1,
> +	ADIS16475_2,
> +	ADIS16475_3,
> +	ADIS16477_1,
> +	ADIS16477_2,
> +	ADIS16477_3,
> +	ADIS16465_1,
> +	ADIS16465_2,
> +	ADIS16465_3,
> +	ADIS16467_1,
> +	ADIS16467_2,
> +	ADIS16467_3,
> +	ADIS16500,
> +	ADIS16505_1,
> +	ADIS16505_2,
> +	ADIS16505_3,
> +	ADIS16507_1,
> +	ADIS16507_2,
> +	ADIS16507_3,
> +
> +};
> +
> +enum {
> +	ADIS16475_DIAG_STAT_DATA_PATH = 1,
> +	ADIS16475_DIAG_STAT_FLASH_MEM,
> +	ADIS16475_DIAG_STAT_SPI,
> +	ADIS16475_DIAG_STAT_STANDBY,
> +	ADIS16475_DIAG_STAT_SENSOR,
> +	ADIS16475_DIAG_STAT_MEMORY,
> +	ADIS16475_DIAG_STAT_CLK,
> +};
> +
> +static const char * const adis16475_status_error_msgs[] = {
> +	[ADIS16475_DIAG_STAT_DATA_PATH] = "Data Path Overrun",
> +	[ADIS16475_DIAG_STAT_FLASH_MEM] = "Flash memory update failure",
> +	[ADIS16475_DIAG_STAT_SPI] = "SPI communication error",
> +	[ADIS16475_DIAG_STAT_STANDBY] = "Standby mode",
> +	[ADIS16475_DIAG_STAT_SENSOR] = "Sensor failure",
> +	[ADIS16475_DIAG_STAT_MEMORY] = "Memory failure",
> +	[ADIS16475_DIAG_STAT_CLK] = "Clock error",
> +};
> +
> +static int adis16475_enable_irq(struct adis *adis, bool enable)
> +{
> +	/*
> +	 * There is no way to gate the data-ready signal internally inside the
> +	 * ADIS16475. We can only control it's polarity...
> +	 */
> +	if (enable)
> +		enable_irq(adis->spi->irq);
> +	else
> +		disable_irq(adis->spi->irq);
> +
> +	return 0;
> +}
> +
> +#define ADIS16475_DATA(_prod_id, _timeouts)				\
> +{									\
> +	.msc_ctrl_reg = ADIS16475_REG_MSG_CTRL,				\
> +	.glob_cmd_reg = ADIS16475_REG_GLOB_CMD,				\
> +	.diag_stat_reg = ADIS16475_REG_DIAG_STAT,			\
> +	.prod_id_reg = ADIS16475_REG_PROD_ID,				\
> +	.prod_id = (_prod_id),						\
> +	.self_test_mask = BIT(2),					\
> +	.self_test_reg = ADIS16475_REG_GLOB_CMD,			\
> +	.cs_change_delay = 16,						\
> +	.read_delay = 5,						\
> +	.write_delay = 5,						\
> +	.status_error_msgs = adis16475_status_error_msgs,		\
> +	.status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) |	\
> +		BIT(ADIS16475_DIAG_STAT_FLASH_MEM) |			\
> +		BIT(ADIS16475_DIAG_STAT_SPI) |				\
> +		BIT(ADIS16475_DIAG_STAT_STANDBY) |			\
> +		BIT(ADIS16475_DIAG_STAT_SENSOR) |			\
> +		BIT(ADIS16475_DIAG_STAT_MEMORY) |			\
> +		BIT(ADIS16475_DIAG_STAT_CLK),				\
> +	.enable_irq = adis16475_enable_irq,				\
> +	.timeouts = (_timeouts),					\
> +}
> +
> +static const struct adis16475_clks adis16475_ext_clks[] = {
> +	{ "sync", ADIS16475_CLK_OUTPUT, 1900, 2100 },
> +	{ "direct-sync", ADIS16475_CLK_DIRECT, 1900, 2100 },
> +	{ "scaled-sync", ADIS16475_CLK_SCALED, 1, 128 },
> +	{ "pulse-sync", ADIS16475_CLK_PULSE, 1000, 2100 },

Rob already commented on this so I'll not bother :)

> +};
> +
> +static const struct adis_timeout adis16475_timeouts = {
> +	.reset_ms = 200,
> +	.sw_reset_ms = 200,
> +	.self_test_ms = 20,
> +};
> +
> +static const struct adis_timeout adis1650x_timeouts = {
> +	.reset_ms = 260,
> +	.sw_reset_ms = 260,
> +	.self_test_ms = 30,
> +};
> +
> +static const struct adis16475_chip_info adis16475_chip_info[] = {
> +	[ADIS16470] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16470, &adis16475_timeouts),
> +	},
> +	[ADIS16475_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
> +	},
> +	[ADIS16475_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
> +	},
> +	[ADIS16475_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
> +	},
> +	[ADIS16477_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
> +	},
> +	[ADIS16477_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
> +	},
> +	[ADIS16477_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
> +	},
> +	[ADIS16465_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
> +	},
> +	[ADIS16465_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
> +	},
> +	[ADIS16465_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
> +	},
> +	[ADIS16467_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
> +	},
> +	[ADIS16467_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
> +	},
> +	[ADIS16467_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 1,
> +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> +		.adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
> +	},
> +	[ADIS16500] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 392,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts),
> +	},
> +	[ADIS16505_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 78,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
> +	},
> +	[ADIS16505_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 78,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
> +	},
> +	[ADIS16505_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 78,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
> +	},
> +	[ADIS16507_1] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> +		.accel_max_val = 392,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
> +	},
> +	[ADIS16507_2] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> +		.accel_max_val = 392,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
> +	},
> +	[ADIS16507_3] = {
> +		.num_channels = ARRAY_SIZE(adis16475_channels),
> +		.channels = adis16475_channels,
> +		.gyro_max_val = 1,
> +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> +		.accel_max_val = 392,
> +		.accel_max_scale = 32000 << 16,
> +		.temp_scale = 100,
> +		.int_clk = 2000,
> +		.max_dec = 1999,
> +		.clks = adis16475_ext_clks,
> +		/* pulse sync not supported */
> +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> +		.has_burst32 = true,
> +		.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
> +	},
> +};
> +
> +static const struct iio_info adis16475_info = {
> +	.read_raw = &adis16475_read_raw,
> +	.write_raw = &adis16475_write_raw,
> +	.update_scan_mode = adis_update_scan_mode,
> +	.attrs = &adis16495_attribute_group,
> +	.debugfs_reg_access = adis_debugfs_reg_access,
> +};
> +
> +static struct adis_burst adis16475_burst = {
> +	.en = true,
> +	.reg_cmd = ADIS16475_REG_GLOB_CMD,
> +	/*
> +	 * adis_update_scan_mode_burst() sets the burst length in respect with
> +	 * the number of channels and allocates 16 bits for each. However,
> +	 * adis1647x devices also need space for DIAG_STAT, DATA_CNTR or
> +	 * TIME_STAMP (depending on the clock mode but for us these bytes are
> +	 * don't care...) and CRC.
> +	 */
> +	.extra_len = 3 * sizeof(u16),
> +};
> +
> +static u16 adis16475_validate_crc(const u8 *buffer, const u16 crc,
> +				  const bool burst32)
> +{
> +	int i;
> +	u16 __crc = 0;
> +
> +	/* extra 6 elements for low gyro and accel */
> +	const u16 sz = burst32 ? ADIS16475_BURST_MAX_DATA + 6 :
> +		ADIS16475_BURST_MAX_DATA;
> +
> +	for (i = 0; i < sz * 2 - 2; i++)
> +		__crc += buffer[i];
> +
> +	return (__crc != crc);
> +}
> +
> +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);
> +	struct adis *adis = &st->adis;
> +	int ret, bit, i = 0;
> +	u16 crc, data[ADIS16475_MAX_SCAN_DATA], *buffer, crc_res;
> +	/* offset until the first element after gyro and accel */
> +	const u8 offset = st->burst32 ? 13 : 7;
> +
> +	ret = spi_sync(adis->spi, &adis->msg);
> +	if (ret)
> +		return ret;
> +
> +	buffer = (u16 *)adis->buffer;
> +
> +	if (!(adis->burst && adis->burst->en))
> +		goto push_to_buffers;
> +
> +	/* We always validate the crc to at least print a message */
> +	crc = get_unaligned_be16(&buffer[offset + 2]);
> +	crc_res = adis16475_validate_crc((u8 *)adis->buffer, crc,
> +					 st->burst32);
> +	if (crc_res)
> +		dev_err(&adis->spi->dev, "Invalid crc\n");
> +
> +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> +			 indio_dev->masklength) {
> +		/*
> +		 * When burst mode is used, system flags is the first data
> +		 * channel in the sequence, but the scan index is 7.
> +		 */
> +		switch (bit) {
> +		case ADIS16475_SCAN_TEMP:
> +			data[i++] = get_unaligned(&buffer[offset]);
> +			break;
> +		case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
> +			/*
> +			 * The first 2 bytes on the received data are the
> +			 * DIAG_STAT reg, hence the +1 offset here...
> +			 */
> +			if (st->burst32) {
> +				/* upper 16 */
> +				data[i++] = get_unaligned(&buffer[bit * 2 + 2]);
> +				/* lower 16 */
> +				data[i++] = get_unaligned(&buffer[bit * 2 + 1]);
> +			} else {
> +				data[i++] = get_unaligned(&buffer[bit + 1]);
> +				/* lower not used */
> +				data[i++] = 0;
> +			}
> +			break;
> +		}
> +	}
> +
> +	buffer = data;
> +
> +push_to_buffers:
> +	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);

I'm not sure data is the right size.  It needs to have space to have an aligned
timestamp at the end.

> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void adis16475_disable_clk(void *data)
> +{
> +	clk_disable_unprepare((struct clk *)data);
> +}
> +
> +static int adis16475_config_ext_clk(struct adis16475 *st)
> +{
> +	int ret;
> +	int i;
> +	struct device *dev = &st->adis.spi->dev;
> +	const struct adis16475_clks *ext_clks = st->info->clks;
> +
> +	for (i = 0; i < st->info->num_clks; i++) {
> +		u16 mode = ADIS16475_EXT_CLK(ext_clks[i].clk_mode);
> +		struct clk *clk = devm_clk_get(dev, ext_clks[i].name);
> +
> +		if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT)
> +			return PTR_ERR(clk);
> +		else if (IS_ERR(clk))
> +			continue;
> +
> +		ret = clk_prepare_enable(clk);
> +		if (ret)
> +			return ret;
> +
> +		ret = devm_add_action_or_reset(dev, adis16475_disable_clk, clk);
> +		if (ret)
> +			return ret;
> +
> +		st->clk_freq = clk_get_rate(clk);
> +		if (st->clk_freq < ext_clks[i].min_rate ||
> +		    st->clk_freq > ext_clks[i].max_rate) {
> +			dev_err(dev,
> +				"Clk rate:%u not in a valid range:[%u %u]\n",
> +				st->clk_freq, ext_clks[i].min_rate,
> +				ext_clks[i].max_rate);
> +			return -EINVAL;
> +		}
> +
> +		if (ext_clks[i].clk_mode == ADIS16475_CLK_SCALED) {
> +			u16 up_scale;
> +			u32 scaled_out_freq = 0;
> +			/*
> +			 * If we are in scaled mode, we must have an up_scale.
> +			 * In scaled mode the allowable input clock range is
> +			 * 1 Hz to 128 Hz, and the allowable output range is
> +			 * 1900 to 2100 Hz. Hence, a scale must be given to
> +			 * get the allowable output.
> +			 */
> +			device_property_read_u32(dev, "adi,scaled-output-hz",
> +						 &scaled_out_freq);
> +
> +			if (scaled_out_freq < 1900 || scaled_out_freq > 2100) {
> +				dev_err(dev,
> +					"Invalid value:%u for adi,scaled-output-hz",
> +					scaled_out_freq);
> +				return -EINVAL;
> +			}
> +
> +			up_scale = DIV_ROUND_CLOSEST(scaled_out_freq,
> +						     st->clk_freq);
> +
> +			ret = __adis_write_reg_16(&st->adis,
> +						  ADIS16475_CLK_SCALED,
> +						  up_scale);
> +			if (ret)
> +				return ret;
> +
> +			st->clk_freq = scaled_out_freq;
> +		}
> +		/*
> +		 * Keep in mind that the mask for the clk modes in adis1650*
> +		 * chips is different (1100 instead of 11100). However, we
> +		 * are not configuring BIT(4) in these chips and the default
> +		 * value is 0, so we are fine in doing the below operations.
> +		 * I'm keeping this for simplicity and avoiding extra variables
> +		 * in chip_info.
> +		 */
> +		ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> +					 ADIS16475_EXT_CLK_MASK, mode);
> +		if (ret)
> +			return ret;
> +
> +		usleep_range(250, 260);
> +
> +		break;
> +	}
> +
> +	if (i == st->info->num_clks)
> +		/* internal clk */
> +		st->clk_freq = st->info->int_clk;
> +
> +	st->clk_freq *= 1000;
> +
> +	return 0;
> +}
> +
> +static int adis16475_config_irq_pin(struct adis16475 *st)
> +{
> +	int ret;
> +	struct irq_data *desc;
> +	u32 irq_type;
> +	u16 val = 0;
> +	u8 polarity;
> +	struct spi_device *spi = st->adis.spi;
> +
> +	desc = irq_get_irq_data(spi->irq);
> +	if (!desc) {
> +		dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq);
> +		return -EINVAL;
> +	}
> +	/*
> +	 * It is possible to configure the data ready polarity. Furthermore, we
> +	 * need to update the adis struct if we want data ready as active low.
> +	 */
> +	irq_type = irqd_get_trigger_type(desc);
> +	if (irq_type == IRQF_TRIGGER_RISING) {
> +		polarity = 1;
> +	} else if (irq_type == IRQF_TRIGGER_FALLING) {
> +		polarity = 0;
> +		st->adis.irq_mask = IRQF_TRIGGER_FALLING;
> +	} else {
> +		dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n",
> +			irq_type);
> +		return -EINVAL;
> +	}
> +
> +	val = ADIS16475_MSG_CTRL_DR_POL(polarity);
> +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> +				 ADIS16475_MSG_CTRL_DR_POL_MASK, val);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * There is a delay writing to any bits written to the MSC_CTRL
> +	 * register. It should not be bigger than 200us, so 250 should be more
> +	 * than enough!
> +	 */
> +	usleep_range(250, 260);
> +
> +	return 0;
> +}
> +
> +static int adis16475_burst_config(struct adis16475 *st)
> +{
> +	const u16 burst32 = ADIS16500_BURST32(1);
> +	int ret;
> +
> +	st->burst32 = device_property_read_bool(&st->adis.spi->dev,
> +						"adi,burst32-enable");
> +	if (!st->burst32)
> +		goto burst16;
A forwards goto like this on a non error condition, is a bit unusual.
While it involves more indenting I would still prefer the logic flipped
	if (st->burst32) {

	}


> +
> +	if (!st->info->has_burst32) {
> +		dev_err(&st->adis.spi->dev, "%s does not support burst32 mode\n",
> +			spi_get_device_id(st->adis.spi)->name);
> +		return -EINVAL;
> +	}
> +
> +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> +				 ADIS16500_BURST32_MASK, burst32);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(250, 260);
> +	/*
> +	 * In 32bit mode we need extra 2 bytes for all gyro and accel
> +	 * channels.
> +	 */
> +	adis16475_burst.extra_len += 6 * sizeof(u16);
> +burst16:
> +	st->adis.burst = &adis16475_burst;
> +	/* it's enabled by default so spi max speed needs to be 1MHz */
> +	st->cached_spi_speed_hz = st->adis.spi->max_speed_hz;
> +	st->adis.spi->max_speed_hz = 1000000;
> +
> +	return 0;
> +}
> +
> +static int adis16475_probe(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev;
> +	struct adis16475 *st;
> +	const struct spi_device_id *id = spi_get_device_id(spi);
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	st = iio_priv(indio_dev);
> +	st->info = &adis16475_chip_info[id->driver_data];
> +	spi_set_drvdata(spi, indio_dev);
> +
> +	ret = adis_init(&st->adis, indio_dev, spi, &st->info->adis_data);
> +	if (ret)
> +		return ret;
> +
> +	indio_dev->dev.parent = &spi->dev;
> +	indio_dev->name = id->name;
> +	indio_dev->channels = st->info->channels;
> +	indio_dev->num_channels = st->info->num_channels;
> +	indio_dev->info = &adis16475_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +
> +	ret = __adis_initial_startup(&st->adis);
> +	if (ret)
> +		return ret;
> +
> +	ret = adis16475_burst_config(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = adis16475_config_irq_pin(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = adis16475_config_ext_clk(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
> +						 adis16475_trigger_handler);
> +	if (ret)
> +		return ret;
> +
> +	adis16475_enable_irq(&st->adis, false);
> +
> +	ret = devm_iio_device_register(&spi->dev, indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	adis16475_debugfs_init(indio_dev);
> +
> +	return 0;
> +}
> +
> +static const struct spi_device_id adis16475_ids[] = {

Is it actually possible to instantiate this except by
using the dt table below?  If not, then move the 'data'
part into that table and don't provide an spi_device_id
table at all.  It's not relevant to the possible ways
of causing the driver to probe.

> +	{ "adis16470", ADIS16470 },
> +	{ "adis16475-1", ADIS16475_1 },
> +	{ "adis16475-2", ADIS16475_2 },
> +	{ "adis16475-3", ADIS16475_3 },
> +	{ "adis16477-1", ADIS16477_1 },
> +	{ "adis16477-2", ADIS16477_2 },
> +	{ "adis16477-3", ADIS16477_3 },
> +	{ "adis16465-1", ADIS16465_1 },
> +	{ "adis16465-2", ADIS16465_2 },
> +	{ "adis16465-3", ADIS16465_3 },
> +	{ "adis16467-1", ADIS16467_1 },
> +	{ "adis16467-2", ADIS16467_2 },
> +	{ "adis16467-3", ADIS16467_3 },
> +	{ "adis16500", ADIS16500 },
> +	{ "adis16505-1", ADIS16505_1 },
> +	{ "adis16505-2", ADIS16505_2 },
> +	{ "adis16505-3", ADIS16505_3 },
> +	{ "adis16507-1", ADIS16507_1 },
> +	{ "adis16507-2", ADIS16507_2 },
> +	{ "adis16507-3", ADIS16507_3 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(spi, adis16475_ids);
> +
> +static const struct of_device_id adis16475_of_match[] = {
> +	{ .compatible = "adi,adis16470" },
> +	{ .compatible = "adi,adis16475-1" },
> +	{ .compatible = "adi,adis16475-2" },
> +	{ .compatible = "adi,adis16475-3" },
> +	{ .compatible = "adi,adis16477-1" },
> +	{ .compatible = "adi,adis16477-2" },
> +	{ .compatible = "adi,adis16477-3" },
> +	{ .compatible = "adi,adis16465-1" },
> +	{ .compatible = "adi,adis16465-2" },
> +	{ .compatible = "adi,adis16465-3" },
> +	{ .compatible = "adi,adis16467-1" },
> +	{ .compatible = "adi,adis16467-2" },
> +	{ .compatible = "adi,adis16467-3" },
> +	{ .compatible = "adi,adis16500" },
> +	{ .compatible = "adi,adis16505-1" },
> +	{ .compatible = "adi,adis16505-2" },
> +	{ .compatible = "adi,adis16505-3" },
> +	{ .compatible = "adi,adis16507-1" },
> +	{ .compatible = "adi,adis16507-2" },
> +	{ .compatible = "adi,adis16507-3" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, adis16475_of_match);
> +
> +static struct spi_driver adis16475_driver = {
> +	.driver = {
> +		.name = "adis16475",
> +		.of_match_table = adis16475_of_match,
> +	},
> +	.id_table = adis16475_ids,
> +	.probe = adis16475_probe,
> +};
> +module_spi_driver(adis16475_driver);
> +
> +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
> +MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
> +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-02-25 12:41 ` [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation Nuno Sá
  2020-03-02 22:22   ` Rob Herring
@ 2020-03-03 21:10   ` Jonathan Cameron
  2020-03-04 18:00     ` Sa, Nuno
  1 sibling, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-03 21:10 UTC (permalink / raw)
  To: Nuno Sá
  Cc: linux-iio, devicetree, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Rob Herring, Mark Rutland,
	Alexandru Ardelean, Michael Hennerich

On Tue, 25 Feb 2020 13:41:52 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> Document the ADIS16475 device devicetree bindings.
> 
> Signed-off-by: Nuno Sá <nuno.sa@analog.com>

One thing inline on the burst mode stuff.

Thanks,

Jonathan

> ---
>  .../bindings/iio/imu/adi,adis16475.yaml       | 130 ++++++++++++++++++
>  MAINTAINERS                                   |   1 +
>  2 files changed, 131 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> new file mode 100644
> index 000000000000..c0f2146e000c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices ADIS16475 and similar IMUs
> +
> +maintainers:
> +  - Nuno Sá <nuno.sa@analog.com>
> +
> +description: |
> +  Analog Devices ADIS16475 and similar IMUs
> +  https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> +
> +properties:
> +  compatible:
> +    enum:
> +      - adi,adis16475-1
> +      - adi,adis16475-2
> +      - adi,adis16475-3
> +      - adi,adis16477-1
> +      - adi,adis16477-2
> +      - adi,adis16477-3
> +      - adi,adis16470
> +      - adi,adis16465-1
> +      - adi,adis16465-2
> +      - adi,adis16465-3
> +      - adi,adis16467-1
> +      - adi,adis16467-2
> +      - adi,adis16467-3
> +      - adi,adis16500
> +      - adi,adis16505-1
> +      - adi,adis16505-2
> +      - adi,adis16505-3
> +      - adi,adis16507-1
> +      - adi,adis16507-2
> +      - adi,adis16507-3
> +
> +  reg:
> +    maxItems: 1
> +
> +  spi-cpha: true
> +
> +  spi-cpol: true
> +
> +  spi-max-frequency:
> +    maximum: 2000000
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    oneOf:
> +      - const: sync
> +      - const: direct-sync
> +      - const: pulse-sync
> +      - const: scaled-sync
> +
> +  reset-gpios:
> +    description:
> +      Must be the device tree identifier of the RESET pin. If specified,
> +      it will be asserted during driver probe. As the line is active low,
> +      it should be marked GPIO_ACTIVE_LOW.
> +    maxItems: 1
> +
> +  adi,scaled-output-hz:
> +    description:
> +      This property must be present if the clock mode is scaled-sync through
> +      clock-names property. In this mode, the input clock can have a range
> +      of 1Hz to 128HZ which must be scaled to originate an allowable sample
> +      rate. This property specifies that rate.
> +    minimum: 1900
> +    maximum: 2100
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - spi-cpha
> +  - spi-cpol
> +
> +if:
> +  properties:
> +    compatible:
> +      contains:
> +        enum:
> +          - adi,adis16500
> +          - adi,adis16505-1
> +          - adi,adis16505-2
> +          - adi,adis16505-3
> +          - adi,adis16507-1
> +          - adi,adis16507-2
> +          - adi,adis16507-3
> +
> +then:
> +  properties:
> +    clock-names:
> +      oneOf:
> +        - const: sync
> +        - const: direct-sync
> +        - const: scaled-sync
> +
> +    adi,burst32-enable:
> +      description:
> +        Enable burst32 mode. In this mode, a burst reading contains calibrated
> +        gyroscope and accelerometer data in 32-bit format.

Why is this in DT?  Is it not a runtime decision
(ideally automatically selected)

> +      type: boolean
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    spi {
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            adis16475: adis16475-3@0 {
> +                    compatible = "adi,adis16475-3";
> +                    reg = <0>;
> +                    spi-cpha;
> +                    spi-cpol;
> +                    spi-max-frequency = <2000000>;
> +                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> +                    interrupt-parent = <&gpio>;
> +            };
> +    };
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f11262f1f3bb..f8ccc92ab378 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1015,6 +1015,7 @@ W:	http://ez.analog.com/community/linux-device-drivers
>  S:	Supported
>  F:	drivers/iio/imu/adis16475.c
>  F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> +F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>  
>  ANALOG DEVICES INC ADM1177 DRIVER
>  M:	Beniamin Bia <beniamin.bia@analog.com>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-03 16:34         ` Rob Herring
@ 2020-03-04 17:25           ` Sa, Nuno
  0 siblings, 0 replies; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 17:25 UTC (permalink / raw)
  To: robh
  Cc: linux-iio, devicetree, Ardelean, Alexandru, pmeerw, knaack.h,
	Hennerich, Michael, lars, mark.rutland, jic23

On Tue, 2020-03-03 at 10:34 -0600, Rob Herring wrote:
> On Tue, Mar 3, 2020 at 3:59 AM Sa, Nuno <Nuno.Sa@analog.com> wrote:
> > On Tue, 2020-03-03 at 09:43 +0000, Sa, Nuno wrote:
> > > [External]
> > > 
> > > On Mon, 2020-03-02 at 16:22 -0600, Rob Herring wrote:
> > > > On Tue, Feb 25, 2020 at 01:41:52PM +0100, Nuno Sá wrote:
> > > > > Document the ADIS16475 device devicetree bindings.
> > > > > 
> > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > > > > ---
> > > > >  .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > > > > ++++++++++++++++++
> > > > >  MAINTAINERS                                   |   1 +
> > > > >  2 files changed, 131 insertions(+)
> > > > >  create mode 100644
> > > > > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > > 
> > > > > diff --git
> > > > > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yam
> > > > > l
> > > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yam
> > > > > l
> > > > > new file mode 100644
> > > > > index 000000000000..c0f2146e000c
> > > > > --- /dev/null
> > > > > +++
> > > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yam
> > > > > l
> > > > > @@ -0,0 +1,130 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id: 
> > > > > http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: Analog Devices ADIS16475 and similar IMUs
> > > > > +
> > > > > +maintainers:
> > > > > +  - Nuno Sá <nuno.sa@analog.com>
> > > > > +
> > > > > +description: |
> > > > > +  Analog Devices ADIS16475 and similar IMUs
> > > > > +
> > > > > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > > > > +
> > > > > +properties:
> > > > > +  compatible:
> > > > > +    enum:
> > > > > +      - adi,adis16475-1
> > > > > +      - adi,adis16475-2
> > > > > +      - adi,adis16475-3
> > > > > +      - adi,adis16477-1
> > > > > +      - adi,adis16477-2
> > > > > +      - adi,adis16477-3
> > > > > +      - adi,adis16470
> > > > > +      - adi,adis16465-1
> > > > > +      - adi,adis16465-2
> > > > > +      - adi,adis16465-3
> > > > > +      - adi,adis16467-1
> > > > > +      - adi,adis16467-2
> > > > > +      - adi,adis16467-3
> > > > > +      - adi,adis16500
> > > > > +      - adi,adis16505-1
> > > > > +      - adi,adis16505-2
> > > > > +      - adi,adis16505-3
> > > > > +      - adi,adis16507-1
> > > > > +      - adi,adis16507-2
> > > > > +      - adi,adis16507-3
> > > > > +
> > > > > +  reg:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  spi-cpha: true
> > > > > +
> > > > > +  spi-cpol: true
> > > > > +
> > > > > +  spi-max-frequency:
> > > > > +    maximum: 2000000
> > > > > +
> > > > > +  interrupts:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  clocks:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  clock-names:
> > > > > +    oneOf:
> > > > > +      - const: sync
> > > > > +      - const: direct-sync
> > > > > +      - const: pulse-sync
> > > > > +      - const: scaled-sync
> > > > 
> > > > According to the datasheet I looked at, the input is called
> > > > 'sync'.
> > > > It
> > > > looks like you are mixing operating mode and clock connection.
> > > 
> > > The sync pin is where the external clock should be connected
> > > (when
> > > available). I'm kinda of using the clock-name property as a way
> > > of
> > > selecting the mode the user wants to use as done in other devices
> > > (
> > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/iio/imu/adi,adis16480.txt
> > > ). In the end, what we should have in the sync pin is an external
> > > clock
> > > with the exception of the `sync` mode. I guess this one could be
> > > called
> > > output-sync and, in this case, the sync pin is actually an output
> > > pin
> > > pulsing when the internal processor collects data.
> > > 
> > > I'm ok in changing it if there's a better way of doing it... Do
> > > you
> > > have any suggestion?
> > > 
> > > -Nuno Sá
> > 
> > So, you mean having the clock-name only as "sync" (or maybe even
> > removing it?) and having a dedicated property like clock-mode?
> 
> Yes. Though it needs a vendor prefix: adi,clock-mode. Or perhaps
> adi,sync-mode?

I'm tempted to go with adi,sync-mode to respect the datasheet
terminology. Moreover, when using output-sync mode, the sync pin is an
output pin and there's no external clock. Hence, in this mode, it
actually does not make any sense in giving a clock property. This must
also be fixed in the driver.

- Nuno Sá
> Rob


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] iio: imu: adis: Add Managed device functions
  2020-03-03 20:38   ` Jonathan Cameron
@ 2020-03-04 17:28     ` Sa, Nuno
  0 siblings, 0 replies; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 17:28 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, Hennerich, Michael, devicetree, robh+dt

On Tue, 2020-03-03 at 20:38 +0000, Jonathan Cameron wrote:
> On Tue, 25 Feb 2020 13:41:48 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > This patch adds support for a managed device version of
> > adis_setup_buffer_and_trigger. It works exactly as the original
> > one but it calls all the devm_iio_* functions to setup an iio
> > buffer and trigger. Hence we do not need to care about cleaning
> > those
> > and we do not need to support a remove() callback for every driver
> > using
> > the adis library.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> 
> A few trivial things inline.
> 
> I'm hoping the plan here is to replace all the existing non devm
> versions
> and remove the non devm versions?
> 
> That way we don't end up with a near identical repeated block of
> code.

Honestly, I did not thought about it but I do agree with you. So, we
will have to prepare patches to update all users to use the devm
versions and after that, remove the old versions...

- Nuno Sá
> Thanks,
> 
> Jonathan
> 
> 
> > ---
> >  drivers/iio/imu/adis_buffer.c  | 34 +++++++++++++++++++++++++++++
> >  drivers/iio/imu/adis_trigger.c | 39
> > +++++++++++++++++++++++++++++++---
> >  include/linux/iio/imu/adis.h   | 17 +++++++++++++++
> >  3 files changed, 87 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/iio/imu/adis_buffer.c
> > b/drivers/iio/imu/adis_buffer.c
> > index 3f4dd5c00b03..296036a01d39 100644
> > --- a/drivers/iio/imu/adis_buffer.c
> > +++ b/drivers/iio/imu/adis_buffer.c
> > @@ -196,7 +196,41 @@ int adis_setup_buffer_and_trigger(struct adis
> > *adis, struct iio_dev *indio_dev,
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
> 
> blank line here.
> 
> > +/**
> > + * devm_adis_setup_buffer_and_trigger() - Sets up buffer and
> > trigger for
> > + *					  the managed adis device
> > + * @adis: The adis device
> > + * @indio_dev: The IIO device
> > + * @trigger_handler: Optional trigger handler, may be NULL.
> > + *
> > + * Returns 0 on success, a negative error code otherwise.
> > + *
> > + * This function perfoms exactly the same as
> > adis_setup_buffer_and_trigger()
> > + */
> > +int
> > +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct
> > iio_dev *indio_dev,
> > +				   irqreturn_t (*trigger_handler)(int,
> > void *))
> > +{
> > +	int ret;
> > +
> > +	if (!trigger_handler)
> > +		trigger_handler = adis_trigger_handler;
> > +
> > +	ret = devm_iio_triggered_buffer_setup(&adis->spi->dev,
> > indio_dev,
> > +					      &iio_pollfunc_store_time,
> > +					      trigger_handler, NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (adis->spi->irq) {
> > +		ret = devm_adis_probe_trigger(adis, indio_dev);
> > +		if (ret)
> > +			return ret;
> > +	}
> >  
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger);
> >  /**
> >   * adis_cleanup_buffer_and_trigger() - Free buffer and trigger
> > resources
> >   * @adis: The adis device.
> > diff --git a/drivers/iio/imu/adis_trigger.c
> > b/drivers/iio/imu/adis_trigger.c
> > index 8b9cd02c0f9f..a07dcc365c18 100644
> > --- a/drivers/iio/imu/adis_trigger.c
> > +++ b/drivers/iio/imu/adis_trigger.c
> > @@ -27,6 +27,13 @@ static const struct iio_trigger_ops
> > adis_trigger_ops = {
> >  	.set_trigger_state = &adis_data_rdy_trigger_set_state,
> >  };
> >  
> > +static inline void adis_trigger_setup(struct adis *adis)
> > +{
> > +	adis->trig->dev.parent = &adis->spi->dev;
> > +	adis->trig->ops = &adis_trigger_ops;
> > +	iio_trigger_set_drvdata(adis->trig, adis);
> > +}
> > +
> >  /**
> >   * adis_probe_trigger() - Sets up trigger for a adis device
> >   * @adis: The adis device
> > @@ -45,9 +52,7 @@ int adis_probe_trigger(struct adis *adis, struct
> > iio_dev *indio_dev)
> >  	if (adis->trig == NULL)
> >  		return -ENOMEM;
> >  
> > -	adis->trig->dev.parent = &adis->spi->dev;
> > -	adis->trig->ops = &adis_trigger_ops;
> > -	iio_trigger_set_drvdata(adis->trig, adis);
> > +	adis_trigger_setup(adis);
> >  
> >  	ret = request_irq(adis->spi->irq,
> >  			  &iio_trigger_generic_data_rdy_poll,
> > @@ -72,7 +77,35 @@ int adis_probe_trigger(struct adis *adis, struct
> > iio_dev *indio_dev)
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL_GPL(adis_probe_trigger);
> 
> Blank line here would help a tiny bit on readability.

Got it...

> > +/**
> > + * devm_adis_probe_trigger() - Sets up trigger for a managed adis
> > device
> > + * @adis: The adis device
> > + * @indio_dev: The IIO device
> > + *
> > + * Returns 0 on success or a negative error code
> > + */
> > +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev
> > *indio_dev)
> > +{
> > +	int ret;
> >  
> > +	adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-
> > dev%d",
> > +					    indio_dev->name, indio_dev-
> > >id);
> > +	if (!adis->trig)
> > +		return -ENOMEM;
> > +
> > +	adis_trigger_setup(adis);
> > +
> > +	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
> > +			       &iio_trigger_generic_data_rdy_poll,
> > +			       IRQF_TRIGGER_RISING,
> > +			       indio_dev->name,
> > +			       adis->trig);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return devm_iio_trigger_register(&adis->spi->dev, adis->trig);
> > +}
> > +EXPORT_SYMBOL_GPL(devm_adis_probe_trigger);
> >  /**
> >   * adis_remove_trigger() - Remove trigger for a adis devices
> >   * @adis: The adis device
> > diff --git a/include/linux/iio/imu/adis.h
> > b/include/linux/iio/imu/adis.h
> > index ac7cfd073804..741512b28aaa 100644
> > --- a/include/linux/iio/imu/adis.h
> > +++ b/include/linux/iio/imu/adis.h
> > @@ -419,11 +419,15 @@ struct adis_burst {
> >  	unsigned int	extra_len;
> >  };
> >  
> > +int
> > +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct
> > iio_dev *indio_dev,
> > +				   irqreturn_t (*trigger_handler)(int,
> > void *));
> >  int adis_setup_buffer_and_trigger(struct adis *adis,
> >  	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int,
> > void *));
> >  void adis_cleanup_buffer_and_trigger(struct adis *adis,
> >  	struct iio_dev *indio_dev);
> >  
> > +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev
> > *indio_dev);
> >  int adis_probe_trigger(struct adis *adis, struct iio_dev
> > *indio_dev);
> >  void adis_remove_trigger(struct adis *adis);
> >  
> > @@ -432,6 +436,13 @@ int adis_update_scan_mode(struct iio_dev
> > *indio_dev,
> >  
> >  #else /* CONFIG_IIO_BUFFER */
> >  
> > +static inline int
> > +devm_adis_setup_buffer_and_trigger(struct adis *adis, struct
> > iio_dev *indio_dev,
> > +				   irqreturn_t (*trigger_handler)(int,
> > void *))
> > +{
> > +	return 0;
> > +}
> > +
> >  static inline int adis_setup_buffer_and_trigger(struct adis *adis,
> >  	struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int,
> > void *))
> >  {
> > @@ -443,6 +454,12 @@ static inline void
> > adis_cleanup_buffer_and_trigger(struct adis *adis,
> >  {
> >  }
> >  
> > +static inline int devm_adis_probe_trigger(struct adis *adis,
> > +					  struct iio_dev *indio_dev)
> > +{
> > +	return 0;
> > +}
> > +
> >  static inline int adis_probe_trigger(struct adis *adis,
> >  	struct iio_dev *indio_dev)
> >  {


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] iio: imu: adis: Add irq mask variable
  2020-03-03 20:40   ` Jonathan Cameron
@ 2020-03-04 17:29     ` Sa, Nuno
  0 siblings, 0 replies; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 17:29 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, Hennerich, Michael, devicetree, robh+dt

On Tue, 2020-03-03 at 20:40 +0000, Jonathan Cameron wrote:
> On Tue, 25 Feb 2020 13:41:49 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > There are some ADIS devices that can configure the data ready pin
> > polarity. Hence, we cannot hardcode our IRQ mask as
> > IRQF_TRIGGER_RISING
> > since we might want to have it as IRQF_TRIGGER_FALLING.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> 
> Missing docs for the addition to struct adis.
> 
> Otherwise, looks good to me.

Got it.

- Nuno Sá
> thanks,
> 
> Jonathan
> 
> > ---
> >  drivers/iio/imu/adis_trigger.c | 26 ++++++++++++++++++++++++--
> >  include/linux/iio/imu/adis.h   |  1 +
> >  2 files changed, 25 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/iio/imu/adis_trigger.c
> > b/drivers/iio/imu/adis_trigger.c
> > index a07dcc365c18..ae5a4f66752f 100644
> > --- a/drivers/iio/imu/adis_trigger.c
> > +++ b/drivers/iio/imu/adis_trigger.c
> > @@ -34,6 +34,20 @@ static inline void adis_trigger_setup(struct
> > adis *adis)
> >  	iio_trigger_set_drvdata(adis->trig, adis);
> >  }
> >  
> > +static inline int __adis_validate_irq_mask(struct adis *adis)
> > +{
> > +	if (!adis->irq_mask) {
> > +		adis->irq_mask = IRQF_TRIGGER_RISING;
> > +		return 0;
> > +	} else if (adis->irq_mask != IRQF_TRIGGER_RISING &&
> > +		   adis->irq_mask != IRQF_TRIGGER_FALLING) {
> > +		dev_err(&adis->spi->dev, "Invalid IRQ mask:%08lx\n",
> > +			adis->irq_mask);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> >  /**
> >   * adis_probe_trigger() - Sets up trigger for a adis device
> >   * @adis: The adis device
> > @@ -54,9 +68,13 @@ int adis_probe_trigger(struct adis *adis, struct
> > iio_dev *indio_dev)
> >  
> >  	adis_trigger_setup(adis);
> >  
> > +	ret = __adis_validate_irq_mask(adis);
> > +	if (ret)
> > +		return ret;
> > +
> >  	ret = request_irq(adis->spi->irq,
> >  			  &iio_trigger_generic_data_rdy_poll,
> > -			  IRQF_TRIGGER_RISING,
> > +			  adis->irq_mask,
> >  			  indio_dev->name,
> >  			  adis->trig);
> >  	if (ret)
> > @@ -95,9 +113,13 @@ int devm_adis_probe_trigger(struct adis *adis,
> > struct iio_dev *indio_dev)
> >  
> >  	adis_trigger_setup(adis);
> >  
> > +	ret = __adis_validate_irq_mask(adis);
> > +	if (ret)
> > +		return ret;
> > +
> >  	ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
> >  			       &iio_trigger_generic_data_rdy_poll,
> > -			       IRQF_TRIGGER_RISING,
> > +			       adis->irq_mask,
> >  			       indio_dev->name,
> >  			       adis->trig);
> >  	if (ret)
> > diff --git a/include/linux/iio/imu/adis.h
> > b/include/linux/iio/imu/adis.h
> > index 741512b28aaa..b4c35d137e2a 100644
> > --- a/include/linux/iio/imu/adis.h
> > +++ b/include/linux/iio/imu/adis.h
> > @@ -84,6 +84,7 @@ struct adis {
> >  	struct spi_message	msg;
> >  	struct spi_transfer	*xfer;
> >  	unsigned int		current_page;
> > +	unsigned long		irq_mask;
> 
> This structure has kernel-doc. Please add this new element.
> 
> >  	void			*buffer;
> >  
> >  	uint8_t			tx[10] ____cacheline_aligned;


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/5] iio: adis: Add adis_update_bits() APIs
  2020-03-03 20:48   ` Jonathan Cameron
@ 2020-03-04 17:32     ` Sa, Nuno
  0 siblings, 0 replies; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 17:32 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, Hennerich, Michael, devicetree, robh+dt

On Tue, 2020-03-03 at 20:48 +0000, Jonathan Cameron wrote:
> On Tue, 25 Feb 2020 13:41:50 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > This patch adds a `regmap_update_bits()` like API to the ADIS
> > library.
> > It provides locked and unlocked variant.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> Mostly fine, but I wonder if we can avoid the need to have comments
> on handling of 1 and 8 byte values by explicitly avoiding them
> happening.
> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  drivers/iio/imu/adis.c       | 26 +++++++++++++++
> >  include/linux/iio/imu/adis.h | 61
> > ++++++++++++++++++++++++++++++++++++
> >  2 files changed, 87 insertions(+)
> > 
> > diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
> > index a8afd01de4f3..fa0ee35d96f0 100644
> > --- a/drivers/iio/imu/adis.c
> > +++ b/drivers/iio/imu/adis.c
> > @@ -223,6 +223,32 @@ int __adis_read_reg(struct adis *adis,
> > unsigned int reg,
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL_GPL(__adis_read_reg);
> > +/**
> > + * __adis_update_bits_base() - ADIS Update bits function -
> > Unlocked version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + * @size: Size of the register to update
> > + *
> > + * Updates the desired bits of @reg in accordance with @mask and
> > @val.
> > + */
> > +int __adis_update_bits_base(struct adis *adis, unsigned int reg,
> > const u32 mask,
> > +			    const u32 val, u8 size)
> > +{
> > +	int ret;
> > +	u32 __val;
> > +
> > +	ret = __adis_read_reg(adis, reg, &__val, size);
> > +	if (ret)
> > +		return ret;
> > +
> > +	__val &= ~mask;
> > +	__val |= val & mask;
> > +
> > +	return __adis_write_reg(adis, reg, __val, size);
> > +}
> > +EXPORT_SYMBOL_GPL(__adis_update_bits_base);
> >  
> >  #ifdef CONFIG_DEBUG_FS
> >  
> > diff --git a/include/linux/iio/imu/adis.h
> > b/include/linux/iio/imu/adis.h
> > index b4c35d137e2a..07073f698718 100644
> > --- a/include/linux/iio/imu/adis.h
> > +++ b/include/linux/iio/imu/adis.h
> > @@ -303,6 +303,67 @@ static inline int adis_read_reg_32(struct adis
> > *adis, unsigned int reg,
> >  	return ret;
> >  }
> >  
> > +int __adis_update_bits_base(struct adis *adis, unsigned int reg,
> > const u32 mask,
> > +			    const u32 val, u8 size);
> > +/**
> > + * adis_update_bits_base() - ADIS Update bits function - Locked
> > version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + * @size: Size of the register to update
> > + *
> > + * Updates the desired bits of @reg in accordance with @mask and
> > @val.
> > + */
> > +static inline int adis_update_bits_base(struct adis *adis,
> > unsigned int reg,
> > +					const u32 mask, const u32 val,
> > u8 size)
> > +{
> > +	int ret;
> > +
> > +	mutex_lock(&adis->state_lock);
> > +	ret = __adis_update_bits_base(adis, reg, mask, val, size);
> > +	mutex_unlock(&adis->state_lock);
> > +	return ret;
> > +}
> > +
> > +/**
> > + * adis_update_bits() - Wrapper macro for adis_update_bits_base -
> > Locked version
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + *
> > + * This macro evaluates the sizeof of @val at compile time and
> > calls
> > + * adis_update_bits_base() accordingly. Be aware that using
> > MACROS/DEFINES for
> > + * @val can lead to undesired behavior if the register to update
> > is 16bit. Also
> > + * note that a 64bit value will be treated as an integer. In the
> > same way,
> > + * a char is seen as a short.
> 
> Are these 'edge' conditions desirable?  If not can we use the compile
> time checking tricks to trigger a build failure if they occur?
> BUILD_BUG_ON(sizeof(val) == 1) etc.

So, I guess there's no arm in the 'edge' conditions if users know what
they are doing :). But I have no problems in making/forcing the right
types by adding the compile time checks...

Will add it in v2

- Nuno Sá
> > + */
> > +#define adis_update_bits(adis, reg, mask, val) ({			
> > \
> > +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> > +		adis_update_bits_base(adis, reg, mask, val,
> > 4),         \
> > +		adis_update_bits_base(adis, reg, mask, val, 2));	\
> > +})
> > +
> > +/**
> > + * adis_update_bits() - Wrapper macro for adis_update_bits_base
> > + * @adis: The adis device
> > + * @reg: The address of the lower of the two registers
> > + * @mask: Bitmask to change
> > + * @val: Value to be written
> > + *
> > + * This macro evaluates the sizeof of @val at compile time and
> > calls
> > + * adis_update_bits_base() accordingly. Be aware that using
> > MACROS/DEFINES for
> > + * @val can lead to undesired behavior if the register to update
> > is 16bit. Also
> > + * note that a 64bit value will be treated as an integer. In the
> > same way,
> > + * a char is seen as a short.
> > + */
> > +#define __adis_update_bits(adis, reg, mask, val) ({		
> > 	\
> > +	__builtin_choose_expr(sizeof(val) == 8 || sizeof(val) == 4,	\
> > +		__adis_update_bits_base(adis, reg, mask, val, 4),	\
> > +		__adis_update_bits_base(adis, reg, mask, val, 2));	\
> > +})
> > +
> >  int adis_enable_irq(struct adis *adis, bool enable);
> >  int __adis_check_status(struct adis *adis);
> >  int __adis_initial_startup(struct adis *adis);

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-03-03 21:08   ` Jonathan Cameron
@ 2020-03-04 17:59     ` Sa, Nuno
  2020-03-05  9:58       ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 17:59 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, Hennerich, Michael, devicetree, robh+dt

On Tue, 2020-03-03 at 21:08 +0000, Jonathan Cameron wrote:
> [External]
> 
> On Tue, 25 Feb 2020 13:41:51 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > Support ADIS16475 and similar IMU devices. These devices are
> > a precision, miniature MEMS inertial measurement unit (IMU) that
> > includes a triaxial gyroscope and a triaxial accelerometer. Each
> > inertial sensor combines with signal conditioning that optimizes
> > dynamic performance.
> > 
> > The driver adds support for the following devices:
> >  * adis16470, adis16475, adis16477, adis16465, adis16467,
> > adis16500,
> >    adis16505, adis16507.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> 
> A few bits and pieces inline.
> 
> Thanks,
> 
> Jonathan
> 
> 
> > ---
> >  .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
> >  MAINTAINERS                                   |    8 +
> >  drivers/iio/imu/Kconfig                       |   13 +
> >  drivers/iio/imu/Makefile                      |    1 +
> >  drivers/iio/imu/adis16475.c                   | 1304
> > +++++++++++++++++
> >  5 files changed, 1333 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-
> > adis16475
> >  create mode 100644 drivers/iio/imu/adis16475.c
> > 
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > new file mode 100644
> > index 000000000000..e2c3776035ea
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > @@ -0,0 +1,7 @@
> > +What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_ena
> > ble
> > +KernelVersion:
> > +Contact:	linux-iio@vger.kernel.org
> > +Description:
> > +		Use the device burst read mode when reading buffered
> > +		data. This mode provides a way to read a batch of
> > +		output data registers, using a continuous stream of
> > bits.
> 
> See comment on this below.  I'm not keen on this being exposed to
> userspace
> because it will rarely have any idea how to set it.
> 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 8fa40c3eb72a..f11262f1f3bb 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1008,6 +1008,14 @@ W:	
> > http://ez.analog.com/community/linux-device-drivers
> >  F:	drivers/iio/imu/adis16460.c
> >  F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
> >  
> > +ANALOG DEVICES INC ADIS16475 DRIVER
> > +M:	Nuno Sa <nuno.sa@analog.com>
> > +L:	linux-iio@vger.kernel.org
> > +W:	http://ez.analog.com/community/linux-device-drivers
> > +S:	Supported
> > +F:	drivers/iio/imu/adis16475.c
> > +F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > +
> >  ANALOG DEVICES INC ADM1177 DRIVER
> >  M:	Beniamin Bia <beniamin.bia@analog.com>
> >  M:	Michael Hennerich <Michael.Hennerich@analog.com>
> > diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> > index 60bb1029e759..fc4123d518bc 100644
> > --- a/drivers/iio/imu/Kconfig
> > +++ b/drivers/iio/imu/Kconfig
> > @@ -29,6 +29,19 @@ config ADIS16460
> >  	  To compile this driver as a module, choose M here: the module
> > will be
> >  	  called adis16460.
> >  
> > +config ADIS16475
> > +	tristate "Analog Devices ADIS16475 and similar IMU driver"
> > +	depends on SPI
> > +	select IIO_ADIS_LIB
> > +	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
> > +	help
> > +	  Say yes here to build support for Analog Devices ADIS16470,
> > ADIS16475,
> > +	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505,
> > ADIS16507 inertial
> > +	  sensors.
> > +
> > +	  To compile this driver as a module, choose M here: the module
> > will be
> > +	  called adis16475.
> > +
> >  config ADIS16480
> >  	tristate "Analog Devices ADIS16480 and similar IMU driver"
> >  	depends on SPI
> > diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> > index 5237fd4bc384..88b2c4555230 100644
> > --- a/drivers/iio/imu/Makefile
> > +++ b/drivers/iio/imu/Makefile
> > @@ -6,6 +6,7 @@
> >  # When adding new entries keep the list in alphabetical order
> >  obj-$(CONFIG_ADIS16400) += adis16400.o
> >  obj-$(CONFIG_ADIS16460) += adis16460.o
> > +obj-$(CONFIG_ADIS16475) += adis16475.o
> >  obj-$(CONFIG_ADIS16480) += adis16480.o
> >  
> >  adis_lib-y += adis.o
> > diff --git a/drivers/iio/imu/adis16475.c
> > b/drivers/iio/imu/adis16475.c
> > new file mode 100644
> > index 000000000000..f7c637734ec8
> > --- /dev/null
> > +++ b/drivers/iio/imu/adis16475.c
> > @@ -0,0 +1,1304 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * ADIS16475 IMU driver
> > + *
> > + * Copyright 2019 Analog Devices Inc.
> > + */
> > +#include <asm/unaligned.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/bitops.h>
> > +#include <linux/clk.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/kernel.h>
> > +#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/module.h>
> > +#include <linux/spi/spi.h>
> > +
> > +#define ADIS16475_REG_DIAG_STAT		0x02
> > +#define ADIS16475_REG_X_GYRO_L		0x04
> > +#define ADIS16475_REG_Y_GYRO_L		0x08
> > +#define ADIS16475_REG_Z_GYRO_L		0x0C
> > +#define ADIS16475_REG_X_ACCEL_L		0x10
> > +#define ADIS16475_REG_Y_ACCEL_L		0x14
> > +#define ADIS16475_REG_Z_ACCEL_L		0x18
> > +#define ADIS16475_REG_TEMP_OUT		0x1c
> > +#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
> > +#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
> > +#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
> > +#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
> > +#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
> > +#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
> > +#define ADIS16475_REG_FILT_CTRL		0x5c
> > +#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
> > +#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FI
> > LT_CTRL_MASK, x)
> > +#define ADIS16475_REG_MSG_CTRL		0x60
> > +#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
> > +#define ADIS16475_MSG_CTRL_DR_POL(x) \
> > +				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MA
> > SK, x)
> > +#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
> > +#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EX
> > T_CLK_MASK, x)
> > +#define ADIS16475_REG_UP_SCALE		0x62
> > +#define ADIS16475_REG_DEC_RATE		0x64
> > +#define ADIS16475_REG_GLOB_CMD		0x68
> > +#define ADIS16475_REG_FIRM_REV		0x6c
> > +#define ADIS16475_REG_FIRM_DM		0x6e
> > +#define ADIS16475_REG_FIRM_Y		0x70
> > +#define ADIS16475_REG_PROD_ID		0x72
> > +#define ADIS16475_REG_SERIAL_NUM	0x74
> > +#define ADIS16475_REG_FLASH_CNT		0x7c
> > +#define ADIS16500_BURST32_MASK		BIT(9)
> > +#define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BU
> > RST32_MASK, x)
> > +/* number of data elements in burst mode */
> > +#define ADIS16475_BURST_MAX_DATA	10
> > +#define ADIS16475_MAX_SCAN_DATA		15
> > +
> > +enum clk_mode {
> > +	ADIS16475_CLK_DIRECT = 1,
> > +	ADIS16475_CLK_SCALED,
> > +	ADIS16475_CLK_OUTPUT,
> > +	ADIS16475_CLK_PULSE = 5,
> > +};
> > +
> > +struct adis16475_clks {
> > +	const char *name;
> > +	enum clk_mode clk_mode;
> > +	u16 min_rate;
> > +	u16 max_rate;
> > +};
> > +
> > +struct adis16475_chip_info {
> > +	const struct iio_chan_spec *channels;
> > +	const struct adis16475_clks *clks;
> > +	const struct adis_data adis_data;
> > +	u32 num_channels;
> > +	u32 gyro_max_val;
> > +	u32 gyro_max_scale;
> > +	u32 accel_max_val;
> > +	u32 accel_max_scale;
> > +	u32 temp_scale;
> > +	u32 int_clk;
> > +	u16 max_dec;
> > +	u8 num_clks;
> > +	bool has_burst32;
> > +};
> > +
> > +struct adis16475 {
> > +	const struct adis16475_chip_info *info;
> > +	struct adis adis;
> > +	u32 clk_freq;
> > +	u32 cached_spi_speed_hz;
> > +	bool burst32;
> > +};
> > +
> > +enum {
> > +	ADIS16475_SCAN_GYRO_X,
> > +	ADIS16475_SCAN_GYRO_Y,
> > +	ADIS16475_SCAN_GYRO_Z,
> > +	ADIS16475_SCAN_ACCEL_X,
> > +	ADIS16475_SCAN_ACCEL_Y,
> > +	ADIS16475_SCAN_ACCEL_Z,
> > +	ADIS16475_SCAN_TEMP,
> > +	ADIS16475_SCAN_DIAG_S_FLAGS,
> > +	ADIS16475_SCAN_CRC_FAILURE,
> > +};
> > +
> > +#ifdef CONFIG_DEBUG_FS
> > +static ssize_t adis16475_show_firmware_revision(struct file *file,
> > +						char __user *userbuf,
> > +						size_t count, loff_t
> > *ppos)
> > +{
> > +	struct adis16475 *st = file->private_data;
> > +	char buf[7];
> > +	size_t len;
> > +	u16 rev;
> > +	int ret;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV,
> > &rev);
> > +	if (ret)
> > +		return ret;
> > +
> > +	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev &
> > 0xff);
> > +
> > +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> > +}
> > +
> > +static const struct file_operations
> > adis16475_firmware_revision_fops = {
> > +	.open = simple_open,
> > +	.read = adis16475_show_firmware_revision,
> > +	.llseek = default_llseek,
> > +	.owner = THIS_MODULE,
> > +};
> > +
> > +static ssize_t adis16475_show_firmware_date(struct file *file,
> > +					    char __user *userbuf,
> > +					    size_t count, loff_t *ppos)
> > +{
> > +	struct adis16475 *st = file->private_data;
> > +	u16 md, year;
> > +	char buf[12];
> > +	size_t len;
> > +	int ret;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
> > +	if (ret)
> > +		return ret;
> > +
> > +	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8,
> > md & 0xff,
> > +		       year);
> > +
> > +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> > +}
> > +
> > +static const struct file_operations adis16475_firmware_date_fops =
> > {
> > +	.open = simple_open,
> > +	.read = adis16475_show_firmware_date,
> > +	.llseek = default_llseek,
> > +	.owner = THIS_MODULE,
> > +};
> > +
> > +static int adis16475_show_serial_number(void *arg, u64 *val)
> > +{
> > +	struct adis16475 *st = arg;
> > +	u16 serial;
> > +	int ret;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM,
> > &serial);
> > +	if (ret)
> > +		return ret;
> > +
> > +	*val = serial;
> > +
> > +	return 0;
> > +}
> > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
> > +			adis16475_show_serial_number, NULL,
> > "0x%.4llx\n");
> > +
> > +static int adis16475_show_product_id(void *arg, u64 *val)
> > +{
> > +	struct adis16475 *st = arg;
> > +	u16 prod_id;
> > +	int ret;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID,
> > &prod_id);
> > +	if (ret)
> > +		return ret;
> > +
> > +	*val = prod_id;
> > +
> > +	return 0;
> > +}
> > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
> > +			adis16475_show_product_id, NULL, "%llu\n");
> > +
> > +static int adis16475_show_flash_count(void *arg, u64 *val)
> > +{
> > +	struct adis16475 *st = arg;
> > +	u32 flash_count;
> > +	int ret;
> > +
> > +	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
> > +			       &flash_count);
> > +	if (ret)
> > +		return ret;
> > +
> > +	*val = flash_count;
> > +
> > +	return 0;
> > +}
> > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
> > +			adis16475_show_flash_count, NULL, "%lld\n");
> > +
> > +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> > +{
> > +	struct adis16475 *st = iio_priv(indio_dev);
> > +
> > +	debugfs_create_file("serial_number", 0400, indio_dev-
> > >debugfs_dentry,
> > +			    st, &adis16475_serial_number_fops);
> > +	debugfs_create_file("product_id", 0400, indio_dev-
> > >debugfs_dentry, st,
> > +			    &adis16475_product_id_fops);
> > +	debugfs_create_file("flash_count", 0400, indio_dev-
> > >debugfs_dentry, st,
> > +			    &adis16475_flash_count_fops);
> > +	debugfs_create_file("firmware_revision", 0400,
> > +			    indio_dev->debugfs_dentry, st,
> > +			    &adis16475_firmware_revision_fops);
> > +	debugfs_create_file("firmware_date", 0400, indio_dev-
> > >debugfs_dentry,
> > +			    st, &adis16475_firmware_date_fops);
> > +	return 0;
> > +}
> > +#else
> > +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> > +{
> > +	return 0;
> > +}
> > +#endif
> > +
> > +static ssize_t adis16475_burst_mode_enable_get(struct device *dev,
> > +					       struct device_attribute
> > *attr,
> > +					       char *buf)
> > +{
> > +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> > +
> > +	return sprintf(buf, "%d\n", st->adis.burst->en);
> > +}
> > +
> > +static ssize_t adis16475_burst_mode_enable_set(struct device *dev,
> > +					       struct device_attribute
> > *attr,
> > +					       const char *buf, size_t
> > len)
> > +{
> > +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> > +	bool val;
> > +	int ret;
> > +
> > +	ret = kstrtobool(buf, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (val)
> > +		/* 1MHz max in burst mode */
> > +		st->adis.spi->max_speed_hz = 1000000;
> > +	else
> > +		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
> > +
> > +	st->adis.burst->en = val;
> > +
> > +	return len;
> > +}
> > +
> > +static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
> > +		       adis16475_burst_mode_enable_get,
> > +		       adis16475_burst_mode_enable_set, 0);
> > +
> > +static struct attribute *adis16475_attributes[] = {
> > +	&iio_dev_attr_burst_mode_enable.dev_attr.attr,
> 
> Hmm.  Normally we try to avoid exposing this and make the decision
> automatically based on which channels are enabled.

Hmm. In that case, the decision would probably have to go to the
library since it is there that the "preparations" for buffered mode are
done. Mostly, the data we are interested in the burst data is gyro,
accel and temp. So to make the decision based on which channels are
enabled is not that straight. Should we enable it only when all
channels are enabled? Some of them (and which)?

I guess that the only case where not using burst mode is faster is
__maybe__ when only reading one channel (even then Im not sure...).
Hence, I'm kind of thinking in the cynical approach :).

However, I was also using this to handle the spi max_speed_hz since we
have some limitations in burst mode. I have two thoughts here:

1) We handle this in the trigger handler, before doing the spi transfer
2) Just set the spi max_speed_hz to the one allowed by burst mode in
the devicetree.

Any preference?
> If more cynical we decide that no one buys and expensive sensor only
> to read a few of it's channels, so we turn on burst mode all the time
> :)
> 
> > +	NULL,
> > +};
> > +
> > +static const struct attribute_group adis16495_attribute_group = {
> > +	.attrs = adis16475_attributes,
> > +};
> > +
> > +static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
> > +{
> > +	int ret;
> > +	u16 dec;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE,
> > &dec);
> > +	if (ret)
> > +		return -EINVAL;
> > +
> > +	*freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1);
> > +
> > +	return 0;
> > +}
> > +
> > +static int adis16475_set_freq(struct adis16475 *st, const u32
> > freq)
> > +{
> > +	u16 dec;
> > +
> > +	if (freq == 0 || freq > st->clk_freq)
> > +		return -EINVAL;
> > +
> > +	dec = DIV_ROUND_CLOSEST(st->clk_freq, freq);
> > +
> > +	if (dec)
> > +		dec--;
> > +
> > +	if (dec > st->info->max_dec)
> > +		dec = st->info->max_dec;
> > +
> > +	return adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE,
> > dec);
> > +}
> > +
> > +/* The values are approximated. */
> > +static const u32 adis16475_3db_freqs[] = {
> > +	[0] = 720, /* Filter disabled, full BW (~720Hz) */
> > +	[1] = 360,
> > +	[2] = 164,
> > +	[3] = 80,
> > +	[4] = 40,
> > +	[5] = 20,
> > +	[6] = 10,
> > +	[7] = 10, /* not a valid setting */
> > +};
> > +
> > +static int adis16475_get_filter(struct adis16475 *st, u32 *filter)
> > +{
> > +	u16 filter_sz;
> > +	int ret;
> > +	const int mask = ADIS16475_FILT_CTRL_MASK;
> > +
> > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
> > &filter_sz);
> > +	if (ret)
> > +		return ret;
> > +
> > +	*filter = adis16475_3db_freqs[filter_sz & mask];
> > +
> > +	return 0;
> > +}
> > +
> > +static int adis16475_set_filter(struct adis16475 *st, const u32
> > filter)
> > +{
> > +	int i;
> > +
> > +	for (i = ARRAY_SIZE(adis16475_3db_freqs) - 1; i >= 1; i--) {
> > +		if (adis16475_3db_freqs[i] >= filter)
> > +			break;
> > +	}
> > +
> > +	return adis_write_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
> > +				 ADIS16475_FILT_CTRL(i));
> > +}
> > +
> > +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,
> > +	[ADIS16475_SCAN_GYRO_Z] = ADIS16475_REG_Z_GYRO_BIAS_L,
> > +	[ADIS16475_SCAN_ACCEL_X] = ADIS16475_REG_X_ACCEL_BIAS_L,
> > +	[ADIS16475_SCAN_ACCEL_Y] = ADIS16475_REG_Y_ACCEL_BIAS_L,
> > +	[ADIS16475_SCAN_ACCEL_Z] = ADIS16475_REG_Z_ACCEL_BIAS_L,
> > +};
> > +
> > +static int adis16475_read_raw(struct iio_dev *indio_dev,
> > +			      const struct iio_chan_spec *chan,
> > +			      int *val, int *val2, long info)
> > +{
> > +	struct adis16475 *st = iio_priv(indio_dev);
> > +	int ret;
> > +	u32 tmp;
> > +
> > +	switch (info) {
> > +	case IIO_CHAN_INFO_RAW:
> > +		return adis_single_conversion(indio_dev, chan, 0, val);
> > +	case IIO_CHAN_INFO_SCALE:
> > +		switch (chan->type) {
> > +		case IIO_ANGL_VEL:
> > +			*val = st->info->gyro_max_val;
> > +			*val2 = st->info->gyro_max_scale;
> > +			return IIO_VAL_FRACTIONAL;
> > +		case IIO_ACCEL:
> > +			*val = st->info->accel_max_val;
> > +			*val2 = st->info->accel_max_scale;
> > +			return IIO_VAL_FRACTIONAL;
> > +		case IIO_TEMP:
> > +			*val = st->info->temp_scale;
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_CALIBBIAS:
> > +		ret = adis_read_reg_32(&st->adis,
> > +				       adis16475_calib_regs[chan-
> > >scan_index],
> > +				       val);
> > +		break;
> > +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> > +		ret = adis16475_get_filter(st, val);
> > +		break;
> > +	case IIO_CHAN_INFO_SAMP_FREQ:
> > +		ret = adis16475_get_freq(st, &tmp);
> > +		if (ret)
> > +			return ret;
> > +
> > +		*val = tmp / 1000;
> > +		*val2 = (tmp % 1000) * 1000;
> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (ret)
> > +		return ret;
> 
> Better to put this inline after each ret = section and return
> directly from those.
> As it stands the code paths are rather inconsistent.

Got it...

> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int adis16475_write_raw(struct iio_dev *indio_dev,
> > +			       const struct iio_chan_spec *chan,
> > +			       int val, int val2, long info)
> > +{
> > +	struct adis16475 *st = iio_priv(indio_dev);
> > +	u32 tmp;
> > +
> > +	switch (info) {
> > +	case IIO_CHAN_INFO_SAMP_FREQ:
> > +		tmp = val * 1000 + val2 / 1000;
> > +		return adis16475_set_freq(st, tmp);
> > +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> > +		return adis16475_set_filter(st, val);
> > +	case IIO_CHAN_INFO_CALIBBIAS:
> > +		return adis_write_reg_32(&st->adis,
> > +					 adis16475_calib_regs[chan-
> > >scan_index],
> > +					 val);
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +#define ADIS16475_MOD_CHAN(_type, _mod, _address, _si, _r_bits,
> > _s_bits) \
> > +	{ \
> > +		.type = (_type), \
> > +		.modified = 1, \
> > +		.channel2 = (_mod), \
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > +			BIT(IIO_CHAN_INFO_CALIBBIAS), \
> > +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> > +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)
> > | \
> > +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY
> > ), \
> > +		.address = (_address), \
> > +		.scan_index = (_si), \
> > +		.scan_type = { \
> > +			.sign = 's', \
> > +			.realbits = (_r_bits), \
> > +			.storagebits = (_s_bits), \
> > +			.endianness = IIO_BE, \
> > +		}, \
> > +	}
> > +
> > +#define ADIS16475_GYRO_CHANNEL(_mod) \
> > +	ADIS16475_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
> > +	ADIS16475_REG_ ## _mod ## _GYRO_L, ADIS16475_SCAN_GYRO_ ##
> > _mod, 32, \
> > +	32)
> > +
> > +#define ADIS16475_ACCEL_CHANNEL(_mod) \
> > +	ADIS16475_MOD_CHAN(IIO_ACCEL, IIO_MOD_ ## _mod, \
> > +	ADIS16475_REG_ ## _mod ## _ACCEL_L, ADIS16475_SCAN_ACCEL_ ##
> > _mod, 32, \
> > +	32)
> > +
> > +#define ADIS16475_TEMP_CHANNEL() { \
> > +		.type = IIO_TEMP, \
> > +		.indexed = 1, \
> > +		.channel = 0, \
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > +			BIT(IIO_CHAN_INFO_SCALE), \
> > +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)
> > | \
> > +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY
> > ), \
> > +		.address = ADIS16475_REG_TEMP_OUT, \
> > +		.scan_index = ADIS16475_SCAN_TEMP, \
> > +		.scan_type = { \
> > +			.sign = 's', \
> > +			.realbits = 16, \
> > +			.storagebits = 16, \
> > +			.endianness = IIO_BE, \
> > +		}, \
> > +	}
> > +
> > +static const struct iio_chan_spec adis16475_channels[] = {
> > +	ADIS16475_GYRO_CHANNEL(X),
> > +	ADIS16475_GYRO_CHANNEL(Y),
> > +	ADIS16475_GYRO_CHANNEL(Z),
> > +	ADIS16475_ACCEL_CHANNEL(X),
> > +	ADIS16475_ACCEL_CHANNEL(Y),
> > +	ADIS16475_ACCEL_CHANNEL(Z),
> > +	ADIS16475_TEMP_CHANNEL(),
> > +	IIO_CHAN_SOFT_TIMESTAMP(9)
> > +};
> > +
> > +enum adis16475_variant {
> > +	ADIS16470,
> > +	ADIS16475_1,
> > +	ADIS16475_2,
> > +	ADIS16475_3,
> > +	ADIS16477_1,
> > +	ADIS16477_2,
> > +	ADIS16477_3,
> > +	ADIS16465_1,
> > +	ADIS16465_2,
> > +	ADIS16465_3,
> > +	ADIS16467_1,
> > +	ADIS16467_2,
> > +	ADIS16467_3,
> > +	ADIS16500,
> > +	ADIS16505_1,
> > +	ADIS16505_2,
> > +	ADIS16505_3,
> > +	ADIS16507_1,
> > +	ADIS16507_2,
> > +	ADIS16507_3,
> > +
> > +};
> > +
> > +enum {
> > +	ADIS16475_DIAG_STAT_DATA_PATH = 1,
> > +	ADIS16475_DIAG_STAT_FLASH_MEM,
> > +	ADIS16475_DIAG_STAT_SPI,
> > +	ADIS16475_DIAG_STAT_STANDBY,
> > +	ADIS16475_DIAG_STAT_SENSOR,
> > +	ADIS16475_DIAG_STAT_MEMORY,
> > +	ADIS16475_DIAG_STAT_CLK,
> > +};
> > +
> > +static const char * const adis16475_status_error_msgs[] = {
> > +	[ADIS16475_DIAG_STAT_DATA_PATH] = "Data Path Overrun",
> > +	[ADIS16475_DIAG_STAT_FLASH_MEM] = "Flash memory update
> > failure",
> > +	[ADIS16475_DIAG_STAT_SPI] = "SPI communication error",
> > +	[ADIS16475_DIAG_STAT_STANDBY] = "Standby mode",
> > +	[ADIS16475_DIAG_STAT_SENSOR] = "Sensor failure",
> > +	[ADIS16475_DIAG_STAT_MEMORY] = "Memory failure",
> > +	[ADIS16475_DIAG_STAT_CLK] = "Clock error",
> > +};
> > +
> > +static int adis16475_enable_irq(struct adis *adis, bool enable)
> > +{
> > +	/*
> > +	 * There is no way to gate the data-ready signal internally
> > inside the
> > +	 * ADIS16475. We can only control it's polarity...
> > +	 */
> > +	if (enable)
> > +		enable_irq(adis->spi->irq);
> > +	else
> > +		disable_irq(adis->spi->irq);
> > +
> > +	return 0;
> > +}
> > +
> > +#define ADIS16475_DATA(_prod_id, _timeouts)			
> > 	\
> > +{									
> > \
> > +	.msc_ctrl_reg = ADIS16475_REG_MSG_CTRL,				
> > \
> > +	.glob_cmd_reg = ADIS16475_REG_GLOB_CMD,				
> > \
> > +	.diag_stat_reg = ADIS16475_REG_DIAG_STAT,			\
> > +	.prod_id_reg = ADIS16475_REG_PROD_ID,				
> > \
> > +	.prod_id = (_prod_id),						
> > \
> > +	.self_test_mask = BIT(2),					\
> > +	.self_test_reg = ADIS16475_REG_GLOB_CMD,			\
> > +	.cs_change_delay = 16,						
> > \
> > +	.read_delay = 5,						\
> > +	.write_delay = 5,						\
> > +	.status_error_msgs = adis16475_status_error_msgs,		\
> > +	.status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) |	\
> > +		BIT(ADIS16475_DIAG_STAT_FLASH_MEM) |			
> > \
> > +		BIT(ADIS16475_DIAG_STAT_SPI) |				
> > \
> > +		BIT(ADIS16475_DIAG_STAT_STANDBY) |			\
> > +		BIT(ADIS16475_DIAG_STAT_SENSOR) |			\
> > +		BIT(ADIS16475_DIAG_STAT_MEMORY) |			\
> > +		BIT(ADIS16475_DIAG_STAT_CLK),				
> > \
> > +	.enable_irq = adis16475_enable_irq,				\
> > +	.timeouts = (_timeouts),					\
> > +}
> > +
> > +static const struct adis16475_clks adis16475_ext_clks[] = {
> > +	{ "sync", ADIS16475_CLK_OUTPUT, 1900, 2100 },
> > +	{ "direct-sync", ADIS16475_CLK_DIRECT, 1900, 2100 },
> > +	{ "scaled-sync", ADIS16475_CLK_SCALED, 1, 128 },
> > +	{ "pulse-sync", ADIS16475_CLK_PULSE, 1000, 2100 },
> 
> Rob already commented on this so I'll not bother :)

I will change the name to adis16475_sync...

> > +};
> > +
> > +static const struct adis_timeout adis16475_timeouts = {
> > +	.reset_ms = 200,
> > +	.sw_reset_ms = 200,
> > +	.self_test_ms = 20,
> > +};
> > +
> > +static const struct adis_timeout adis1650x_timeouts = {
> > +	.reset_ms = 260,
> > +	.sw_reset_ms = 260,
> > +	.self_test_ms = 30,
> > +};
> > +
> > +static const struct adis16475_chip_info adis16475_chip_info[] = {
> > +	[ADIS16470] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16470,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16475_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16475,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16475_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16475,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16475_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16475,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16477_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16477,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16477_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16477,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16477_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16477,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16465_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16465,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16465_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16465,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16465_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16465,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16467_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16467,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16467_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16467,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16467_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 1,
> > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > +		.adis_data = ADIS16475_DATA(16467,
> > &adis16475_timeouts),
> > +	},
> > +	[ADIS16500] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 392,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16500,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16505_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 78,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16505,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16505_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 78,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16505,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16505_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 78,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16505,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16507_1] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > +		.accel_max_val = 392,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16507,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16507_2] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > +		.accel_max_val = 392,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16507,
> > &adis1650x_timeouts),
> > +	},
> > +	[ADIS16507_3] = {
> > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > +		.channels = adis16475_channels,
> > +		.gyro_max_val = 1,
> > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > +		.accel_max_val = 392,
> > +		.accel_max_scale = 32000 << 16,
> > +		.temp_scale = 100,
> > +		.int_clk = 2000,
> > +		.max_dec = 1999,
> > +		.clks = adis16475_ext_clks,
> > +		/* pulse sync not supported */
> > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > +		.has_burst32 = true,
> > +		.adis_data = ADIS16475_DATA(16507,
> > &adis1650x_timeouts),
> > +	},
> > +};
> > +
> > +static const struct iio_info adis16475_info = {
> > +	.read_raw = &adis16475_read_raw,
> > +	.write_raw = &adis16475_write_raw,
> > +	.update_scan_mode = adis_update_scan_mode,
> > +	.attrs = &adis16495_attribute_group,
> > +	.debugfs_reg_access = adis_debugfs_reg_access,
> > +};
> > +
> > +static struct adis_burst adis16475_burst = {
> > +	.en = true,
> > +	.reg_cmd = ADIS16475_REG_GLOB_CMD,
> > +	/*
> > +	 * adis_update_scan_mode_burst() sets the burst length in
> > respect with
> > +	 * the number of channels and allocates 16 bits for each.
> > However,
> > +	 * adis1647x devices also need space for DIAG_STAT, DATA_CNTR
> > or
> > +	 * TIME_STAMP (depending on the clock mode but for us these
> > bytes are
> > +	 * don't care...) and CRC.
> > +	 */
> > +	.extra_len = 3 * sizeof(u16),
> > +};
> > +
> > +static u16 adis16475_validate_crc(const u8 *buffer, const u16 crc,
> > +				  const bool burst32)
> > +{
> > +	int i;
> > +	u16 __crc = 0;
> > +
> > +	/* extra 6 elements for low gyro and accel */
> > +	const u16 sz = burst32 ? ADIS16475_BURST_MAX_DATA + 6 :
> > +		ADIS16475_BURST_MAX_DATA;
> > +
> > +	for (i = 0; i < sz * 2 - 2; i++)
> > +		__crc += buffer[i];
> > +
> > +	return (__crc != crc);
> > +}
> > +
> > +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);
> > +	struct adis *adis = &st->adis;
> > +	int ret, bit, i = 0;
> > +	u16 crc, data[ADIS16475_MAX_SCAN_DATA], *buffer, crc_res;
> > +	/* offset until the first element after gyro and accel */
> > +	const u8 offset = st->burst32 ? 13 : 7;
> > +
> > +	ret = spi_sync(adis->spi, &adis->msg);
> > +	if (ret)
> > +		return ret;
> > +
> > +	buffer = (u16 *)adis->buffer;
> > +
> > +	if (!(adis->burst && adis->burst->en))
> > +		goto push_to_buffers;
> > +
> > +	/* We always validate the crc to at least print a message */
> > +	crc = get_unaligned_be16(&buffer[offset + 2]);
> > +	crc_res = adis16475_validate_crc((u8 *)adis->buffer, crc,
> > +					 st->burst32);
> > +	if (crc_res)
> > +		dev_err(&adis->spi->dev, "Invalid crc\n");
> > +
> > +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> > +			 indio_dev->masklength) {
> > +		/*
> > +		 * When burst mode is used, system flags is the first
> > data
> > +		 * channel in the sequence, but the scan index is 7.
> > +		 */
> > +		switch (bit) {
> > +		case ADIS16475_SCAN_TEMP:
> > +			data[i++] = get_unaligned(&buffer[offset]);
> > +			break;
> > +		case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
> > +			/*
> > +			 * The first 2 bytes on the received data are
> > the
> > +			 * DIAG_STAT reg, hence the +1 offset here...
> > +			 */
> > +			if (st->burst32) {
> > +				/* upper 16 */
> > +				data[i++] = get_unaligned(&buffer[bit *
> > 2 + 2]);
> > +				/* lower 16 */
> > +				data[i++] = get_unaligned(&buffer[bit *
> > 2 + 1]);
> > +			} else {
> > +				data[i++] = get_unaligned(&buffer[bit +
> > 1]);
> > +				/* lower not used */
> > +				data[i++] = 0;
> > +			}
> > +			break;
> > +		}
> > +	}
> > +
> > +	buffer = data;
> > +
> > +push_to_buffers:
> > +	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf-
> > >timestamp);
> 
> I'm not sure data is the right size.  It needs to have space to have
> an aligned
> timestamp at the end.

Will double check this... Honestly I did not had the timestamp into
account so the size is probably wrong.

> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static void adis16475_disable_clk(void *data)
> > +{
> > +	clk_disable_unprepare((struct clk *)data);
> > +}
> > +
> > +static int adis16475_config_ext_clk(struct adis16475 *st)
> > +{
> > +	int ret;
> > +	int i;
> > +	struct device *dev = &st->adis.spi->dev;
> > +	const struct adis16475_clks *ext_clks = st->info->clks;
> > +
> > +	for (i = 0; i < st->info->num_clks; i++) {
> > +		u16 mode = ADIS16475_EXT_CLK(ext_clks[i].clk_mode);
> > +		struct clk *clk = devm_clk_get(dev, ext_clks[i].name);
> > +
> > +		if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT)
> > +			return PTR_ERR(clk);
> > +		else if (IS_ERR(clk))
> > +			continue;
> > +
> > +		ret = clk_prepare_enable(clk);
> > +		if (ret)
> > +			return ret;
> > +
> > +		ret = devm_add_action_or_reset(dev,
> > adis16475_disable_clk, clk);
> > +		if (ret)
> > +			return ret;
> > +
> > +		st->clk_freq = clk_get_rate(clk);
> > +		if (st->clk_freq < ext_clks[i].min_rate ||
> > +		    st->clk_freq > ext_clks[i].max_rate) {
> > +			dev_err(dev,
> > +				"Clk rate:%u not in a valid range:[%u
> > %u]\n",
> > +				st->clk_freq, ext_clks[i].min_rate,
> > +				ext_clks[i].max_rate);
> > +			return -EINVAL;
> > +		}
> > +
> > +		if (ext_clks[i].clk_mode == ADIS16475_CLK_SCALED) {
> > +			u16 up_scale;
> > +			u32 scaled_out_freq = 0;
> > +			/*
> > +			 * If we are in scaled mode, we must have an
> > up_scale.
> > +			 * In scaled mode the allowable input clock
> > range is
> > +			 * 1 Hz to 128 Hz, and the allowable output
> > range is
> > +			 * 1900 to 2100 Hz. Hence, a scale must be
> > given to
> > +			 * get the allowable output.
> > +			 */
> > +			device_property_read_u32(dev, "adi,scaled-
> > output-hz",
> > +						 &scaled_out_freq);
> > +
> > +			if (scaled_out_freq < 1900 || scaled_out_freq >
> > 2100) {
> > +				dev_err(dev,
> > +					"Invalid value:%u for
> > adi,scaled-output-hz",
> > +					scaled_out_freq);
> > +				return -EINVAL;
> > +			}
> > +
> > +			up_scale = DIV_ROUND_CLOSEST(scaled_out_freq,
> > +						     st->clk_freq);
> > +
> > +			ret = __adis_write_reg_16(&st->adis,
> > +						  ADIS16475_CLK_SCALED,
> > +						  up_scale);
> > +			if (ret)
> > +				return ret;
> > +
> > +			st->clk_freq = scaled_out_freq;
> > +		}
> > +		/*
> > +		 * Keep in mind that the mask for the clk modes in
> > adis1650*
> > +		 * chips is different (1100 instead of 11100). However,
> > we
> > +		 * are not configuring BIT(4) in these chips and the
> > default
> > +		 * value is 0, so we are fine in doing the below
> > operations.
> > +		 * I'm keeping this for simplicity and avoiding extra
> > variables
> > +		 * in chip_info.
> > +		 */
> > +		ret = __adis_update_bits(&st->adis,
> > ADIS16475_REG_MSG_CTRL,
> > +					 ADIS16475_EXT_CLK_MASK, mode);
> > +		if (ret)
> > +			return ret;
> > +
> > +		usleep_range(250, 260);
> > +
> > +		break;
> > +	}
> > +
> > +	if (i == st->info->num_clks)
> > +		/* internal clk */
> > +		st->clk_freq = st->info->int_clk;
> > +
> > +	st->clk_freq *= 1000;
> > +
> > +	return 0;
> > +}
> > 
> > +static int adis16475_config_irq_pin(struct adis16475 *st)
> > +{
> > +	int ret;
> > +	struct irq_data *desc;
> > +	u32 irq_type;
> > +	u16 val = 0;
> > +	u8 polarity;
> > +	struct spi_device *spi = st->adis.spi;
> > +
> > +	desc = irq_get_irq_data(spi->irq);
> > +	if (!desc) {
> > +		dev_err(&spi->dev, "Could not find IRQ %d\n", spi-
> > >irq);
> > +		return -EINVAL;
> > +	}
> > +	/*
> > +	 * It is possible to configure the data ready polarity.
> > Furthermore, we
> > +	 * need to update the adis struct if we want data ready as
> > active low.
> > +	 */
> > +	irq_type = irqd_get_trigger_type(desc);
> > +	if (irq_type == IRQF_TRIGGER_RISING) {
> > +		polarity = 1;
> > +	} else if (irq_type == IRQF_TRIGGER_FALLING) {
> > +		polarity = 0;
> > +		st->adis.irq_mask = IRQF_TRIGGER_FALLING;
> > +	} else {
> > +		dev_err(&spi->dev, "Invalid interrupt type 0x%x
> > specified\n",
> > +			irq_type);
> > +		return -EINVAL;
> > +	}
> > +
> > +	val = ADIS16475_MSG_CTRL_DR_POL(polarity);
> > +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> > +				 ADIS16475_MSG_CTRL_DR_POL_MASK, val);
> > +	if (ret)
> > +		return ret;
> > +	/*
> > +	 * There is a delay writing to any bits written to the MSC_CTRL
> > +	 * register. It should not be bigger than 200us, so 250 should
> > be more
> > +	 * than enough!
> > +	 */
> > +	usleep_range(250, 260);
> > +
> > +	return 0;
> > +}
> > +
> > +static int adis16475_burst_config(struct adis16475 *st)
> > +{
> > +	const u16 burst32 = ADIS16500_BURST32(1);
> > +	int ret;
> > +
> > +	st->burst32 = device_property_read_bool(&st->adis.spi->dev,
> > +						"adi,burst32-enable");
> > +	if (!st->burst32)
> > +		goto burst16;
> A forwards goto like this on a non error condition, is a bit unusual.
> While it involves more indenting I would still prefer the logic
> flipped

Honestly I find it more readable (to me) like this. But I do agree it's
not that usual. Will change it...

> 	if (st->burst32) {
> 
> 	}
> 
> 
> > +
> > +	if (!st->info->has_burst32) {
> > +		dev_err(&st->adis.spi->dev, "%s does not support
> > burst32 mode\n",
> > +			spi_get_device_id(st->adis.spi)->name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> > +				 ADIS16500_BURST32_MASK, burst32);
> > +	if (ret)
> > +		return ret;
> > +
> > +	usleep_range(250, 260);
> > +	/*
> > +	 * In 32bit mode we need extra 2 bytes for all gyro and accel
> > +	 * channels.
> > +	 */
> > +	adis16475_burst.extra_len += 6 * sizeof(u16);
> > +burst16:
> > +	st->adis.burst = &adis16475_burst;
> > +	/* it's enabled by default so spi max speed needs to be 1MHz */
> > +	st->cached_spi_speed_hz = st->adis.spi->max_speed_hz;
> > +	st->adis.spi->max_speed_hz = 1000000;
> > +
> > +	return 0;
> > +}
> > +
> > +static int adis16475_probe(struct spi_device *spi)
> > +{
> > +	struct iio_dev *indio_dev;
> > +	struct adis16475 *st;
> > +	const struct spi_device_id *id = spi_get_device_id(spi);
> > +	int ret;
> > +
> > +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	st = iio_priv(indio_dev);
> > +	st->info = &adis16475_chip_info[id->driver_data];
> > +	spi_set_drvdata(spi, indio_dev);
> > +
> > +	ret = adis_init(&st->adis, indio_dev, spi, &st->info-
> > >adis_data);
> > +	if (ret)
> > +		return ret;
> > +
> > +	indio_dev->dev.parent = &spi->dev;
> > +	indio_dev->name = id->name;
> > +	indio_dev->channels = st->info->channels;
> > +	indio_dev->num_channels = st->info->num_channels;
> > +	indio_dev->info = &adis16475_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +
> > +	ret = __adis_initial_startup(&st->adis);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = adis16475_burst_config(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = adis16475_config_irq_pin(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = adis16475_config_ext_clk(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
> > +						 adis16475_trigger_hand
> > ler);
> > +	if (ret)
> > +		return ret;
> > +
> > +	adis16475_enable_irq(&st->adis, false);
> > +
> > +	ret = devm_iio_device_register(&spi->dev, indio_dev);
> > +	if (ret)
> > +		return ret;
> > +
> > +	adis16475_debugfs_init(indio_dev);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct spi_device_id adis16475_ids[] = {
> 
> Is it actually possible to instantiate this except by
> using the dt table below?  If not, then move the 'data'
> part into that table and don't provide an spi_device_id
> table at all.  It's not relevant to the possible ways
> of causing the driver to probe.

I guess we could use the id table with devicetree even without the dt
table (even though it makes no sense).

So, I can remove it but I was using the id->name to set the the iio_dev
name which I guess is not the right way?

What Im thinking is having a name/part number string in chip info that
I can use to set the iio dev name. For parts that have the *-[1|2|3]
variations I could use the devicetree iio label property. Is this the
correct way of handling this?

- Nuno Sá
> > +	{ "adis16470", ADIS16470 },
> > +	{ "adis16475-1", ADIS16475_1 },
> > +	{ "adis16475-2", ADIS16475_2 },
> > +	{ "adis16475-3", ADIS16475_3 },
> > +	{ "adis16477-1", ADIS16477_1 },
> > +	{ "adis16477-2", ADIS16477_2 },
> > +	{ "adis16477-3", ADIS16477_3 },
> > +	{ "adis16465-1", ADIS16465_1 },
> > +	{ "adis16465-2", ADIS16465_2 },
> > +	{ "adis16465-3", ADIS16465_3 },
> > +	{ "adis16467-1", ADIS16467_1 },
> > +	{ "adis16467-2", ADIS16467_2 },
> > +	{ "adis16467-3", ADIS16467_3 },
> > +	{ "adis16500", ADIS16500 },
> > +	{ "adis16505-1", ADIS16505_1 },
> > +	{ "adis16505-2", ADIS16505_2 },
> > +	{ "adis16505-3", ADIS16505_3 },
> > +	{ "adis16507-1", ADIS16507_1 },
> > +	{ "adis16507-2", ADIS16507_2 },
> > +	{ "adis16507-3", ADIS16507_3 },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(spi, adis16475_ids);
> > +
> > +static const struct of_device_id adis16475_of_match[] = {
> > +	{ .compatible = "adi,adis16470" },
> > +	{ .compatible = "adi,adis16475-1" },
> > +	{ .compatible = "adi,adis16475-2" },
> > +	{ .compatible = "adi,adis16475-3" },
> > +	{ .compatible = "adi,adis16477-1" },
> > +	{ .compatible = "adi,adis16477-2" },
> > +	{ .compatible = "adi,adis16477-3" },
> > +	{ .compatible = "adi,adis16465-1" },
> > +	{ .compatible = "adi,adis16465-2" },
> > +	{ .compatible = "adi,adis16465-3" },
> > +	{ .compatible = "adi,adis16467-1" },
> > +	{ .compatible = "adi,adis16467-2" },
> > +	{ .compatible = "adi,adis16467-3" },
> > +	{ .compatible = "adi,adis16500" },
> > +	{ .compatible = "adi,adis16505-1" },
> > +	{ .compatible = "adi,adis16505-2" },
> > +	{ .compatible = "adi,adis16505-3" },
> > +	{ .compatible = "adi,adis16507-1" },
> > +	{ .compatible = "adi,adis16507-2" },
> > +	{ .compatible = "adi,adis16507-3" },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, adis16475_of_match);
> > +
> > +static struct spi_driver adis16475_driver = {
> > +	.driver = {
> > +		.name = "adis16475",
> > +		.of_match_table = adis16475_of_match,
> > +	},
> > +	.id_table = adis16475_ids,
> > +	.probe = adis16475_probe,
> > +};
> > +module_spi_driver(adis16475_driver);
> > +
> > +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
> > +MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
> > +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-03 21:10   ` Jonathan Cameron
@ 2020-03-04 18:00     ` Sa, Nuno
  2020-03-05 10:34       ` Lars-Peter Clausen
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-04 18:00 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, lars,
	knaack.h, Hennerich, Michael, devicetree, robh+dt

On Tue, 2020-03-03 at 21:10 +0000, Jonathan Cameron wrote:
> [External]
> 
> On Tue, 25 Feb 2020 13:41:52 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:
> 
> > Document the ADIS16475 device devicetree bindings.
> > 
> > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> 
> One thing inline on the burst mode stuff.
> 
> Thanks,
> 
> Jonathan
> 
> > ---
> >  .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > ++++++++++++++++++
> >  MAINTAINERS                                   |   1 +
> >  2 files changed, 131 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > new file mode 100644
> > index 000000000000..c0f2146e000c
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > @@ -0,0 +1,130 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Analog Devices ADIS16475 and similar IMUs
> > +
> > +maintainers:
> > +  - Nuno Sá <nuno.sa@analog.com>
> > +
> > +description: |
> > +  Analog Devices ADIS16475 and similar IMUs
> > +  
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - adi,adis16475-1
> > +      - adi,adis16475-2
> > +      - adi,adis16475-3
> > +      - adi,adis16477-1
> > +      - adi,adis16477-2
> > +      - adi,adis16477-3
> > +      - adi,adis16470
> > +      - adi,adis16465-1
> > +      - adi,adis16465-2
> > +      - adi,adis16465-3
> > +      - adi,adis16467-1
> > +      - adi,adis16467-2
> > +      - adi,adis16467-3
> > +      - adi,adis16500
> > +      - adi,adis16505-1
> > +      - adi,adis16505-2
> > +      - adi,adis16505-3
> > +      - adi,adis16507-1
> > +      - adi,adis16507-2
> > +      - adi,adis16507-3
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  spi-cpha: true
> > +
> > +  spi-cpol: true
> > +
> > +  spi-max-frequency:
> > +    maximum: 2000000
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  clock-names:
> > +    oneOf:
> > +      - const: sync
> > +      - const: direct-sync
> > +      - const: pulse-sync
> > +      - const: scaled-sync
> > +
> > +  reset-gpios:
> > +    description:
> > +      Must be the device tree identifier of the RESET pin. If
> > specified,
> > +      it will be asserted during driver probe. As the line is
> > active low,
> > +      it should be marked GPIO_ACTIVE_LOW.
> > +    maxItems: 1
> > +
> > +  adi,scaled-output-hz:
> > +    description:
> > +      This property must be present if the clock mode is scaled-
> > sync through
> > +      clock-names property. In this mode, the input clock can have
> > a range
> > +      of 1Hz to 128HZ which must be scaled to originate an
> > allowable sample
> > +      rate. This property specifies that rate.
> > +    minimum: 1900
> > +    maximum: 2100
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - spi-cpha
> > +  - spi-cpol
> > +
> > +if:
> > +  properties:
> > +    compatible:
> > +      contains:
> > +        enum:
> > +          - adi,adis16500
> > +          - adi,adis16505-1
> > +          - adi,adis16505-2
> > +          - adi,adis16505-3
> > +          - adi,adis16507-1
> > +          - adi,adis16507-2
> > +          - adi,adis16507-3
> > +
> > +then:
> > +  properties:
> > +    clock-names:
> > +      oneOf:
> > +        - const: sync
> > +        - const: direct-sync
> > +        - const: scaled-sync
> > +
> > +    adi,burst32-enable:
> > +      description:
> > +        Enable burst32 mode. In this mode, a burst reading
> > contains calibrated
> > +        gyroscope and accelerometer data in 32-bit format.
> 
> Why is this in DT?  Is it not a runtime decision
> (ideally automatically selected)

So, you mean just have this mode by default on parts that support it?

- Nuno Sá
> > +      type: boolean
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    spi {
> > +            #address-cells = <1>;
> > +            #size-cells = <0>;
> > +
> > +            adis16475: adis16475-3@0 {
> > +                    compatible = "adi,adis16475-3";
> > +                    reg = <0>;
> > +                    spi-cpha;
> > +                    spi-cpol;
> > +                    spi-max-frequency = <2000000>;
> > +                    interrupts = <4 IRQ_TYPE_EDGE_RISING>;
> > +                    interrupt-parent = <&gpio>;
> > +            };
> > +    };
> > +...
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index f11262f1f3bb..f8ccc92ab378 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1015,6 +1015,7 @@ W:	
> > http://ez.analog.com/community/linux-device-drivers
> >  S:	Supported
> >  F:	drivers/iio/imu/adis16475.c
> >  F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > +F:	Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> >  
> >  ANALOG DEVICES INC ADM1177 DRIVER
> >  M:	Beniamin Bia <beniamin.bia@analog.com>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-03-04 17:59     ` Sa, Nuno
@ 2020-03-05  9:58       ` Sa, Nuno
  2020-03-05 10:39         ` Lars-Peter Clausen
  2020-03-07 11:27         ` Jonathan Cameron
  0 siblings, 2 replies; 31+ messages in thread
From: Sa, Nuno @ 2020-03-05  9:58 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, devicetree, mark.rutland, pmeerw, lars, Ardelean,
	Alexandru, Hennerich, Michael, knaack.h, robh+dt

On Wed, 2020-03-04 at 17:59 +0000, Sa, Nuno wrote:
> [External]
> 
> On Tue, 2020-03-03 at 21:08 +0000, Jonathan Cameron wrote:
> > [External]
> > 
> > On Tue, 25 Feb 2020 13:41:51 +0100
> > Nuno Sá <nuno.sa@analog.com> wrote:
> > 
> > > Support ADIS16475 and similar IMU devices. These devices are
> > > a precision, miniature MEMS inertial measurement unit (IMU) that
> > > includes a triaxial gyroscope and a triaxial accelerometer. Each
> > > inertial sensor combines with signal conditioning that optimizes
> > > dynamic performance.
> > > 
> > > The driver adds support for the following devices:
> > >  * adis16470, adis16475, adis16477, adis16465, adis16467,
> > > adis16500,
> > >    adis16505, adis16507.
> > > 
> > > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > 
> > A few bits and pieces inline.
> > 
> > Thanks,
> > 
> > Jonathan
> > 
> > 
> > > ---
> > >  .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
> > >  MAINTAINERS                                   |    8 +
> > >  drivers/iio/imu/Kconfig                       |   13 +
> > >  drivers/iio/imu/Makefile                      |    1 +
> > >  drivers/iio/imu/adis16475.c                   | 1304
> > > +++++++++++++++++
> > >  5 files changed, 1333 insertions(+)
> > >  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-
> > > adis16475
> > >  create mode 100644 drivers/iio/imu/adis16475.c
> > > 
> > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-
> > > adis16475
> > > b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > > new file mode 100644
> > > index 000000000000..e2c3776035ea
> > > --- /dev/null
> > > +++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > > @@ -0,0 +1,7 @@
> > > +What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_ena
> > > ble
> > > +KernelVersion:
> > > +Contact:	linux-iio@vger.kernel.org
> > > +Description:
> > > +		Use the device burst read mode when reading buffered
> > > +		data. This mode provides a way to read a batch of
> > > +		output data registers, using a continuous stream of
> > > bits.
> > 
> > See comment on this below.  I'm not keen on this being exposed to
> > userspace
> > because it will rarely have any idea how to set it.
> > 
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 8fa40c3eb72a..f11262f1f3bb 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -1008,6 +1008,14 @@ W:	
> > > http://ez.analog.com/community/linux-device-drivers
> > >  F:	drivers/iio/imu/adis16460.c
> > >  F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460
> > > .yaml
> > >  
> > > +ANALOG DEVICES INC ADIS16475 DRIVER
> > > +M:	Nuno Sa <nuno.sa@analog.com>
> > > +L:	linux-iio@vger.kernel.org
> > > +W:	http://ez.analog.com/community/linux-device-drivers
> > > +S:	Supported
> > > +F:	drivers/iio/imu/adis16475.c
> > > +F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> > > +
> > >  ANALOG DEVICES INC ADM1177 DRIVER
> > >  M:	Beniamin Bia <beniamin.bia@analog.com>
> > >  M:	Michael Hennerich <Michael.Hennerich@analog.com>
> > > diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> > > index 60bb1029e759..fc4123d518bc 100644
> > > --- a/drivers/iio/imu/Kconfig
> > > +++ b/drivers/iio/imu/Kconfig
> > > @@ -29,6 +29,19 @@ config ADIS16460
> > >  	  To compile this driver as a module, choose M here: the module
> > > will be
> > >  	  called adis16460.
> > >  
> > > +config ADIS16475
> > > +	tristate "Analog Devices ADIS16475 and similar IMU driver"
> > > +	depends on SPI
> > > +	select IIO_ADIS_LIB
> > > +	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
> > > +	help
> > > +	  Say yes here to build support for Analog Devices ADIS16470,
> > > ADIS16475,
> > > +	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505,
> > > ADIS16507 inertial
> > > +	  sensors.
> > > +
> > > +	  To compile this driver as a module, choose M here: the module
> > > will be
> > > +	  called adis16475.
> > > +
> > >  config ADIS16480
> > >  	tristate "Analog Devices ADIS16480 and similar IMU driver"
> > >  	depends on SPI
> > > diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> > > index 5237fd4bc384..88b2c4555230 100644
> > > --- a/drivers/iio/imu/Makefile
> > > +++ b/drivers/iio/imu/Makefile
> > > @@ -6,6 +6,7 @@
> > >  # When adding new entries keep the list in alphabetical order
> > >  obj-$(CONFIG_ADIS16400) += adis16400.o
> > >  obj-$(CONFIG_ADIS16460) += adis16460.o
> > > +obj-$(CONFIG_ADIS16475) += adis16475.o
> > >  obj-$(CONFIG_ADIS16480) += adis16480.o
> > >  
> > >  adis_lib-y += adis.o
> > > diff --git a/drivers/iio/imu/adis16475.c
> > > b/drivers/iio/imu/adis16475.c
> > > new file mode 100644
> > > index 000000000000..f7c637734ec8
> > > --- /dev/null
> > > +++ b/drivers/iio/imu/adis16475.c
> > > @@ -0,0 +1,1304 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * ADIS16475 IMU driver
> > > + *
> > > + * Copyright 2019 Analog Devices Inc.
> > > + */
> > > +#include <asm/unaligned.h>
> > > +#include <linux/bitfield.h>
> > > +#include <linux/bitops.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/debugfs.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/device.h>
> > > +#include <linux/kernel.h>
> > > +#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/module.h>
> > > +#include <linux/spi/spi.h>
> > > +
> > > +#define ADIS16475_REG_DIAG_STAT		0x02
> > > +#define ADIS16475_REG_X_GYRO_L		0x04
> > > +#define ADIS16475_REG_Y_GYRO_L		0x08
> > > +#define ADIS16475_REG_Z_GYRO_L		0x0C
> > > +#define ADIS16475_REG_X_ACCEL_L		0x10
> > > +#define ADIS16475_REG_Y_ACCEL_L		0x14
> > > +#define ADIS16475_REG_Z_ACCEL_L		0x18
> > > +#define ADIS16475_REG_TEMP_OUT		0x1c
> > > +#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
> > > +#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
> > > +#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
> > > +#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
> > > +#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
> > > +#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
> > > +#define ADIS16475_REG_FILT_CTRL		0x5c
> > > +#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
> > > +#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FI
> > > LT_CTRL_MASK, x)
> > > +#define ADIS16475_REG_MSG_CTRL		0x60
> > > +#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
> > > +#define ADIS16475_MSG_CTRL_DR_POL(x) \
> > > +				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MA
> > > SK, x)
> > > +#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
> > > +#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EX
> > > T_CLK_MASK, x)
> > > +#define ADIS16475_REG_UP_SCALE		0x62
> > > +#define ADIS16475_REG_DEC_RATE		0x64
> > > +#define ADIS16475_REG_GLOB_CMD		0x68
> > > +#define ADIS16475_REG_FIRM_REV		0x6c
> > > +#define ADIS16475_REG_FIRM_DM		0x6e
> > > +#define ADIS16475_REG_FIRM_Y		0x70
> > > +#define ADIS16475_REG_PROD_ID		0x72
> > > +#define ADIS16475_REG_SERIAL_NUM	0x74
> > > +#define ADIS16475_REG_FLASH_CNT		0x7c
> > > +#define ADIS16500_BURST32_MASK		BIT(9)
> > > +#define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BU
> > > RST32_MASK, x)
> > > +/* number of data elements in burst mode */
> > > +#define ADIS16475_BURST_MAX_DATA	10
> > > +#define ADIS16475_MAX_SCAN_DATA		15
> > > +
> > > +enum clk_mode {
> > > +	ADIS16475_CLK_DIRECT = 1,
> > > +	ADIS16475_CLK_SCALED,
> > > +	ADIS16475_CLK_OUTPUT,
> > > +	ADIS16475_CLK_PULSE = 5,
> > > +};
> > > +
> > > +struct adis16475_clks {
> > > +	const char *name;
> > > +	enum clk_mode clk_mode;
> > > +	u16 min_rate;
> > > +	u16 max_rate;
> > > +};
> > > +
> > > +struct adis16475_chip_info {
> > > +	const struct iio_chan_spec *channels;
> > > +	const struct adis16475_clks *clks;
> > > +	const struct adis_data adis_data;
> > > +	u32 num_channels;
> > > +	u32 gyro_max_val;
> > > +	u32 gyro_max_scale;
> > > +	u32 accel_max_val;
> > > +	u32 accel_max_scale;
> > > +	u32 temp_scale;
> > > +	u32 int_clk;
> > > +	u16 max_dec;
> > > +	u8 num_clks;
> > > +	bool has_burst32;
> > > +};
> > > +
> > > +struct adis16475 {
> > > +	const struct adis16475_chip_info *info;
> > > +	struct adis adis;
> > > +	u32 clk_freq;
> > > +	u32 cached_spi_speed_hz;
> > > +	bool burst32;
> > > +};
> > > +
> > > +enum {
> > > +	ADIS16475_SCAN_GYRO_X,
> > > +	ADIS16475_SCAN_GYRO_Y,
> > > +	ADIS16475_SCAN_GYRO_Z,
> > > +	ADIS16475_SCAN_ACCEL_X,
> > > +	ADIS16475_SCAN_ACCEL_Y,
> > > +	ADIS16475_SCAN_ACCEL_Z,
> > > +	ADIS16475_SCAN_TEMP,
> > > +	ADIS16475_SCAN_DIAG_S_FLAGS,
> > > +	ADIS16475_SCAN_CRC_FAILURE,
> > > +};
> > > +
> > > +#ifdef CONFIG_DEBUG_FS
> > > +static ssize_t adis16475_show_firmware_revision(struct file
> > > *file,
> > > +						char __user *userbuf,
> > > +						size_t count, loff_t
> > > *ppos)
> > > +{
> > > +	struct adis16475 *st = file->private_data;
> > > +	char buf[7];
> > > +	size_t len;
> > > +	u16 rev;
> > > +	int ret;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV,
> > > &rev);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev &
> > > 0xff);
> > > +
> > > +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> > > +}
> > > +
> > > +static const struct file_operations
> > > adis16475_firmware_revision_fops = {
> > > +	.open = simple_open,
> > > +	.read = adis16475_show_firmware_revision,
> > > +	.llseek = default_llseek,
> > > +	.owner = THIS_MODULE,
> > > +};
> > > +
> > > +static ssize_t adis16475_show_firmware_date(struct file *file,
> > > +					    char __user *userbuf,
> > > +					    size_t count, loff_t *ppos)
> > > +{
> > > +	struct adis16475 *st = file->private_data;
> > > +	u16 md, year;
> > > +	char buf[12];
> > > +	size_t len;
> > > +	int ret;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8,
> > > md & 0xff,
> > > +		       year);
> > > +
> > > +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> > > +}
> > > +
> > > +static const struct file_operations adis16475_firmware_date_fops
> > > =
> > > {
> > > +	.open = simple_open,
> > > +	.read = adis16475_show_firmware_date,
> > > +	.llseek = default_llseek,
> > > +	.owner = THIS_MODULE,
> > > +};
> > > +
> > > +static int adis16475_show_serial_number(void *arg, u64 *val)
> > > +{
> > > +	struct adis16475 *st = arg;
> > > +	u16 serial;
> > > +	int ret;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM,
> > > &serial);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	*val = serial;
> > > +
> > > +	return 0;
> > > +}
> > > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
> > > +			adis16475_show_serial_number, NULL,
> > > "0x%.4llx\n");
> > > +
> > > +static int adis16475_show_product_id(void *arg, u64 *val)
> > > +{
> > > +	struct adis16475 *st = arg;
> > > +	u16 prod_id;
> > > +	int ret;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID,
> > > &prod_id);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	*val = prod_id;
> > > +
> > > +	return 0;
> > > +}
> > > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
> > > +			adis16475_show_product_id, NULL, "%llu\n");
> > > +
> > > +static int adis16475_show_flash_count(void *arg, u64 *val)
> > > +{
> > > +	struct adis16475 *st = arg;
> > > +	u32 flash_count;
> > > +	int ret;
> > > +
> > > +	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
> > > +			       &flash_count);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	*val = flash_count;
> > > +
> > > +	return 0;
> > > +}
> > > +DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
> > > +			adis16475_show_flash_count, NULL, "%lld\n");
> > > +
> > > +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> > > +{
> > > +	struct adis16475 *st = iio_priv(indio_dev);
> > > +
> > > +	debugfs_create_file("serial_number", 0400, indio_dev-
> > > > debugfs_dentry,
> > > +			    st, &adis16475_serial_number_fops);
> > > +	debugfs_create_file("product_id", 0400, indio_dev-
> > > > debugfs_dentry, st,
> > > +			    &adis16475_product_id_fops);
> > > +	debugfs_create_file("flash_count", 0400, indio_dev-
> > > > debugfs_dentry, st,
> > > +			    &adis16475_flash_count_fops);
> > > +	debugfs_create_file("firmware_revision", 0400,
> > > +			    indio_dev->debugfs_dentry, st,
> > > +			    &adis16475_firmware_revision_fops);
> > > +	debugfs_create_file("firmware_date", 0400, indio_dev-
> > > > debugfs_dentry,
> > > +			    st, &adis16475_firmware_date_fops);
> > > +	return 0;
> > > +}
> > > +#else
> > > +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> > > +{
> > > +	return 0;
> > > +}
> > > +#endif
> > > +
> > > +static ssize_t adis16475_burst_mode_enable_get(struct device
> > > *dev,
> > > +					       struct device_attribute
> > > *attr,
> > > +					       char *buf)
> > > +{
> > > +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> > > +
> > > +	return sprintf(buf, "%d\n", st->adis.burst->en);
> > > +}
> > > +
> > > +static ssize_t adis16475_burst_mode_enable_set(struct device
> > > *dev,
> > > +					       struct device_attribute
> > > *attr,
> > > +					       const char *buf, size_t
> > > len)
> > > +{
> > > +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> > > +	bool val;
> > > +	int ret;
> > > +
> > > +	ret = kstrtobool(buf, &val);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	if (val)
> > > +		/* 1MHz max in burst mode */
> > > +		st->adis.spi->max_speed_hz = 1000000;
> > > +	else
> > > +		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
> > > +
> > > +	st->adis.burst->en = val;
> > > +
> > > +	return len;
> > > +}
> > > +
> > > +static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
> > > +		       adis16475_burst_mode_enable_get,
> > > +		       adis16475_burst_mode_enable_set, 0);
> > > +
> > > +static struct attribute *adis16475_attributes[] = {
> > > +	&iio_dev_attr_burst_mode_enable.dev_attr.attr,
> > 
> > Hmm.  Normally we try to avoid exposing this and make the decision
> > automatically based on which channels are enabled.
> 
> Hmm. In that case, the decision would probably have to go to the
> library since it is there that the "preparations" for buffered mode
> are
> done. Mostly, the data we are interested in the burst data is gyro,
> accel and temp. So to make the decision based on which channels are
> enabled is not that straight. Should we enable it only when all
> channels are enabled? Some of them (and which)?

I thought a little bit more about it and we could do some math in the
lib to know when using burst mode becomes faster (depending on enabled
scan elements). The library would need to know about the burst max spi
frequency and also some minor changes in how burst_len is being
calculated (drivers should explicitly set this rather than the
library). The question is, is it worth it to go with this extra work
:)?

> I guess that the only case where not using burst mode is faster is
> __maybe__ when only reading one channel (even then Im not sure...).
> Hence, I'm kind of thinking in the cynical approach :).
> 
> However, I was also using this to handle the spi max_speed_hz since
> we
> have some limitations in burst mode. I have two thoughts here:
> 
> 1) We handle this in the trigger handler, before doing the spi
> transfer
> 2) Just set the spi max_speed_hz to the one allowed by burst mode in
> the devicetree.
> 
> Any preference?
> > If more cynical we decide that no one buys and expensive sensor
> > only
> > to read a few of it's channels, so we turn on burst mode all the
> > time
> > :)
> > 
> > > +	NULL,
> > > +};
> > > +
> > > +static const struct attribute_group adis16495_attribute_group =
> > > {
> > > +	.attrs = adis16475_attributes,
> > > +};
> > > +
> > > +static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
> > > +{
> > > +	int ret;
> > > +	u16 dec;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE,
> > > &dec);
> > > +	if (ret)
> > > +		return -EINVAL;
> > > +
> > > +	*freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int adis16475_set_freq(struct adis16475 *st, const u32
> > > freq)
> > > +{
> > > +	u16 dec;
> > > +
> > > +	if (freq == 0 || freq > st->clk_freq)
> > > +		return -EINVAL;
> > > +
> > > +	dec = DIV_ROUND_CLOSEST(st->clk_freq, freq);
> > > +
> > > +	if (dec)
> > > +		dec--;
> > > +
> > > +	if (dec > st->info->max_dec)
> > > +		dec = st->info->max_dec;
> > > +
> > > +	return adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE,
> > > dec);
> > > +}
> > > +
> > > +/* The values are approximated. */
> > > +static const u32 adis16475_3db_freqs[] = {
> > > +	[0] = 720, /* Filter disabled, full BW (~720Hz) */
> > > +	[1] = 360,
> > > +	[2] = 164,
> > > +	[3] = 80,
> > > +	[4] = 40,
> > > +	[5] = 20,
> > > +	[6] = 10,
> > > +	[7] = 10, /* not a valid setting */
> > > +};
> > > +
> > > +static int adis16475_get_filter(struct adis16475 *st, u32
> > > *filter)
> > > +{
> > > +	u16 filter_sz;
> > > +	int ret;
> > > +	const int mask = ADIS16475_FILT_CTRL_MASK;
> > > +
> > > +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
> > > &filter_sz);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	*filter = adis16475_3db_freqs[filter_sz & mask];
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int adis16475_set_filter(struct adis16475 *st, const u32
> > > filter)
> > > +{
> > > +	int i;
> > > +
> > > +	for (i = ARRAY_SIZE(adis16475_3db_freqs) - 1; i >= 1; i--) {
> > > +		if (adis16475_3db_freqs[i] >= filter)
> > > +			break;
> > > +	}
> > > +
> > > +	return adis_write_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL,
> > > +				 ADIS16475_FILT_CTRL(i));
> > > +}
> > > +
> > > +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,
> > > +	[ADIS16475_SCAN_GYRO_Z] = ADIS16475_REG_Z_GYRO_BIAS_L,
> > > +	[ADIS16475_SCAN_ACCEL_X] = ADIS16475_REG_X_ACCEL_BIAS_L,
> > > +	[ADIS16475_SCAN_ACCEL_Y] = ADIS16475_REG_Y_ACCEL_BIAS_L,
> > > +	[ADIS16475_SCAN_ACCEL_Z] = ADIS16475_REG_Z_ACCEL_BIAS_L,
> > > +};
> > > +
> > > +static int adis16475_read_raw(struct iio_dev *indio_dev,
> > > +			      const struct iio_chan_spec *chan,
> > > +			      int *val, int *val2, long info)
> > > +{
> > > +	struct adis16475 *st = iio_priv(indio_dev);
> > > +	int ret;
> > > +	u32 tmp;
> > > +
> > > +	switch (info) {
> > > +	case IIO_CHAN_INFO_RAW:
> > > +		return adis_single_conversion(indio_dev, chan, 0, val);
> > > +	case IIO_CHAN_INFO_SCALE:
> > > +		switch (chan->type) {
> > > +		case IIO_ANGL_VEL:
> > > +			*val = st->info->gyro_max_val;
> > > +			*val2 = st->info->gyro_max_scale;
> > > +			return IIO_VAL_FRACTIONAL;
> > > +		case IIO_ACCEL:
> > > +			*val = st->info->accel_max_val;
> > > +			*val2 = st->info->accel_max_scale;
> > > +			return IIO_VAL_FRACTIONAL;
> > > +		case IIO_TEMP:
> > > +			*val = st->info->temp_scale;
> > > +			return IIO_VAL_INT;
> > > +		default:
> > > +			return -EINVAL;
> > > +		}
> > > +	case IIO_CHAN_INFO_CALIBBIAS:
> > > +		ret = adis_read_reg_32(&st->adis,
> > > +				       adis16475_calib_regs[chan-
> > > > scan_index],
> > > +				       val);
> > > +		break;
> > > +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> > > +		ret = adis16475_get_filter(st, val);
> > > +		break;
> > > +	case IIO_CHAN_INFO_SAMP_FREQ:
> > > +		ret = adis16475_get_freq(st, &tmp);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		*val = tmp / 1000;
> > > +		*val2 = (tmp % 1000) * 1000;
> > > +		return IIO_VAL_INT_PLUS_MICRO;
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	if (ret)
> > > +		return ret;
> > 
> > Better to put this inline after each ret = section and return
> > directly from those.
> > As it stands the code paths are rather inconsistent.
> 
> Got it...
> 
> > > +
> > > +	return IIO_VAL_INT;
> > > +}
> > > +
> > > +static int adis16475_write_raw(struct iio_dev *indio_dev,
> > > +			       const struct iio_chan_spec *chan,
> > > +			       int val, int val2, long info)
> > > +{
> > > +	struct adis16475 *st = iio_priv(indio_dev);
> > > +	u32 tmp;
> > > +
> > > +	switch (info) {
> > > +	case IIO_CHAN_INFO_SAMP_FREQ:
> > > +		tmp = val * 1000 + val2 / 1000;
> > > +		return adis16475_set_freq(st, tmp);
> > > +	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> > > +		return adis16475_set_filter(st, val);
> > > +	case IIO_CHAN_INFO_CALIBBIAS:
> > > +		return adis_write_reg_32(&st->adis,
> > > +					 adis16475_calib_regs[chan-
> > > > scan_index],
> > > +					 val);
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +}
> > > +
> > > +#define ADIS16475_MOD_CHAN(_type, _mod, _address, _si, _r_bits,
> > > _s_bits) \
> > > +	{ \
> > > +		.type = (_type), \
> > > +		.modified = 1, \
> > > +		.channel2 = (_mod), \
> > > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > > +			BIT(IIO_CHAN_INFO_CALIBBIAS), \
> > > +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
> > > +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)
> > > > \
> > > +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY
> > > ), \
> > > +		.address = (_address), \
> > > +		.scan_index = (_si), \
> > > +		.scan_type = { \
> > > +			.sign = 's', \
> > > +			.realbits = (_r_bits), \
> > > +			.storagebits = (_s_bits), \
> > > +			.endianness = IIO_BE, \
> > > +		}, \
> > > +	}
> > > +
> > > +#define ADIS16475_GYRO_CHANNEL(_mod) \
> > > +	ADIS16475_MOD_CHAN(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
> > > +	ADIS16475_REG_ ## _mod ## _GYRO_L, ADIS16475_SCAN_GYRO_ ##
> > > _mod, 32, \
> > > +	32)
> > > +
> > > +#define ADIS16475_ACCEL_CHANNEL(_mod) \
> > > +	ADIS16475_MOD_CHAN(IIO_ACCEL, IIO_MOD_ ## _mod, \
> > > +	ADIS16475_REG_ ## _mod ## _ACCEL_L, ADIS16475_SCAN_ACCEL_ ##
> > > _mod, 32, \
> > > +	32)
> > > +
> > > +#define ADIS16475_TEMP_CHANNEL() { \
> > > +		.type = IIO_TEMP, \
> > > +		.indexed = 1, \
> > > +		.channel = 0, \
> > > +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > > +			BIT(IIO_CHAN_INFO_SCALE), \
> > > +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)
> > > > \
> > > +			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY
> > > ), \
> > > +		.address = ADIS16475_REG_TEMP_OUT, \
> > > +		.scan_index = ADIS16475_SCAN_TEMP, \
> > > +		.scan_type = { \
> > > +			.sign = 's', \
> > > +			.realbits = 16, \
> > > +			.storagebits = 16, \
> > > +			.endianness = IIO_BE, \
> > > +		}, \
> > > +	}
> > > +
> > > +static const struct iio_chan_spec adis16475_channels[] = {
> > > +	ADIS16475_GYRO_CHANNEL(X),
> > > +	ADIS16475_GYRO_CHANNEL(Y),
> > > +	ADIS16475_GYRO_CHANNEL(Z),
> > > +	ADIS16475_ACCEL_CHANNEL(X),
> > > +	ADIS16475_ACCEL_CHANNEL(Y),
> > > +	ADIS16475_ACCEL_CHANNEL(Z),
> > > +	ADIS16475_TEMP_CHANNEL(),
> > > +	IIO_CHAN_SOFT_TIMESTAMP(9)
> > > +};
> > > +
> > > +enum adis16475_variant {
> > > +	ADIS16470,
> > > +	ADIS16475_1,
> > > +	ADIS16475_2,
> > > +	ADIS16475_3,
> > > +	ADIS16477_1,
> > > +	ADIS16477_2,
> > > +	ADIS16477_3,
> > > +	ADIS16465_1,
> > > +	ADIS16465_2,
> > > +	ADIS16465_3,
> > > +	ADIS16467_1,
> > > +	ADIS16467_2,
> > > +	ADIS16467_3,
> > > +	ADIS16500,
> > > +	ADIS16505_1,
> > > +	ADIS16505_2,
> > > +	ADIS16505_3,
> > > +	ADIS16507_1,
> > > +	ADIS16507_2,
> > > +	ADIS16507_3,
> > > +
> > > +};
> > > +
> > > +enum {
> > > +	ADIS16475_DIAG_STAT_DATA_PATH = 1,
> > > +	ADIS16475_DIAG_STAT_FLASH_MEM,
> > > +	ADIS16475_DIAG_STAT_SPI,
> > > +	ADIS16475_DIAG_STAT_STANDBY,
> > > +	ADIS16475_DIAG_STAT_SENSOR,
> > > +	ADIS16475_DIAG_STAT_MEMORY,
> > > +	ADIS16475_DIAG_STAT_CLK,
> > > +};
> > > +
> > > +static const char * const adis16475_status_error_msgs[] = {
> > > +	[ADIS16475_DIAG_STAT_DATA_PATH] = "Data Path Overrun",
> > > +	[ADIS16475_DIAG_STAT_FLASH_MEM] = "Flash memory update
> > > failure",
> > > +	[ADIS16475_DIAG_STAT_SPI] = "SPI communication error",
> > > +	[ADIS16475_DIAG_STAT_STANDBY] = "Standby mode",
> > > +	[ADIS16475_DIAG_STAT_SENSOR] = "Sensor failure",
> > > +	[ADIS16475_DIAG_STAT_MEMORY] = "Memory failure",
> > > +	[ADIS16475_DIAG_STAT_CLK] = "Clock error",
> > > +};
> > > +
> > > +static int adis16475_enable_irq(struct adis *adis, bool enable)
> > > +{
> > > +	/*
> > > +	 * There is no way to gate the data-ready signal internally
> > > inside the
> > > +	 * ADIS16475. We can only control it's polarity...
> > > +	 */
> > > +	if (enable)
> > > +		enable_irq(adis->spi->irq);
> > > +	else
> > > +		disable_irq(adis->spi->irq);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +#define ADIS16475_DATA(_prod_id, _timeouts)			
> > > 	\
> > > +{								
> > > 	
> > > \
> > > +	.msc_ctrl_reg = ADIS16475_REG_MSG_CTRL,				
> > > \
> > > +	.glob_cmd_reg = ADIS16475_REG_GLOB_CMD,				
> > > \
> > > +	.diag_stat_reg = ADIS16475_REG_DIAG_STAT,			\
> > > +	.prod_id_reg = ADIS16475_REG_PROD_ID,				
> > > \
> > > +	.prod_id = (_prod_id),						
> > > \
> > > +	.self_test_mask = BIT(2),					\
> > > +	.self_test_reg = ADIS16475_REG_GLOB_CMD,			\
> > > +	.cs_change_delay = 16,						
> > > \
> > > +	.read_delay = 5,						\
> > > +	.write_delay = 5,						\
> > > +	.status_error_msgs = adis16475_status_error_msgs,		\
> > > +	.status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) |	\
> > > +		BIT(ADIS16475_DIAG_STAT_FLASH_MEM) |			
> > > \
> > > +		BIT(ADIS16475_DIAG_STAT_SPI) |				
> > > \
> > > +		BIT(ADIS16475_DIAG_STAT_STANDBY) |			\
> > > +		BIT(ADIS16475_DIAG_STAT_SENSOR) |			\
> > > +		BIT(ADIS16475_DIAG_STAT_MEMORY) |			\
> > > +		BIT(ADIS16475_DIAG_STAT_CLK),				
> > > \
> > > +	.enable_irq = adis16475_enable_irq,				\
> > > +	.timeouts = (_timeouts),					\
> > > +}
> > > +
> > > +static const struct adis16475_clks adis16475_ext_clks[] = {
> > > +	{ "sync", ADIS16475_CLK_OUTPUT, 1900, 2100 },
> > > +	{ "direct-sync", ADIS16475_CLK_DIRECT, 1900, 2100 },
> > > +	{ "scaled-sync", ADIS16475_CLK_SCALED, 1, 128 },
> > > +	{ "pulse-sync", ADIS16475_CLK_PULSE, 1000, 2100 },
> > 
> > Rob already commented on this so I'll not bother :)
> 
> I will change the name to adis16475_sync...
> 
> > > +};
> > > +
> > > +static const struct adis_timeout adis16475_timeouts = {
> > > +	.reset_ms = 200,
> > > +	.sw_reset_ms = 200,
> > > +	.self_test_ms = 20,
> > > +};
> > > +
> > > +static const struct adis_timeout adis1650x_timeouts = {
> > > +	.reset_ms = 260,
> > > +	.sw_reset_ms = 260,
> > > +	.self_test_ms = 30,
> > > +};
> > > +
> > > +static const struct adis16475_chip_info adis16475_chip_info[] =
> > > {
> > > +	[ADIS16470] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16470,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16475_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16475,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16475_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16475,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16475_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16475,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16477_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16477,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16477_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16477,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16477_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16477,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16465_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16465,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16465_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16465,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16465_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16465,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16467_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16467,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16467_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16467,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16467_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 1,
> > > +		.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks),
> > > +		.adis_data = ADIS16475_DATA(16467,
> > > &adis16475_timeouts),
> > > +	},
> > > +	[ADIS16500] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 392,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16500,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16505_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 78,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16505,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16505_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 78,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16505,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16505_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 78,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16505,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16507_1] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
> > > +		.accel_max_val = 392,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16507,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16507_2] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
> > > +		.accel_max_val = 392,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16507,
> > > &adis1650x_timeouts),
> > > +	},
> > > +	[ADIS16507_3] = {
> > > +		.num_channels = ARRAY_SIZE(adis16475_channels),
> > > +		.channels = adis16475_channels,
> > > +		.gyro_max_val = 1,
> > > +		.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
> > > +		.accel_max_val = 392,
> > > +		.accel_max_scale = 32000 << 16,
> > > +		.temp_scale = 100,
> > > +		.int_clk = 2000,
> > > +		.max_dec = 1999,
> > > +		.clks = adis16475_ext_clks,
> > > +		/* pulse sync not supported */
> > > +		.num_clks = ARRAY_SIZE(adis16475_ext_clks) - 1,
> > > +		.has_burst32 = true,
> > > +		.adis_data = ADIS16475_DATA(16507,
> > > &adis1650x_timeouts),
> > > +	},
> > > +};
> > > +
> > > +static const struct iio_info adis16475_info = {
> > > +	.read_raw = &adis16475_read_raw,
> > > +	.write_raw = &adis16475_write_raw,
> > > +	.update_scan_mode = adis_update_scan_mode,
> > > +	.attrs = &adis16495_attribute_group,
> > > +	.debugfs_reg_access = adis_debugfs_reg_access,
> > > +};
> > > +
> > > +static struct adis_burst adis16475_burst = {
> > > +	.en = true,
> > > +	.reg_cmd = ADIS16475_REG_GLOB_CMD,
> > > +	/*
> > > +	 * adis_update_scan_mode_burst() sets the burst length in
> > > respect with
> > > +	 * the number of channels and allocates 16 bits for each.
> > > However,
> > > +	 * adis1647x devices also need space for DIAG_STAT, DATA_CNTR
> > > or
> > > +	 * TIME_STAMP (depending on the clock mode but for us these
> > > bytes are
> > > +	 * don't care...) and CRC.
> > > +	 */
> > > +	.extra_len = 3 * sizeof(u16),
> > > +};
> > > +
> > > +static u16 adis16475_validate_crc(const u8 *buffer, const u16
> > > crc,
> > > +				  const bool burst32)
> > > +{
> > > +	int i;
> > > +	u16 __crc = 0;
> > > +
> > > +	/* extra 6 elements for low gyro and accel */
> > > +	const u16 sz = burst32 ? ADIS16475_BURST_MAX_DATA + 6 :
> > > +		ADIS16475_BURST_MAX_DATA;
> > > +
> > > +	for (i = 0; i < sz * 2 - 2; i++)
> > > +		__crc += buffer[i];
> > > +
> > > +	return (__crc != crc);
> > > +}
> > > +
> > > +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);
> > > +	struct adis *adis = &st->adis;
> > > +	int ret, bit, i = 0;
> > > +	u16 crc, data[ADIS16475_MAX_SCAN_DATA], *buffer, crc_res;
> > > +	/* offset until the first element after gyro and accel */
> > > +	const u8 offset = st->burst32 ? 13 : 7;
> > > +
> > > +	ret = spi_sync(adis->spi, &adis->msg);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	buffer = (u16 *)adis->buffer;
> > > +
> > > +	if (!(adis->burst && adis->burst->en))
> > > +		goto push_to_buffers;
> > > +
> > > +	/* We always validate the crc to at least print a message */
> > > +	crc = get_unaligned_be16(&buffer[offset + 2]);
> > > +	crc_res = adis16475_validate_crc((u8 *)adis->buffer, crc,
> > > +					 st->burst32);
> > > +	if (crc_res)
> > > +		dev_err(&adis->spi->dev, "Invalid crc\n");
> > > +
> > > +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> > > +			 indio_dev->masklength) {
> > > +		/*
> > > +		 * When burst mode is used, system flags is the first
> > > data
> > > +		 * channel in the sequence, but the scan index is 7.
> > > +		 */
> > > +		switch (bit) {
> > > +		case ADIS16475_SCAN_TEMP:
> > > +			data[i++] = get_unaligned(&buffer[offset]);
> > > +			break;
> > > +		case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
> > > +			/*
> > > +			 * The first 2 bytes on the received data are
> > > the
> > > +			 * DIAG_STAT reg, hence the +1 offset here...
> > > +			 */
> > > +			if (st->burst32) {
> > > +				/* upper 16 */
> > > +				data[i++] = get_unaligned(&buffer[bit *
> > > 2 + 2]);
> > > +				/* lower 16 */
> > > +				data[i++] = get_unaligned(&buffer[bit *
> > > 2 + 1]);
> > > +			} else {
> > > +				data[i++] = get_unaligned(&buffer[bit +
> > > 1]);
> > > +				/* lower not used */
> > > +				data[i++] = 0;
> > > +			}
> > > +			break;
> > > +		}
> > > +	}
> > > +
> > > +	buffer = data;
> > > +
> > > +push_to_buffers:
> > > +	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf-
> > > > timestamp);
> > 
> > I'm not sure data is the right size.  It needs to have space to
> > have
> > an aligned
> > timestamp at the end.
> 
> Will double check this... Honestly I did not had the timestamp into
> account so the size is probably wrong.

I guess you are right. With all the channels enabled I think we need a
40 bytes buffer in order to have the aligned timestamp...

> > > +	iio_trigger_notify_done(indio_dev->trig);
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static void adis16475_disable_clk(void *data)
> > > +{
> > > +	clk_disable_unprepare((struct clk *)data);
> > > +}
> > > +
> > > +static int adis16475_config_ext_clk(struct adis16475 *st)
> > > +{
> > > +	int ret;
> > > +	int i;
> > > +	struct device *dev = &st->adis.spi->dev;
> > > +	const struct adis16475_clks *ext_clks = st->info->clks;
> > > +
> > > +	for (i = 0; i < st->info->num_clks; i++) {
> > > +		u16 mode = ADIS16475_EXT_CLK(ext_clks[i].clk_mode);
> > > +		struct clk *clk = devm_clk_get(dev, ext_clks[i].name);
> > > +
> > > +		if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT)
> > > +			return PTR_ERR(clk);
> > > +		else if (IS_ERR(clk))
> > > +			continue;
> > > +
> > > +		ret = clk_prepare_enable(clk);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		ret = devm_add_action_or_reset(dev,
> > > adis16475_disable_clk, clk);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		st->clk_freq = clk_get_rate(clk);
> > > +		if (st->clk_freq < ext_clks[i].min_rate ||
> > > +		    st->clk_freq > ext_clks[i].max_rate) {
> > > +			dev_err(dev,
> > > +				"Clk rate:%u not in a valid range:[%u
> > > %u]\n",
> > > +				st->clk_freq, ext_clks[i].min_rate,
> > > +				ext_clks[i].max_rate);
> > > +			return -EINVAL;
> > > +		}
> > > +
> > > +		if (ext_clks[i].clk_mode == ADIS16475_CLK_SCALED) {
> > > +			u16 up_scale;
> > > +			u32 scaled_out_freq = 0;
> > > +			/*
> > > +			 * If we are in scaled mode, we must have an
> > > up_scale.
> > > +			 * In scaled mode the allowable input clock
> > > range is
> > > +			 * 1 Hz to 128 Hz, and the allowable output
> > > range is
> > > +			 * 1900 to 2100 Hz. Hence, a scale must be
> > > given to
> > > +			 * get the allowable output.
> > > +			 */
> > > +			device_property_read_u32(dev, "adi,scaled-
> > > output-hz",
> > > +						 &scaled_out_freq);
> > > +
> > > +			if (scaled_out_freq < 1900 || scaled_out_freq >
> > > 2100) {
> > > +				dev_err(dev,
> > > +					"Invalid value:%u for
> > > adi,scaled-output-hz",
> > > +					scaled_out_freq);
> > > +				return -EINVAL;
> > > +			}
> > > +
> > > +			up_scale = DIV_ROUND_CLOSEST(scaled_out_freq,
> > > +						     st->clk_freq);
> > > +
> > > +			ret = __adis_write_reg_16(&st->adis,
> > > +						  ADIS16475_CLK_SCALED,
> > > +						  up_scale);
> > > +			if (ret)
> > > +				return ret;
> > > +
> > > +			st->clk_freq = scaled_out_freq;
> > > +		}
> > > +		/*
> > > +		 * Keep in mind that the mask for the clk modes in
> > > adis1650*
> > > +		 * chips is different (1100 instead of 11100). However,
> > > we
> > > +		 * are not configuring BIT(4) in these chips and the
> > > default
> > > +		 * value is 0, so we are fine in doing the below
> > > operations.
> > > +		 * I'm keeping this for simplicity and avoiding extra
> > > variables
> > > +		 * in chip_info.
> > > +		 */
> > > +		ret = __adis_update_bits(&st->adis,
> > > ADIS16475_REG_MSG_CTRL,
> > > +					 ADIS16475_EXT_CLK_MASK, mode);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		usleep_range(250, 260);
> > > +
> > > +		break;
> > > +	}
> > > +
> > > +	if (i == st->info->num_clks)
> > > +		/* internal clk */
> > > +		st->clk_freq = st->info->int_clk;
> > > +
> > > +	st->clk_freq *= 1000;
> > > +
> > > +	return 0;
> > > +}
> > > 
> > > +static int adis16475_config_irq_pin(struct adis16475 *st)
> > > +{
> > > +	int ret;
> > > +	struct irq_data *desc;
> > > +	u32 irq_type;
> > > +	u16 val = 0;
> > > +	u8 polarity;
> > > +	struct spi_device *spi = st->adis.spi;
> > > +
> > > +	desc = irq_get_irq_data(spi->irq);
> > > +	if (!desc) {
> > > +		dev_err(&spi->dev, "Could not find IRQ %d\n", spi-
> > > > irq);
> > > +		return -EINVAL;
> > > +	}
> > > +	/*
> > > +	 * It is possible to configure the data ready polarity.
> > > Furthermore, we
> > > +	 * need to update the adis struct if we want data ready as
> > > active low.
> > > +	 */
> > > +	irq_type = irqd_get_trigger_type(desc);
> > > +	if (irq_type == IRQF_TRIGGER_RISING) {
> > > +		polarity = 1;
> > > +	} else if (irq_type == IRQF_TRIGGER_FALLING) {
> > > +		polarity = 0;
> > > +		st->adis.irq_mask = IRQF_TRIGGER_FALLING;
> > > +	} else {
> > > +		dev_err(&spi->dev, "Invalid interrupt type 0x%x
> > > specified\n",
> > > +			irq_type);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	val = ADIS16475_MSG_CTRL_DR_POL(polarity);
> > > +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> > > +				 ADIS16475_MSG_CTRL_DR_POL_MASK, val);
> > > +	if (ret)
> > > +		return ret;
> > > +	/*
> > > +	 * There is a delay writing to any bits written to the MSC_CTRL
> > > +	 * register. It should not be bigger than 200us, so 250 should
> > > be more
> > > +	 * than enough!
> > > +	 */
> > > +	usleep_range(250, 260);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int adis16475_burst_config(struct adis16475 *st)
> > > +{
> > > +	const u16 burst32 = ADIS16500_BURST32(1);
> > > +	int ret;
> > > +
> > > +	st->burst32 = device_property_read_bool(&st->adis.spi->dev,
> > > +						"adi,burst32-enable");
> > > +	if (!st->burst32)
> > > +		goto burst16;
> > A forwards goto like this on a non error condition, is a bit
> > unusual.
> > While it involves more indenting I would still prefer the logic
> > flipped
> 
> Honestly I find it more readable (to me) like this. But I do agree
> it's
> not that usual. Will change it...
> 
> > 	if (st->burst32) {
> > 
> > 	}
> > 
> > 
> > > +
> > > +	if (!st->info->has_burst32) {
> > > +		dev_err(&st->adis.spi->dev, "%s does not support
> > > burst32 mode\n",
> > > +			spi_get_device_id(st->adis.spi)->name);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
> > > +				 ADIS16500_BURST32_MASK, burst32);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	usleep_range(250, 260);
> > > +	/*
> > > +	 * In 32bit mode we need extra 2 bytes for all gyro and accel
> > > +	 * channels.
> > > +	 */
> > > +	adis16475_burst.extra_len += 6 * sizeof(u16);
> > > +burst16:
> > > +	st->adis.burst = &adis16475_burst;
> > > +	/* it's enabled by default so spi max speed needs to be 1MHz */
> > > +	st->cached_spi_speed_hz = st->adis.spi->max_speed_hz;
> > > +	st->adis.spi->max_speed_hz = 1000000;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int adis16475_probe(struct spi_device *spi)
> > > +{
> > > +	struct iio_dev *indio_dev;
> > > +	struct adis16475 *st;
> > > +	const struct spi_device_id *id = spi_get_device_id(spi);
> > > +	int ret;
> > > +
> > > +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> > > +	if (!indio_dev)
> > > +		return -ENOMEM;
> > > +
> > > +	st = iio_priv(indio_dev);
> > > +	st->info = &adis16475_chip_info[id->driver_data];
> > > +	spi_set_drvdata(spi, indio_dev);
> > > +
> > > +	ret = adis_init(&st->adis, indio_dev, spi, &st->info-
> > > > adis_data);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	indio_dev->dev.parent = &spi->dev;
> > > +	indio_dev->name = id->name;
> > > +	indio_dev->channels = st->info->channels;
> > > +	indio_dev->num_channels = st->info->num_channels;
> > > +	indio_dev->info = &adis16475_info;
> > > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > > +
> > > +	ret = __adis_initial_startup(&st->adis);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = adis16475_burst_config(st);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = adis16475_config_irq_pin(st);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = adis16475_config_ext_clk(st);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
> > > +						 adis16475_trigger_hand
> > > ler);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	adis16475_enable_irq(&st->adis, false);
> > > +
> > > +	ret = devm_iio_device_register(&spi->dev, indio_dev);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	adis16475_debugfs_init(indio_dev);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct spi_device_id adis16475_ids[] = {
> > 
> > Is it actually possible to instantiate this except by
> > using the dt table below?  If not, then move the 'data'
> > part into that table and don't provide an spi_device_id
> > table at all.  It's not relevant to the possible ways
> > of causing the driver to probe.
> 
> I guess we could use the id table with devicetree even without the dt
> table (even though it makes no sense).
> 
> So, I can remove it but I was using the id->name to set the the
> iio_dev
> name which I guess is not the right way?
> 
> What Im thinking is having a name/part number string in chip info
> that
> I can use to set the iio dev name. For parts that have the *-[1|2|3]
> variations I could use the devicetree iio label property. Is this the
> correct way of handling this?

I was misunderstanding some stuff here. So, the *-[1|2|3] are valid
part numbers so they can be in the `name`, right? So, labels come into
play, for example, when we have multiple instances of the same part,
right?
 
> - Nuno Sá
> > > +	{ "adis16470", ADIS16470 },
> > > +	{ "adis16475-1", ADIS16475_1 },
> > > +	{ "adis16475-2", ADIS16475_2 },
> > > +	{ "adis16475-3", ADIS16475_3 },
> > > +	{ "adis16477-1", ADIS16477_1 },
> > > +	{ "adis16477-2", ADIS16477_2 },
> > > +	{ "adis16477-3", ADIS16477_3 },
> > > +	{ "adis16465-1", ADIS16465_1 },
> > > +	{ "adis16465-2", ADIS16465_2 },
> > > +	{ "adis16465-3", ADIS16465_3 },
> > > +	{ "adis16467-1", ADIS16467_1 },
> > > +	{ "adis16467-2", ADIS16467_2 },
> > > +	{ "adis16467-3", ADIS16467_3 },
> > > +	{ "adis16500", ADIS16500 },
> > > +	{ "adis16505-1", ADIS16505_1 },
> > > +	{ "adis16505-2", ADIS16505_2 },
> > > +	{ "adis16505-3", ADIS16505_3 },
> > > +	{ "adis16507-1", ADIS16507_1 },
> > > +	{ "adis16507-2", ADIS16507_2 },
> > > +	{ "adis16507-3", ADIS16507_3 },
> > > +	{ }
> > > +};
> > > +MODULE_DEVICE_TABLE(spi, adis16475_ids);
> > > +
> > > +static const struct of_device_id adis16475_of_match[] = {
> > > +	{ .compatible = "adi,adis16470" },
> > > +	{ .compatible = "adi,adis16475-1" },
> > > +	{ .compatible = "adi,adis16475-2" },
> > > +	{ .compatible = "adi,adis16475-3" },
> > > +	{ .compatible = "adi,adis16477-1" },
> > > +	{ .compatible = "adi,adis16477-2" },
> > > +	{ .compatible = "adi,adis16477-3" },
> > > +	{ .compatible = "adi,adis16465-1" },
> > > +	{ .compatible = "adi,adis16465-2" },
> > > +	{ .compatible = "adi,adis16465-3" },
> > > +	{ .compatible = "adi,adis16467-1" },
> > > +	{ .compatible = "adi,adis16467-2" },
> > > +	{ .compatible = "adi,adis16467-3" },
> > > +	{ .compatible = "adi,adis16500" },
> > > +	{ .compatible = "adi,adis16505-1" },
> > > +	{ .compatible = "adi,adis16505-2" },
> > > +	{ .compatible = "adi,adis16505-3" },
> > > +	{ .compatible = "adi,adis16507-1" },
> > > +	{ .compatible = "adi,adis16507-2" },
> > > +	{ .compatible = "adi,adis16507-3" },
> > > +	{ },
> > > +};
> > > +MODULE_DEVICE_TABLE(of, adis16475_of_match);
> > > +
> > > +static struct spi_driver adis16475_driver = {
> > > +	.driver = {
> > > +		.name = "adis16475",
> > > +		.of_match_table = adis16475_of_match,
> > > +	},
> > > +	.id_table = adis16475_ids,
> > > +	.probe = adis16475_probe,
> > > +};
> > > +module_spi_driver(adis16475_driver);
> > > +
> > > +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
> > > +MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
> > > +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-04 18:00     ` Sa, Nuno
@ 2020-03-05 10:34       ` Lars-Peter Clausen
  2020-03-05 12:27         ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Lars-Peter Clausen @ 2020-03-05 10:34 UTC (permalink / raw)
  To: Sa, Nuno, jic23
  Cc: linux-iio, mark.rutland, Ardelean, Alexandru, pmeerw, knaack.h,
	Hennerich, Michael, devicetree, robh+dt

On 3/4/20 7:00 PM, Sa, Nuno wrote:
> On Tue, 2020-03-03 at 21:10 +0000, Jonathan Cameron wrote:
>> [External]
>>
>> On Tue, 25 Feb 2020 13:41:52 +0100
>> Nuno Sá <nuno.sa@analog.com> wrote:
>>
>>> Document the ADIS16475 device devicetree bindings.
>>>
>>> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
>> One thing inline on the burst mode stuff.
>>
>> Thanks,
>>
>> Jonathan
>>
>>> ---
>>>   .../bindings/iio/imu/adi,adis16475.yaml       | 130
>>> ++++++++++++++++++
>>>   MAINTAINERS                                   |   1 +
>>>   2 files changed, 131 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>>> b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>>> new file mode 100644
>>> index 000000000000..c0f2146e000c
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
>>> @@ -0,0 +1,130 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Analog Devices ADIS16475 and similar IMUs
>>> +
>>> +maintainers:
>>> +  - Nuno Sá <nuno.sa@analog.com>
>>> +
>>> +description: |
>>> +  Analog Devices ADIS16475 and similar IMUs
>>> +
>>> https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
>>> +
>>> +properties:
>>> +  compatible:
>>> +    enum:
>>> +      - adi,adis16475-1
>>> +      - adi,adis16475-2
>>> +      - adi,adis16475-3
>>> +      - adi,adis16477-1
>>> +      - adi,adis16477-2
>>> +      - adi,adis16477-3
>>> +      - adi,adis16470
>>> +      - adi,adis16465-1
>>> +      - adi,adis16465-2
>>> +      - adi,adis16465-3
>>> +      - adi,adis16467-1
>>> +      - adi,adis16467-2
>>> +      - adi,adis16467-3
>>> +      - adi,adis16500
>>> +      - adi,adis16505-1
>>> +      - adi,adis16505-2
>>> +      - adi,adis16505-3
>>> +      - adi,adis16507-1
>>> +      - adi,adis16507-2
>>> +      - adi,adis16507-3
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  spi-cpha: true
>>> +
>>> +  spi-cpol: true
>>> +
>>> +  spi-max-frequency:
>>> +    maximum: 2000000
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +
>>> +  clocks:
>>> +    maxItems: 1
>>> +
>>> +  clock-names:
>>> +    oneOf:
>>> +      - const: sync
>>> +      - const: direct-sync
>>> +      - const: pulse-sync
>>> +      - const: scaled-sync
>>> +
>>> +  reset-gpios:
>>> +    description:
>>> +      Must be the device tree identifier of the RESET pin. If
>>> specified,
>>> +      it will be asserted during driver probe. As the line is
>>> active low,
>>> +      it should be marked GPIO_ACTIVE_LOW.
>>> +    maxItems: 1
>>> +
>>> +  adi,scaled-output-hz:
>>> +    description:
>>> +      This property must be present if the clock mode is scaled-
>>> sync through
>>> +      clock-names property. In this mode, the input clock can have
>>> a range
>>> +      of 1Hz to 128HZ which must be scaled to originate an
>>> allowable sample
>>> +      rate. This property specifies that rate.
>>> +    minimum: 1900
>>> +    maximum: 2100
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +  - interrupts
>>> +  - spi-cpha
>>> +  - spi-cpol
>>> +
>>> +if:
>>> +  properties:
>>> +    compatible:
>>> +      contains:
>>> +        enum:
>>> +          - adi,adis16500
>>> +          - adi,adis16505-1
>>> +          - adi,adis16505-2
>>> +          - adi,adis16505-3
>>> +          - adi,adis16507-1
>>> +          - adi,adis16507-2
>>> +          - adi,adis16507-3
>>> +
>>> +then:
>>> +  properties:
>>> +    clock-names:
>>> +      oneOf:
>>> +        - const: sync
>>> +        - const: direct-sync
>>> +        - const: scaled-sync
>>> +
>>> +    adi,burst32-enable:
>>> +      description:
>>> +        Enable burst32 mode. In this mode, a burst reading
>>> contains calibrated
>>> +        gyroscope and accelerometer data in 32-bit format.
>> Why is this in DT?  Is it not a runtime decision
>> (ideally automatically selected)
> So, you mean just have this mode by default on parts that support it?

Maybe lets start with explaining what burst32 mode is, so everybody is 
on the same page.

The way registers are usually accessed for this chip is that you first 
write the address you want to read on the SPI bus and then read the 
selected register. This can be quite slow though if you want to read 
multiple registers and is too slow to be able to read all the data at 
full data rate. So there is a special burst mode which allows to read 
all the data registers in one go.

Now by default the data registers are 16-bit. But there is an internal 
decimation filter and the extra bits produced by the decimation filter 
go into additional data registers making the data 32-bit wide. The chip 
allows to configure whether to read the only 16-bit MSBs or the full 
32-bit register.

So the decision whether a user wants to use 32-bit or 16-bit depends on 
whether the extra 16-bit are needed or if they are even available. E.g. 
if the decimation filter is off there wont be any extra bits.

This means ideally it would be user configurable whether to use 16-bit 
or 32-bit burst mode, since it is application specific. The problem is 
we don't have an interface for changing the bit width of a buffer 
channel. Adding such an interface would require quite a bit of effort 
since the assumption currently is that the bit width does not chance. 
E.g. libiio assumes this and would stop working if it did change.

Maybe as a compromise for now. Use 32-bit burst when there is actually 
meaningful data is the LSBs, i.e. the decimation filter is used and 
disable it otherwise. And then think about how to make it configurable 
as a follow up action.

In my opinion there is should not be a difference in the userspace 
interface for chips that do support 32-bit burst and those that don't. 
For devices that don't support 32-bit burst it should be emulated by 
reading the LSB bits registers manually.

- Lars


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-03-05  9:58       ` Sa, Nuno
@ 2020-03-05 10:39         ` Lars-Peter Clausen
  2020-03-07 11:25           ` Jonathan Cameron
  2020-03-07 11:27         ` Jonathan Cameron
  1 sibling, 1 reply; 31+ messages in thread
From: Lars-Peter Clausen @ 2020-03-05 10:39 UTC (permalink / raw)
  To: Sa, Nuno, jic23
  Cc: linux-iio, devicetree, mark.rutland, pmeerw, Ardelean, Alexandru,
	Hennerich, Michael, knaack.h, robh+dt

On 3/5/20 10:58 AM, Sa, Nuno wrote:
> On Wed, 2020-03-04 at 17:59 +0000, Sa, Nuno wrote:
>> [External]
>>
>> On Tue, 2020-03-03 at 21:08 +0000, Jonathan Cameron wrote:
>>> [External]
>>>
>>> On Tue, 25 Feb 2020 13:41:51 +0100
>>> Nuno Sá <nuno.sa@analog.com> wrote:
>>>
>>>> Support ADIS16475 and similar IMU devices. These devices are
>>>> a precision, miniature MEMS inertial measurement unit (IMU) that
>>>> includes a triaxial gyroscope and a triaxial accelerometer. Each
>>>> inertial sensor combines with signal conditioning that optimizes
>>>> dynamic performance.
>>>>
>>>> The driver adds support for the following devices:
>>>>   * adis16470, adis16475, adis16477, adis16465, adis16467,
>>>> adis16500,
>>>>     adis16505, adis16507.
>>>>
>>>> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
>>> A few bits and pieces inline.
>>>
>>> Thanks,
>>>
>>> Jonathan
>>>
>>>
>>>> ---
>>>>   .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
>>>>   MAINTAINERS                                   |    8 +
>>>>   drivers/iio/imu/Kconfig                       |   13 +
>>>>   drivers/iio/imu/Makefile                      |    1 +
>>>>   drivers/iio/imu/adis16475.c                   | 1304
>>>> +++++++++++++++++
>>>>   5 files changed, 1333 insertions(+)
>>>>   create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-
>>>> adis16475
>>>>   create mode 100644 drivers/iio/imu/adis16475.c
>>>>
>>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-
>>>> adis16475
>>>> b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
>>>> new file mode 100644
>>>> index 000000000000..e2c3776035ea
>>>> --- /dev/null
>>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
>>>> @@ -0,0 +1,7 @@
>>>> +What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_ena
>>>> ble
>>>> +KernelVersion:
>>>> +Contact:	linux-iio@vger.kernel.org
>>>> +Description:
>>>> +		Use the device burst read mode when reading buffered
>>>> +		data. This mode provides a way to read a batch of
>>>> +		output data registers, using a continuous stream of
>>>> bits.
>>> See comment on this below.  I'm not keen on this being exposed to
>>> userspace
>>> because it will rarely have any idea how to set it.
>>>
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 8fa40c3eb72a..f11262f1f3bb 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -1008,6 +1008,14 @@ W:	
>>>> http://ez.analog.com/community/linux-device-drivers
>>>>   F:	drivers/iio/imu/adis16460.c
>>>>   F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460
>>>> .yaml
>>>>   
>>>> +ANALOG DEVICES INC ADIS16475 DRIVER
>>>> +M:	Nuno Sa <nuno.sa@analog.com>
>>>> +L:	linux-iio@vger.kernel.org
>>>> +W:	http://ez.analog.com/community/linux-device-drivers
>>>> +S:	Supported
>>>> +F:	drivers/iio/imu/adis16475.c
>>>> +F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
>>>> +
>>>>   ANALOG DEVICES INC ADM1177 DRIVER
>>>>   M:	Beniamin Bia <beniamin.bia@analog.com>
>>>>   M:	Michael Hennerich <Michael.Hennerich@analog.com>
>>>> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
>>>> index 60bb1029e759..fc4123d518bc 100644
>>>> --- a/drivers/iio/imu/Kconfig
>>>> +++ b/drivers/iio/imu/Kconfig
>>>> @@ -29,6 +29,19 @@ config ADIS16460
>>>>   	  To compile this driver as a module, choose M here: the module
>>>> will be
>>>>   	  called adis16460.
>>>>   
>>>> +config ADIS16475
>>>> +	tristate "Analog Devices ADIS16475 and similar IMU driver"
>>>> +	depends on SPI
>>>> +	select IIO_ADIS_LIB
>>>> +	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
>>>> +	help
>>>> +	  Say yes here to build support for Analog Devices ADIS16470,
>>>> ADIS16475,
>>>> +	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505,
>>>> ADIS16507 inertial
>>>> +	  sensors.
>>>> +
>>>> +	  To compile this driver as a module, choose M here: the module
>>>> will be
>>>> +	  called adis16475.
>>>> +
>>>>   config ADIS16480
>>>>   	tristate "Analog Devices ADIS16480 and similar IMU driver"
>>>>   	depends on SPI
>>>> diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
>>>> index 5237fd4bc384..88b2c4555230 100644
>>>> --- a/drivers/iio/imu/Makefile
>>>> +++ b/drivers/iio/imu/Makefile
>>>> @@ -6,6 +6,7 @@
>>>>   # When adding new entries keep the list in alphabetical order
>>>>   obj-$(CONFIG_ADIS16400) += adis16400.o
>>>>   obj-$(CONFIG_ADIS16460) += adis16460.o
>>>> +obj-$(CONFIG_ADIS16475) += adis16475.o
>>>>   obj-$(CONFIG_ADIS16480) += adis16480.o
>>>>   
>>>>   adis_lib-y += adis.o
>>>> diff --git a/drivers/iio/imu/adis16475.c
>>>> b/drivers/iio/imu/adis16475.c
>>>> new file mode 100644
>>>> index 000000000000..f7c637734ec8
>>>> --- /dev/null
>>>> +++ b/drivers/iio/imu/adis16475.c
>>>> @@ -0,0 +1,1304 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * ADIS16475 IMU driver
>>>> + *
>>>> + * Copyright 2019 Analog Devices Inc.
>>>> + */
>>>> +#include <asm/unaligned.h>
>>>> +#include <linux/bitfield.h>
>>>> +#include <linux/bitops.h>
>>>> +#include <linux/clk.h>
>>>> +#include <linux/debugfs.h>
>>>> +#include <linux/delay.h>
>>>> +#include <linux/device.h>
>>>> +#include <linux/kernel.h>
>>>> +#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/module.h>
>>>> +#include <linux/spi/spi.h>
>>>> +
>>>> +#define ADIS16475_REG_DIAG_STAT		0x02
>>>> +#define ADIS16475_REG_X_GYRO_L		0x04
>>>> +#define ADIS16475_REG_Y_GYRO_L		0x08
>>>> +#define ADIS16475_REG_Z_GYRO_L		0x0C
>>>> +#define ADIS16475_REG_X_ACCEL_L		0x10
>>>> +#define ADIS16475_REG_Y_ACCEL_L		0x14
>>>> +#define ADIS16475_REG_Z_ACCEL_L		0x18
>>>> +#define ADIS16475_REG_TEMP_OUT		0x1c
>>>> +#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
>>>> +#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
>>>> +#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
>>>> +#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
>>>> +#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
>>>> +#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
>>>> +#define ADIS16475_REG_FILT_CTRL		0x5c
>>>> +#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
>>>> +#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FI
>>>> LT_CTRL_MASK, x)
>>>> +#define ADIS16475_REG_MSG_CTRL		0x60
>>>> +#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
>>>> +#define ADIS16475_MSG_CTRL_DR_POL(x) \
>>>> +				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MA
>>>> SK, x)
>>>> +#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
>>>> +#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EX
>>>> T_CLK_MASK, x)
>>>> +#define ADIS16475_REG_UP_SCALE		0x62
>>>> +#define ADIS16475_REG_DEC_RATE		0x64
>>>> +#define ADIS16475_REG_GLOB_CMD		0x68
>>>> +#define ADIS16475_REG_FIRM_REV		0x6c
>>>> +#define ADIS16475_REG_FIRM_DM		0x6e
>>>> +#define ADIS16475_REG_FIRM_Y		0x70
>>>> +#define ADIS16475_REG_PROD_ID		0x72
>>>> +#define ADIS16475_REG_SERIAL_NUM	0x74
>>>> +#define ADIS16475_REG_FLASH_CNT		0x7c
>>>> +#define ADIS16500_BURST32_MASK		BIT(9)
>>>> +#define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BU
>>>> RST32_MASK, x)
>>>> +/* number of data elements in burst mode */
>>>> +#define ADIS16475_BURST_MAX_DATA	10
>>>> +#define ADIS16475_MAX_SCAN_DATA		15
>>>> +
>>>> +enum clk_mode {
>>>> +	ADIS16475_CLK_DIRECT = 1,
>>>> +	ADIS16475_CLK_SCALED,
>>>> +	ADIS16475_CLK_OUTPUT,
>>>> +	ADIS16475_CLK_PULSE = 5,
>>>> +};
>>>> +
>>>> +struct adis16475_clks {
>>>> +	const char *name;
>>>> +	enum clk_mode clk_mode;
>>>> +	u16 min_rate;
>>>> +	u16 max_rate;
>>>> +};
>>>> +
>>>> +struct adis16475_chip_info {
>>>> +	const struct iio_chan_spec *channels;
>>>> +	const struct adis16475_clks *clks;
>>>> +	const struct adis_data adis_data;
>>>> +	u32 num_channels;
>>>> +	u32 gyro_max_val;
>>>> +	u32 gyro_max_scale;
>>>> +	u32 accel_max_val;
>>>> +	u32 accel_max_scale;
>>>> +	u32 temp_scale;
>>>> +	u32 int_clk;
>>>> +	u16 max_dec;
>>>> +	u8 num_clks;
>>>> +	bool has_burst32;
>>>> +};
>>>> +
>>>> +struct adis16475 {
>>>> +	const struct adis16475_chip_info *info;
>>>> +	struct adis adis;
>>>> +	u32 clk_freq;
>>>> +	u32 cached_spi_speed_hz;
>>>> +	bool burst32;
>>>> +};
>>>> +
>>>> +enum {
>>>> +	ADIS16475_SCAN_GYRO_X,
>>>> +	ADIS16475_SCAN_GYRO_Y,
>>>> +	ADIS16475_SCAN_GYRO_Z,
>>>> +	ADIS16475_SCAN_ACCEL_X,
>>>> +	ADIS16475_SCAN_ACCEL_Y,
>>>> +	ADIS16475_SCAN_ACCEL_Z,
>>>> +	ADIS16475_SCAN_TEMP,
>>>> +	ADIS16475_SCAN_DIAG_S_FLAGS,
>>>> +	ADIS16475_SCAN_CRC_FAILURE,
>>>> +};
>>>> +
>>>> +#ifdef CONFIG_DEBUG_FS
>>>> +static ssize_t adis16475_show_firmware_revision(struct file
>>>> *file,
>>>> +						char __user *userbuf,
>>>> +						size_t count, loff_t
>>>> *ppos)
>>>> +{
>>>> +	struct adis16475 *st = file->private_data;
>>>> +	char buf[7];
>>>> +	size_t len;
>>>> +	u16 rev;
>>>> +	int ret;
>>>> +
>>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV,
>>>> &rev);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev &
>>>> 0xff);
>>>> +
>>>> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
>>>> +}
>>>> +
>>>> +static const struct file_operations
>>>> adis16475_firmware_revision_fops = {
>>>> +	.open = simple_open,
>>>> +	.read = adis16475_show_firmware_revision,
>>>> +	.llseek = default_llseek,
>>>> +	.owner = THIS_MODULE,
>>>> +};
>>>> +
>>>> +static ssize_t adis16475_show_firmware_date(struct file *file,
>>>> +					    char __user *userbuf,
>>>> +					    size_t count, loff_t *ppos)
>>>> +{
>>>> +	struct adis16475 *st = file->private_data;
>>>> +	u16 md, year;
>>>> +	char buf[12];
>>>> +	size_t len;
>>>> +	int ret;
>>>> +
>>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8,
>>>> md & 0xff,
>>>> +		       year);
>>>> +
>>>> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
>>>> +}
>>>> +
>>>> +static const struct file_operations adis16475_firmware_date_fops
>>>> =
>>>> {
>>>> +	.open = simple_open,
>>>> +	.read = adis16475_show_firmware_date,
>>>> +	.llseek = default_llseek,
>>>> +	.owner = THIS_MODULE,
>>>> +};
>>>> +
>>>> +static int adis16475_show_serial_number(void *arg, u64 *val)
>>>> +{
>>>> +	struct adis16475 *st = arg;
>>>> +	u16 serial;
>>>> +	int ret;
>>>> +
>>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM,
>>>> &serial);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	*val = serial;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
>>>> +			adis16475_show_serial_number, NULL,
>>>> "0x%.4llx\n");
>>>> +
>>>> +static int adis16475_show_product_id(void *arg, u64 *val)
>>>> +{
>>>> +	struct adis16475 *st = arg;
>>>> +	u16 prod_id;
>>>> +	int ret;
>>>> +
>>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID,
>>>> &prod_id);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	*val = prod_id;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
>>>> +			adis16475_show_product_id, NULL, "%llu\n");
>>>> +
>>>> +static int adis16475_show_flash_count(void *arg, u64 *val)
>>>> +{
>>>> +	struct adis16475 *st = arg;
>>>> +	u32 flash_count;
>>>> +	int ret;
>>>> +
>>>> +	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
>>>> +			       &flash_count);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	*val = flash_count;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
>>>> +			adis16475_show_flash_count, NULL, "%lld\n");
>>>> +
>>>> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
>>>> +{
>>>> +	struct adis16475 *st = iio_priv(indio_dev);
>>>> +
>>>> +	debugfs_create_file("serial_number", 0400, indio_dev-
>>>>> debugfs_dentry,
>>>> +			    st, &adis16475_serial_number_fops);
>>>> +	debugfs_create_file("product_id", 0400, indio_dev-
>>>>> debugfs_dentry, st,
>>>> +			    &adis16475_product_id_fops);
>>>> +	debugfs_create_file("flash_count", 0400, indio_dev-
>>>>> debugfs_dentry, st,
>>>> +			    &adis16475_flash_count_fops);
>>>> +	debugfs_create_file("firmware_revision", 0400,
>>>> +			    indio_dev->debugfs_dentry, st,
>>>> +			    &adis16475_firmware_revision_fops);
>>>> +	debugfs_create_file("firmware_date", 0400, indio_dev-
>>>>> debugfs_dentry,
>>>> +			    st, &adis16475_firmware_date_fops);
>>>> +	return 0;
>>>> +}
>>>> +#else
>>>> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
>>>> +{
>>>> +	return 0;
>>>> +}
>>>> +#endif
>>>> +
>>>> +static ssize_t adis16475_burst_mode_enable_get(struct device
>>>> *dev,
>>>> +					       struct device_attribute
>>>> *attr,
>>>> +					       char *buf)
>>>> +{
>>>> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
>>>> +
>>>> +	return sprintf(buf, "%d\n", st->adis.burst->en);
>>>> +}
>>>> +
>>>> +static ssize_t adis16475_burst_mode_enable_set(struct device
>>>> *dev,
>>>> +					       struct device_attribute
>>>> *attr,
>>>> +					       const char *buf, size_t
>>>> len)
>>>> +{
>>>> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
>>>> +	bool val;
>>>> +	int ret;
>>>> +
>>>> +	ret = kstrtobool(buf, &val);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	if (val)
>>>> +		/* 1MHz max in burst mode */
>>>> +		st->adis.spi->max_speed_hz = 1000000;
>>>> +	else
>>>> +		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
>>>> +
>>>> +	st->adis.burst->en = val;
>>>> +
>>>> +	return len;
>>>> +}
>>>> +
>>>> +static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
>>>> +		       adis16475_burst_mode_enable_get,
>>>> +		       adis16475_burst_mode_enable_set, 0);
>>>> +
>>>> +static struct attribute *adis16475_attributes[] = {
>>>> +	&iio_dev_attr_burst_mode_enable.dev_attr.attr,
>>> Hmm.  Normally we try to avoid exposing this and make the decision
>>> automatically based on which channels are enabled.
>> Hmm. In that case, the decision would probably have to go to the
>> library since it is there that the "preparations" for buffered mode
>> are
>> done. Mostly, the data we are interested in the burst data is gyro,
>> accel and temp. So to make the decision based on which channels are
>> enabled is not that straight. Should we enable it only when all
>> channels are enabled? Some of them (and which)?
> I thought a little bit more about it and we could do some math in the
> lib to know when using burst mode becomes faster (depending on enabled
> scan elements). The library would need to know about the burst max spi
> frequency and also some minor changes in how burst_len is being
> calculated (drivers should explicitly set this rather than the
> library). The question is, is it worth it to go with this extra work
> :)?

You can leave it out of the initial version and always use burst mode 
and then add support for this in a follow up patch if it is worth it.

- Lars


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-05 10:34       ` Lars-Peter Clausen
@ 2020-03-05 12:27         ` Sa, Nuno
  2020-03-05 12:43           ` Lars-Peter Clausen
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-05 12:27 UTC (permalink / raw)
  To: jic23, lars
  Cc: Ardelean, Alexandru, linux-iio, devicetree, mark.rutland, pmeerw,
	knaack.h, Hennerich, Michael, robh+dt

On Thu, 2020-03-05 at 11:34 +0100, Lars-Peter Clausen wrote:
> On 3/4/20 7:00 PM, Sa, Nuno wrote:
> > On Tue, 2020-03-03 at 21:10 +0000, Jonathan Cameron wrote:
> > > 
> > > On Tue, 25 Feb 2020 13:41:52 +0100
> > > Nuno Sá <nuno.sa@analog.com> wrote:
> > > 
> > > > Document the ADIS16475 device devicetree bindings.
> > > > 
> > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> > > One thing inline on the burst mode stuff.
> > > 
> > > Thanks,
> > > 
> > > Jonathan
> > > 
> > > > ---
> > > >   .../bindings/iio/imu/adi,adis16475.yaml       | 130
> > > > ++++++++++++++++++
> > > >   MAINTAINERS                                   |   1 +
> > > >   2 files changed, 131 insertions(+)
> > > >   create mode 100644
> > > > Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > 
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > new file mode 100644
> > > > index 000000000000..c0f2146e000c
> > > > --- /dev/null
> > > > +++
> > > > b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
> > > > @@ -0,0 +1,130 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/iio/imu/adi,adis16475.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Analog Devices ADIS16475 and similar IMUs
> > > > +
> > > > +maintainers:
> > > > +  - Nuno Sá <nuno.sa@analog.com>
> > > > +
> > > > +description: |
> > > > +  Analog Devices ADIS16475 and similar IMUs
> > > > +
> > > > https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16475.pdf
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    enum:
> > > > +      - adi,adis16475-1
> > > > +      - adi,adis16475-2
> > > > +      - adi,adis16475-3
> > > > +      - adi,adis16477-1
> > > > +      - adi,adis16477-2
> > > > +      - adi,adis16477-3
> > > > +      - adi,adis16470
> > > > +      - adi,adis16465-1
> > > > +      - adi,adis16465-2
> > > > +      - adi,adis16465-3
> > > > +      - adi,adis16467-1
> > > > +      - adi,adis16467-2
> > > > +      - adi,adis16467-3
> > > > +      - adi,adis16500
> > > > +      - adi,adis16505-1
> > > > +      - adi,adis16505-2
> > > > +      - adi,adis16505-3
> > > > +      - adi,adis16507-1
> > > > +      - adi,adis16507-2
> > > > +      - adi,adis16507-3
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  spi-cpha: true
> > > > +
> > > > +  spi-cpol: true
> > > > +
> > > > +  spi-max-frequency:
> > > > +    maximum: 2000000
> > > > +
> > > > +  interrupts:
> > > > +    maxItems: 1
> > > > +
> > > > +  clocks:
> > > > +    maxItems: 1
> > > > +
> > > > +  clock-names:
> > > > +    oneOf:
> > > > +      - const: sync
> > > > +      - const: direct-sync
> > > > +      - const: pulse-sync
> > > > +      - const: scaled-sync
> > > > +
> > > > +  reset-gpios:
> > > > +    description:
> > > > +      Must be the device tree identifier of the RESET pin. If
> > > > specified,
> > > > +      it will be asserted during driver probe. As the line is
> > > > active low,
> > > > +      it should be marked GPIO_ACTIVE_LOW.
> > > > +    maxItems: 1
> > > > +
> > > > +  adi,scaled-output-hz:
> > > > +    description:
> > > > +      This property must be present if the clock mode is
> > > > scaled-
> > > > sync through
> > > > +      clock-names property. In this mode, the input clock can
> > > > have
> > > > a range
> > > > +      of 1Hz to 128HZ which must be scaled to originate an
> > > > allowable sample
> > > > +      rate. This property specifies that rate.
> > > > +    minimum: 1900
> > > > +    maximum: 2100
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +  - interrupts
> > > > +  - spi-cpha
> > > > +  - spi-cpol
> > > > +
> > > > +if:
> > > > +  properties:
> > > > +    compatible:
> > > > +      contains:
> > > > +        enum:
> > > > +          - adi,adis16500
> > > > +          - adi,adis16505-1
> > > > +          - adi,adis16505-2
> > > > +          - adi,adis16505-3
> > > > +          - adi,adis16507-1
> > > > +          - adi,adis16507-2
> > > > +          - adi,adis16507-3
> > > > +
> > > > +then:
> > > > +  properties:
> > > > +    clock-names:
> > > > +      oneOf:
> > > > +        - const: sync
> > > > +        - const: direct-sync
> > > > +        - const: scaled-sync
> > > > +
> > > > +    adi,burst32-enable:
> > > > +      description:
> > > > +        Enable burst32 mode. In this mode, a burst reading
> > > > contains calibrated
> > > > +        gyroscope and accelerometer data in 32-bit format.
> > > Why is this in DT?  Is it not a runtime decision
> > > (ideally automatically selected)
> > So, you mean just have this mode by default on parts that support
> > it?
> 
> Maybe lets start with explaining what burst32 mode is, so everybody
> is 
> on the same page.
> 
> The way registers are usually accessed for this chip is that you
> first 
> write the address you want to read on the SPI bus and then read the 
> selected register. This can be quite slow though if you want to read 
> multiple registers and is too slow to be able to read all the data
> at 
> full data rate. So there is a special burst mode which allows to
> read 
> all the data registers in one go.
> 
> Now by default the data registers are 16-bit. But there is an
> internal 
> decimation filter and the extra bits produced by the decimation
> filter 
> go into additional data registers making the data 32-bit wide. The
> chip 
> allows to configure whether to read the only 16-bit MSBs or the full 
> 32-bit register.
> 
> So the decision whether a user wants to use 32-bit or 16-bit depends
> on 
> whether the extra 16-bit are needed or if they are even available.
> E.g. 
> if the decimation filter is off there wont be any extra bits.
> 
> This means ideally it would be user configurable whether to use 16-
> bit 
> or 32-bit burst mode, since it is application specific. The problem
> is 
> we don't have an interface for changing the bit width of a buffer 
> channel. Adding such an interface would require quite a bit of
> effort 
> since the assumption currently is that the bit width does not
> chance. 
> E.g. libiio assumes this and would stop working if it did change.
> 
> Maybe as a compromise for now. Use 32-bit burst when there is
> actually 
> meaningful data is the LSBs, i.e. the decimation filter is used and 
> disable it otherwise. And then think about how to make it
> configurable 
> as a follow up action.

I do agree with that. Just to add that I think we also need to take
into account the FIR filter which can also be responsible for bit
growth. I will cache these values and if one of them is != 0 than burst
32 will be used...

> In my opinion there is should not be a difference in the userspace 
> interface for chips that do support 32-bit burst and those that
> don't. 
> For devices that don't support 32-bit burst it should be emulated by 
> reading the LSB bits registers manually.

Hmm. In terms of interface I think there is no difference. We always
report 32bits channels (for accel and gyro). However, what we do right
know is just to set the LSB to 0 if burst32 is not supported. So, we
can be just ignoring the LSB bits if they are being used...

- Nuno Sá
> - Lars
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-05 12:27         ` Sa, Nuno
@ 2020-03-05 12:43           ` Lars-Peter Clausen
  2020-03-05 13:04             ` Sa, Nuno
  0 siblings, 1 reply; 31+ messages in thread
From: Lars-Peter Clausen @ 2020-03-05 12:43 UTC (permalink / raw)
  To: Sa, Nuno, jic23
  Cc: Ardelean, Alexandru, linux-iio, devicetree, mark.rutland, pmeerw,
	knaack.h, Hennerich, Michael, robh+dt

On 3/5/20 1:27 PM, Sa, Nuno wrote:
>
>> In my opinion there is should not be a difference in the userspace
>> interface for chips that do support 32-bit burst and those that
>> don't.
>> For devices that don't support 32-bit burst it should be emulated by
>> reading the LSB bits registers manually.
> Hmm. In terms of interface I think there is no difference. We always
> report 32bits channels (for accel and gyro). However, what we do right
> know is just to set the LSB to 0 if burst32 is not supported. So, we
> can be just ignoring the LSB bits if they are being used...

What I meant was that somebody might still want to get the full 32-bit 
values in buffered mode, even if the device does not support burst32. In 
that case you can first do a 16-bit burst read to get the MSBs and then 
do manual reads of all the LSB registers and then put both into the buffer.

- Lars


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-05 12:43           ` Lars-Peter Clausen
@ 2020-03-05 13:04             ` Sa, Nuno
  2020-03-07 11:33               ` Jonathan Cameron
  0 siblings, 1 reply; 31+ messages in thread
From: Sa, Nuno @ 2020-03-05 13:04 UTC (permalink / raw)
  To: jic23, lars
  Cc: Ardelean, Alexandru, linux-iio, devicetree, mark.rutland, pmeerw,
	knaack.h, Hennerich, Michael, robh+dt

On Thu, 2020-03-05 at 13:43 +0100, Lars-Peter Clausen wrote:
> On 3/5/20 1:27 PM, Sa, Nuno wrote:
> > > In my opinion there is should not be a difference in the
> > > userspace
> > > interface for chips that do support 32-bit burst and those that
> > > don't.
> > > For devices that don't support 32-bit burst it should be emulated
> > > by
> > > reading the LSB bits registers manually.
> > Hmm. In terms of interface I think there is no difference. We
> > always
> > report 32bits channels (for accel and gyro). However, what we do
> > right
> > know is just to set the LSB to 0 if burst32 is not supported. So,
> > we
> > can be just ignoring the LSB bits if they are being used...
> 
> What I meant was that somebody might still want to get the full 32-
> bit 
> values in buffered mode, even if the device does not support burst32.

They are. Just that the LSB part is always set to 0 :). And that, in my
opinion, is wrong. As you say, we should do the manual readings if
there are any bits on the LSB registers...

- Nuno Sá
> In 
> that case you can first do a 16-bit burst read to get the MSBs and
> then 
> do manual reads of all the LSB registers and then put both into the
> buffer.
> - Lars
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-03-05 10:39         ` Lars-Peter Clausen
@ 2020-03-07 11:25           ` Jonathan Cameron
  0 siblings, 0 replies; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-07 11:25 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Sa, Nuno, linux-iio, devicetree, mark.rutland, pmeerw, Ardelean,
	Alexandru, Hennerich, Michael, knaack.h, robh+dt

On Thu, 5 Mar 2020 11:39:36 +0100
Lars-Peter Clausen <lars@metafoo.de> wrote:

> On 3/5/20 10:58 AM, Sa, Nuno wrote:
> > On Wed, 2020-03-04 at 17:59 +0000, Sa, Nuno wrote:  
> >> [External]
> >>
> >> On Tue, 2020-03-03 at 21:08 +0000, Jonathan Cameron wrote:  
> >>> [External]
> >>>
> >>> On Tue, 25 Feb 2020 13:41:51 +0100
> >>> Nuno Sá <nuno.sa@analog.com> wrote:
> >>>  
> >>>> Support ADIS16475 and similar IMU devices. These devices are
> >>>> a precision, miniature MEMS inertial measurement unit (IMU) that
> >>>> includes a triaxial gyroscope and a triaxial accelerometer. Each
> >>>> inertial sensor combines with signal conditioning that optimizes
> >>>> dynamic performance.
> >>>>
> >>>> The driver adds support for the following devices:
> >>>>   * adis16470, adis16475, adis16477, adis16465, adis16467,
> >>>> adis16500,
> >>>>     adis16505, adis16507.
> >>>>
> >>>> Signed-off-by: Nuno Sá <nuno.sa@analog.com>  
> >>> A few bits and pieces inline.
> >>>
> >>> Thanks,
> >>>
> >>> Jonathan
> >>>
> >>>  
> >>>> ---
> >>>>   .../ABI/testing/sysfs-bus-iio-imu-adis16475   |    7 +
> >>>>   MAINTAINERS                                   |    8 +
> >>>>   drivers/iio/imu/Kconfig                       |   13 +
> >>>>   drivers/iio/imu/Makefile                      |    1 +
> >>>>   drivers/iio/imu/adis16475.c                   | 1304
> >>>> +++++++++++++++++
> >>>>   5 files changed, 1333 insertions(+)
> >>>>   create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-imu-
> >>>> adis16475
> >>>>   create mode 100644 drivers/iio/imu/adis16475.c
> >>>>
> >>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-imu-
> >>>> adis16475
> >>>> b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> >>>> new file mode 100644
> >>>> index 000000000000..e2c3776035ea
> >>>> --- /dev/null
> >>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> >>>> @@ -0,0 +1,7 @@
> >>>> +What:		/sys/bus/iio/devices/iio:deviceX/burst_mode_ena
> >>>> ble
> >>>> +KernelVersion:
> >>>> +Contact:	linux-iio@vger.kernel.org
> >>>> +Description:
> >>>> +		Use the device burst read mode when reading buffered
> >>>> +		data. This mode provides a way to read a batch of
> >>>> +		output data registers, using a continuous stream of
> >>>> bits.  
> >>> See comment on this below.  I'm not keen on this being exposed to
> >>> userspace
> >>> because it will rarely have any idea how to set it.
> >>>  
> >>>> diff --git a/MAINTAINERS b/MAINTAINERS
> >>>> index 8fa40c3eb72a..f11262f1f3bb 100644
> >>>> --- a/MAINTAINERS
> >>>> +++ b/MAINTAINERS
> >>>> @@ -1008,6 +1008,14 @@ W:	
> >>>> http://ez.analog.com/community/linux-device-drivers
> >>>>   F:	drivers/iio/imu/adis16460.c
> >>>>   F:	Documentation/devicetree/bindings/iio/imu/adi,adis16460
> >>>> .yaml
> >>>>   
> >>>> +ANALOG DEVICES INC ADIS16475 DRIVER
> >>>> +M:	Nuno Sa <nuno.sa@analog.com>
> >>>> +L:	linux-iio@vger.kernel.org
> >>>> +W:	http://ez.analog.com/community/linux-device-drivers
> >>>> +S:	Supported
> >>>> +F:	drivers/iio/imu/adis16475.c
> >>>> +F:	Documentation/ABI/testing/sysfs-bus-iio-imu-adis16475
> >>>> +
> >>>>   ANALOG DEVICES INC ADM1177 DRIVER
> >>>>   M:	Beniamin Bia <beniamin.bia@analog.com>
> >>>>   M:	Michael Hennerich <Michael.Hennerich@analog.com>
> >>>> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> >>>> index 60bb1029e759..fc4123d518bc 100644
> >>>> --- a/drivers/iio/imu/Kconfig
> >>>> +++ b/drivers/iio/imu/Kconfig
> >>>> @@ -29,6 +29,19 @@ config ADIS16460
> >>>>   	  To compile this driver as a module, choose M here: the module
> >>>> will be
> >>>>   	  called adis16460.
> >>>>   
> >>>> +config ADIS16475
> >>>> +	tristate "Analog Devices ADIS16475 and similar IMU driver"
> >>>> +	depends on SPI
> >>>> +	select IIO_ADIS_LIB
> >>>> +	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
> >>>> +	help
> >>>> +	  Say yes here to build support for Analog Devices ADIS16470,
> >>>> ADIS16475,
> >>>> +	  ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505,
> >>>> ADIS16507 inertial
> >>>> +	  sensors.
> >>>> +
> >>>> +	  To compile this driver as a module, choose M here: the module
> >>>> will be
> >>>> +	  called adis16475.
> >>>> +
> >>>>   config ADIS16480
> >>>>   	tristate "Analog Devices ADIS16480 and similar IMU driver"
> >>>>   	depends on SPI
> >>>> diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> >>>> index 5237fd4bc384..88b2c4555230 100644
> >>>> --- a/drivers/iio/imu/Makefile
> >>>> +++ b/drivers/iio/imu/Makefile
> >>>> @@ -6,6 +6,7 @@
> >>>>   # When adding new entries keep the list in alphabetical order
> >>>>   obj-$(CONFIG_ADIS16400) += adis16400.o
> >>>>   obj-$(CONFIG_ADIS16460) += adis16460.o
> >>>> +obj-$(CONFIG_ADIS16475) += adis16475.o
> >>>>   obj-$(CONFIG_ADIS16480) += adis16480.o
> >>>>   
> >>>>   adis_lib-y += adis.o
> >>>> diff --git a/drivers/iio/imu/adis16475.c
> >>>> b/drivers/iio/imu/adis16475.c
> >>>> new file mode 100644
> >>>> index 000000000000..f7c637734ec8
> >>>> --- /dev/null
> >>>> +++ b/drivers/iio/imu/adis16475.c
> >>>> @@ -0,0 +1,1304 @@
> >>>> +// SPDX-License-Identifier: GPL-2.0
> >>>> +/*
> >>>> + * ADIS16475 IMU driver
> >>>> + *
> >>>> + * Copyright 2019 Analog Devices Inc.
> >>>> + */
> >>>> +#include <asm/unaligned.h>
> >>>> +#include <linux/bitfield.h>
> >>>> +#include <linux/bitops.h>
> >>>> +#include <linux/clk.h>
> >>>> +#include <linux/debugfs.h>
> >>>> +#include <linux/delay.h>
> >>>> +#include <linux/device.h>
> >>>> +#include <linux/kernel.h>
> >>>> +#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/module.h>
> >>>> +#include <linux/spi/spi.h>
> >>>> +
> >>>> +#define ADIS16475_REG_DIAG_STAT		0x02
> >>>> +#define ADIS16475_REG_X_GYRO_L		0x04
> >>>> +#define ADIS16475_REG_Y_GYRO_L		0x08
> >>>> +#define ADIS16475_REG_Z_GYRO_L		0x0C
> >>>> +#define ADIS16475_REG_X_ACCEL_L		0x10
> >>>> +#define ADIS16475_REG_Y_ACCEL_L		0x14
> >>>> +#define ADIS16475_REG_Z_ACCEL_L		0x18
> >>>> +#define ADIS16475_REG_TEMP_OUT		0x1c
> >>>> +#define ADIS16475_REG_X_GYRO_BIAS_L	0x40
> >>>> +#define ADIS16475_REG_Y_GYRO_BIAS_L	0x44
> >>>> +#define ADIS16475_REG_Z_GYRO_BIAS_L	0x48
> >>>> +#define ADIS16475_REG_X_ACCEL_BIAS_L	0x4c
> >>>> +#define ADIS16475_REG_Y_ACCEL_BIAS_L	0x50
> >>>> +#define ADIS16475_REG_Z_ACCEL_BIAS_L	0x54
> >>>> +#define ADIS16475_REG_FILT_CTRL		0x5c
> >>>> +#define ADIS16475_FILT_CTRL_MASK	GENMASK(2, 0)
> >>>> +#define ADIS16475_FILT_CTRL(x)		FIELD_PREP(ADIS16475_FI
> >>>> LT_CTRL_MASK, x)
> >>>> +#define ADIS16475_REG_MSG_CTRL		0x60
> >>>> +#define ADIS16475_MSG_CTRL_DR_POL_MASK	BIT(0)
> >>>> +#define ADIS16475_MSG_CTRL_DR_POL(x) \
> >>>> +				FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MA
> >>>> SK, x)
> >>>> +#define ADIS16475_EXT_CLK_MASK		GENMASK(4, 2)
> >>>> +#define ADIS16475_EXT_CLK(x)		FIELD_PREP(ADIS16475_EX
> >>>> T_CLK_MASK, x)
> >>>> +#define ADIS16475_REG_UP_SCALE		0x62
> >>>> +#define ADIS16475_REG_DEC_RATE		0x64
> >>>> +#define ADIS16475_REG_GLOB_CMD		0x68
> >>>> +#define ADIS16475_REG_FIRM_REV		0x6c
> >>>> +#define ADIS16475_REG_FIRM_DM		0x6e
> >>>> +#define ADIS16475_REG_FIRM_Y		0x70
> >>>> +#define ADIS16475_REG_PROD_ID		0x72
> >>>> +#define ADIS16475_REG_SERIAL_NUM	0x74
> >>>> +#define ADIS16475_REG_FLASH_CNT		0x7c
> >>>> +#define ADIS16500_BURST32_MASK		BIT(9)
> >>>> +#define ADIS16500_BURST32(x)		FIELD_PREP(ADIS16500_BU
> >>>> RST32_MASK, x)
> >>>> +/* number of data elements in burst mode */
> >>>> +#define ADIS16475_BURST_MAX_DATA	10
> >>>> +#define ADIS16475_MAX_SCAN_DATA		15
> >>>> +
> >>>> +enum clk_mode {
> >>>> +	ADIS16475_CLK_DIRECT = 1,
> >>>> +	ADIS16475_CLK_SCALED,
> >>>> +	ADIS16475_CLK_OUTPUT,
> >>>> +	ADIS16475_CLK_PULSE = 5,
> >>>> +};
> >>>> +
> >>>> +struct adis16475_clks {
> >>>> +	const char *name;
> >>>> +	enum clk_mode clk_mode;
> >>>> +	u16 min_rate;
> >>>> +	u16 max_rate;
> >>>> +};
> >>>> +
> >>>> +struct adis16475_chip_info {
> >>>> +	const struct iio_chan_spec *channels;
> >>>> +	const struct adis16475_clks *clks;
> >>>> +	const struct adis_data adis_data;
> >>>> +	u32 num_channels;
> >>>> +	u32 gyro_max_val;
> >>>> +	u32 gyro_max_scale;
> >>>> +	u32 accel_max_val;
> >>>> +	u32 accel_max_scale;
> >>>> +	u32 temp_scale;
> >>>> +	u32 int_clk;
> >>>> +	u16 max_dec;
> >>>> +	u8 num_clks;
> >>>> +	bool has_burst32;
> >>>> +};
> >>>> +
> >>>> +struct adis16475 {
> >>>> +	const struct adis16475_chip_info *info;
> >>>> +	struct adis adis;
> >>>> +	u32 clk_freq;
> >>>> +	u32 cached_spi_speed_hz;
> >>>> +	bool burst32;
> >>>> +};
> >>>> +
> >>>> +enum {
> >>>> +	ADIS16475_SCAN_GYRO_X,
> >>>> +	ADIS16475_SCAN_GYRO_Y,
> >>>> +	ADIS16475_SCAN_GYRO_Z,
> >>>> +	ADIS16475_SCAN_ACCEL_X,
> >>>> +	ADIS16475_SCAN_ACCEL_Y,
> >>>> +	ADIS16475_SCAN_ACCEL_Z,
> >>>> +	ADIS16475_SCAN_TEMP,
> >>>> +	ADIS16475_SCAN_DIAG_S_FLAGS,
> >>>> +	ADIS16475_SCAN_CRC_FAILURE,
> >>>> +};
> >>>> +
> >>>> +#ifdef CONFIG_DEBUG_FS
> >>>> +static ssize_t adis16475_show_firmware_revision(struct file
> >>>> *file,
> >>>> +						char __user *userbuf,
> >>>> +						size_t count, loff_t
> >>>> *ppos)
> >>>> +{
> >>>> +	struct adis16475 *st = file->private_data;
> >>>> +	char buf[7];
> >>>> +	size_t len;
> >>>> +	u16 rev;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_REV,
> >>>> &rev);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev &
> >>>> 0xff);
> >>>> +
> >>>> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> >>>> +}
> >>>> +
> >>>> +static const struct file_operations
> >>>> adis16475_firmware_revision_fops = {
> >>>> +	.open = simple_open,
> >>>> +	.read = adis16475_show_firmware_revision,
> >>>> +	.llseek = default_llseek,
> >>>> +	.owner = THIS_MODULE,
> >>>> +};
> >>>> +
> >>>> +static ssize_t adis16475_show_firmware_date(struct file *file,
> >>>> +					    char __user *userbuf,
> >>>> +					    size_t count, loff_t *ppos)
> >>>> +{
> >>>> +	struct adis16475 *st = file->private_data;
> >>>> +	u16 md, year;
> >>>> +	char buf[12];
> >>>> +	size_t len;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_Y, &year);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIRM_DM, &md);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", md >> 8,
> >>>> md & 0xff,
> >>>> +		       year);
> >>>> +
> >>>> +	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
> >>>> +}
> >>>> +
> >>>> +static const struct file_operations adis16475_firmware_date_fops
> >>>> =
> >>>> {
> >>>> +	.open = simple_open,
> >>>> +	.read = adis16475_show_firmware_date,
> >>>> +	.llseek = default_llseek,
> >>>> +	.owner = THIS_MODULE,
> >>>> +};
> >>>> +
> >>>> +static int adis16475_show_serial_number(void *arg, u64 *val)
> >>>> +{
> >>>> +	struct adis16475 *st = arg;
> >>>> +	u16 serial;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_SERIAL_NUM,
> >>>> &serial);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	*val = serial;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_serial_number_fops,
> >>>> +			adis16475_show_serial_number, NULL,
> >>>> "0x%.4llx\n");
> >>>> +
> >>>> +static int adis16475_show_product_id(void *arg, u64 *val)
> >>>> +{
> >>>> +	struct adis16475 *st = arg;
> >>>> +	u16 prod_id;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = adis_read_reg_16(&st->adis, ADIS16475_REG_PROD_ID,
> >>>> &prod_id);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	*val = prod_id;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_product_id_fops,
> >>>> +			adis16475_show_product_id, NULL, "%llu\n");
> >>>> +
> >>>> +static int adis16475_show_flash_count(void *arg, u64 *val)
> >>>> +{
> >>>> +	struct adis16475 *st = arg;
> >>>> +	u32 flash_count;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = adis_read_reg_32(&st->adis, ADIS16475_REG_FLASH_CNT,
> >>>> +			       &flash_count);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	*val = flash_count;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +DEFINE_SIMPLE_ATTRIBUTE(adis16475_flash_count_fops,
> >>>> +			adis16475_show_flash_count, NULL, "%lld\n");
> >>>> +
> >>>> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> >>>> +{
> >>>> +	struct adis16475 *st = iio_priv(indio_dev);
> >>>> +
> >>>> +	debugfs_create_file("serial_number", 0400, indio_dev-  
> >>>>> debugfs_dentry,  
> >>>> +			    st, &adis16475_serial_number_fops);
> >>>> +	debugfs_create_file("product_id", 0400, indio_dev-  
> >>>>> debugfs_dentry, st,  
> >>>> +			    &adis16475_product_id_fops);
> >>>> +	debugfs_create_file("flash_count", 0400, indio_dev-  
> >>>>> debugfs_dentry, st,  
> >>>> +			    &adis16475_flash_count_fops);
> >>>> +	debugfs_create_file("firmware_revision", 0400,
> >>>> +			    indio_dev->debugfs_dentry, st,
> >>>> +			    &adis16475_firmware_revision_fops);
> >>>> +	debugfs_create_file("firmware_date", 0400, indio_dev-  
> >>>>> debugfs_dentry,  
> >>>> +			    st, &adis16475_firmware_date_fops);
> >>>> +	return 0;
> >>>> +}
> >>>> +#else
> >>>> +static int adis16475_debugfs_init(struct iio_dev *indio_dev)
> >>>> +{
> >>>> +	return 0;
> >>>> +}
> >>>> +#endif
> >>>> +
> >>>> +static ssize_t adis16475_burst_mode_enable_get(struct device
> >>>> *dev,
> >>>> +					       struct device_attribute
> >>>> *attr,
> >>>> +					       char *buf)
> >>>> +{
> >>>> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> >>>> +
> >>>> +	return sprintf(buf, "%d\n", st->adis.burst->en);
> >>>> +}
> >>>> +
> >>>> +static ssize_t adis16475_burst_mode_enable_set(struct device
> >>>> *dev,
> >>>> +					       struct device_attribute
> >>>> *attr,
> >>>> +					       const char *buf, size_t
> >>>> len)
> >>>> +{
> >>>> +	struct adis16475 *st = iio_priv(dev_to_iio_dev(dev));
> >>>> +	bool val;
> >>>> +	int ret;
> >>>> +
> >>>> +	ret = kstrtobool(buf, &val);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	if (val)
> >>>> +		/* 1MHz max in burst mode */
> >>>> +		st->adis.spi->max_speed_hz = 1000000;
> >>>> +	else
> >>>> +		st->adis.spi->max_speed_hz = st->cached_spi_speed_hz;
> >>>> +
> >>>> +	st->adis.burst->en = val;
> >>>> +
> >>>> +	return len;
> >>>> +}
> >>>> +
> >>>> +static IIO_DEVICE_ATTR(burst_mode_enable, 0644,
> >>>> +		       adis16475_burst_mode_enable_get,
> >>>> +		       adis16475_burst_mode_enable_set, 0);
> >>>> +
> >>>> +static struct attribute *adis16475_attributes[] = {
> >>>> +	&iio_dev_attr_burst_mode_enable.dev_attr.attr,  
> >>> Hmm.  Normally we try to avoid exposing this and make the decision
> >>> automatically based on which channels are enabled.  
> >> Hmm. In that case, the decision would probably have to go to the
> >> library since it is there that the "preparations" for buffered mode
> >> are
> >> done. Mostly, the data we are interested in the burst data is gyro,
> >> accel and temp. So to make the decision based on which channels are
> >> enabled is not that straight. Should we enable it only when all
> >> channels are enabled? Some of them (and which)?  
> > I thought a little bit more about it and we could do some math in the
> > lib to know when using burst mode becomes faster (depending on enabled
> > scan elements). The library would need to know about the burst max spi
> > frequency and also some minor changes in how burst_len is being
> > calculated (drivers should explicitly set this rather than the
> > library). The question is, is it worth it to go with this extra work
> > :)?  
> 
> You can leave it out of the initial version and always use burst mode 
> and then add support for this in a follow up patch if it is worth it.
> 
> - Lars
> 
Agreed.   No one tends to buy an expensive IMU to just sample one channel
quickly!  Hence I doubt anyone will ever run it in a mode where burst
mode doesn't make sense.

Thanks,

Jonathan


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] iio: imu: Add support for adis16475
  2020-03-05  9:58       ` Sa, Nuno
  2020-03-05 10:39         ` Lars-Peter Clausen
@ 2020-03-07 11:27         ` Jonathan Cameron
  1 sibling, 0 replies; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-07 11:27 UTC (permalink / raw)
  To: Sa, Nuno
  Cc: linux-iio, devicetree, mark.rutland, pmeerw, lars, Ardelean,
	Alexandru, Hennerich, Michael, knaack.h, robh+dt

...
> > > > +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);
> > > > +	struct adis *adis = &st->adis;
> > > > +	int ret, bit, i = 0;
> > > > +	u16 crc, data[ADIS16475_MAX_SCAN_DATA], *buffer, crc_res;
> > > > +	/* offset until the first element after gyro and accel */
> > > > +	const u8 offset = st->burst32 ? 13 : 7;
> > > > +
> > > > +	ret = spi_sync(adis->spi, &adis->msg);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	buffer = (u16 *)adis->buffer;
> > > > +
> > > > +	if (!(adis->burst && adis->burst->en))
> > > > +		goto push_to_buffers;
> > > > +
> > > > +	/* We always validate the crc to at least print a message */
> > > > +	crc = get_unaligned_be16(&buffer[offset + 2]);
> > > > +	crc_res = adis16475_validate_crc((u8 *)adis->buffer, crc,
> > > > +					 st->burst32);
> > > > +	if (crc_res)
> > > > +		dev_err(&adis->spi->dev, "Invalid crc\n");
> > > > +
> > > > +	for_each_set_bit(bit, indio_dev->active_scan_mask,
> > > > +			 indio_dev->masklength) {
> > > > +		/*
> > > > +		 * When burst mode is used, system flags is the first
> > > > data
> > > > +		 * channel in the sequence, but the scan index is 7.
> > > > +		 */
> > > > +		switch (bit) {
> > > > +		case ADIS16475_SCAN_TEMP:
> > > > +			data[i++] = get_unaligned(&buffer[offset]);
> > > > +			break;
> > > > +		case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
> > > > +			/*
> > > > +			 * The first 2 bytes on the received data are
> > > > the
> > > > +			 * DIAG_STAT reg, hence the +1 offset here...
> > > > +			 */
> > > > +			if (st->burst32) {
> > > > +				/* upper 16 */
> > > > +				data[i++] = get_unaligned(&buffer[bit *
> > > > 2 + 2]);
> > > > +				/* lower 16 */
> > > > +				data[i++] = get_unaligned(&buffer[bit *
> > > > 2 + 1]);
> > > > +			} else {
> > > > +				data[i++] = get_unaligned(&buffer[bit +
> > > > 1]);
> > > > +				/* lower not used */
> > > > +				data[i++] = 0;
> > > > +			}
> > > > +			break;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	buffer = data;
> > > > +
> > > > +push_to_buffers:
> > > > +	iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf-  
> > > > > timestamp);  
> > > 
> > > I'm not sure data is the right size.  It needs to have space to
> > > have
> > > an aligned
> > > timestamp at the end.  
> > 
> > Will double check this... Honestly I did not had the timestamp into
> > account so the size is probably wrong.  
> 
> I guess you are right. With all the channels enabled I think we need a
> 40 bytes buffer in order to have the aligned timestamp...
> 

Sounds right.

> > > > +static const struct spi_device_id adis16475_ids[] = {  
> > > 
> > > Is it actually possible to instantiate this except by
> > > using the dt table below?  If not, then move the 'data'
> > > part into that table and don't provide an spi_device_id
> > > table at all.  It's not relevant to the possible ways
> > > of causing the driver to probe.  
> > 
> > I guess we could use the id table with devicetree even without the dt
> > table (even though it makes no sense).
> > 
> > So, I can remove it but I was using the id->name to set the the
> > iio_dev
> > name which I guess is not the right way?
> > 
> > What Im thinking is having a name/part number string in chip info
> > that
> > I can use to set the iio dev name. For parts that have the *-[1|2|3]
> > variations I could use the devicetree iio label property. Is this the
> > correct way of handling this?  
> 
> I was misunderstanding some stuff here. So, the *-[1|2|3] are valid
> part numbers so they can be in the `name`, right? So, labels come into
> play, for example, when we have multiple instances of the same part,
> right?

Absolutely fine to have the -1 etc.  They are odd part numbers, but they
are the ones on the datasheet etc.

>  
> > - Nuno Sá  
> > > > +	{ "adis16470", ADIS16470 },
> > > > +	{ "adis16475-1", ADIS16475_1 },
> > > > +	{ "adis16475-2", ADIS16475_2 },
> > > > +	{ "adis16475-3", ADIS16475_3 },
> > > > +	{ "adis16477-1", ADIS16477_1 },
> > > > +	{ "adis16477-2", ADIS16477_2 },
> > > > +	{ "adis16477-3", ADIS16477_3 },
> > > > +	{ "adis16465-1", ADIS16465_1 },
> > > > +	{ "adis16465-2", ADIS16465_2 },
> > > > +	{ "adis16465-3", ADIS16465_3 },
> > > > +	{ "adis16467-1", ADIS16467_1 },
> > > > +	{ "adis16467-2", ADIS16467_2 },
> > > > +	{ "adis16467-3", ADIS16467_3 },
> > > > +	{ "adis16500", ADIS16500 },
> > > > +	{ "adis16505-1", ADIS16505_1 },
> > > > +	{ "adis16505-2", ADIS16505_2 },
> > > > +	{ "adis16505-3", ADIS16505_3 },
> > > > +	{ "adis16507-1", ADIS16507_1 },
> > > > +	{ "adis16507-2", ADIS16507_2 },
> > > > +	{ "adis16507-3", ADIS16507_3 },
> > > > +	{ }
> > > > +};
> > > > +MODULE_DEVICE_TABLE(spi, adis16475_ids);
> > > > +
> > > > +static const struct of_device_id adis16475_of_match[] = {
> > > > +	{ .compatible = "adi,adis16470" },
> > > > +	{ .compatible = "adi,adis16475-1" },
> > > > +	{ .compatible = "adi,adis16475-2" },
> > > > +	{ .compatible = "adi,adis16475-3" },
> > > > +	{ .compatible = "adi,adis16477-1" },
> > > > +	{ .compatible = "adi,adis16477-2" },
> > > > +	{ .compatible = "adi,adis16477-3" },
> > > > +	{ .compatible = "adi,adis16465-1" },
> > > > +	{ .compatible = "adi,adis16465-2" },
> > > > +	{ .compatible = "adi,adis16465-3" },
> > > > +	{ .compatible = "adi,adis16467-1" },
> > > > +	{ .compatible = "adi,adis16467-2" },
> > > > +	{ .compatible = "adi,adis16467-3" },
> > > > +	{ .compatible = "adi,adis16500" },
> > > > +	{ .compatible = "adi,adis16505-1" },
> > > > +	{ .compatible = "adi,adis16505-2" },
> > > > +	{ .compatible = "adi,adis16505-3" },
> > > > +	{ .compatible = "adi,adis16507-1" },
> > > > +	{ .compatible = "adi,adis16507-2" },
> > > > +	{ .compatible = "adi,adis16507-3" },
> > > > +	{ },
> > > > +};
> > > > +MODULE_DEVICE_TABLE(of, adis16475_of_match);
> > > > +
> > > > +static struct spi_driver adis16475_driver = {
> > > > +	.driver = {
> > > > +		.name = "adis16475",
> > > > +		.of_match_table = adis16475_of_match,
> > > > +	},
> > > > +	.id_table = adis16475_ids,
> > > > +	.probe = adis16475_probe,
> > > > +};
> > > > +module_spi_driver(adis16475_driver);
> > > > +
> > > > +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
> > > > +MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver");
> > > > +MODULE_LICENSE("GPL");  
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-05 13:04             ` Sa, Nuno
@ 2020-03-07 11:33               ` Jonathan Cameron
  2020-03-07 20:47                 ` nunojsa
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2020-03-07 11:33 UTC (permalink / raw)
  To: Sa, Nuno
  Cc: lars, Ardelean, Alexandru, linux-iio, devicetree, mark.rutland,
	pmeerw, knaack.h, Hennerich, Michael, robh+dt

On Thu, 5 Mar 2020 13:04:27 +0000
"Sa, Nuno" <Nuno.Sa@analog.com> wrote:

> On Thu, 2020-03-05 at 13:43 +0100, Lars-Peter Clausen wrote:
> > On 3/5/20 1:27 PM, Sa, Nuno wrote:  
> > > > In my opinion there is should not be a difference in the
> > > > userspace
> > > > interface for chips that do support 32-bit burst and those that
> > > > don't.
> > > > For devices that don't support 32-bit burst it should be emulated
> > > > by
> > > > reading the LSB bits registers manually.  
> > > Hmm. In terms of interface I think there is no difference. We
> > > always
> > > report 32bits channels (for accel and gyro). However, what we do
> > > right
> > > know is just to set the LSB to 0 if burst32 is not supported. So,
> > > we
> > > can be just ignoring the LSB bits if they are being used...  
> > 
> > What I meant was that somebody might still want to get the full 32-
> > bit 
> > values in buffered mode, even if the device does not support burst32.  
> 
> They are. Just that the LSB part is always set to 0 :). And that, in my
> opinion, is wrong. As you say, we should do the manual readings if
> there are any bits on the LSB registers...
> 
> - Nuno Sá
> > In 
> > that case you can first do a 16-bit burst read to get the MSBs and
> > then 
> > do manual reads of all the LSB registers and then put both into the
> > buffer.
> > - Lars
> >   
> 
Thanks Lars and Nuno, I'd not grasped exactly what this was.

Hmm.  Not allowing for variable bit widths has bitten us a few times in the
past.  Howwever, it's a really nasty thing to try and add to the core now
unfortunately.

In some cases we've just padded the smaller bitwidth buffer but that
is costly to actually do.  You get fast reads from the hardware then loose
at least some of the benefit respacing the data.

Still it is definitely a policy decision so not DT.  It's ugly but if
we want to support it and can't do it at runtime, perhaps a module parameter
is the best option?

Thanks,

Jonathan



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation
  2020-03-07 11:33               ` Jonathan Cameron
@ 2020-03-07 20:47                 ` nunojsa
  0 siblings, 0 replies; 31+ messages in thread
From: nunojsa @ 2020-03-07 20:47 UTC (permalink / raw)
  To: Jonathan Cameron, Sa, Nuno
  Cc: lars, Ardelean, Alexandru, linux-iio, devicetree, mark.rutland,
	pmeerw, knaack.h, Hennerich, Michael, robh+dt

On 07.03.20 12:33, Jonathan Cameron wrote:
> On Thu, 5 Mar 2020 13:04:27 +0000
> "Sa, Nuno" <Nuno.Sa@analog.com> wrote:
> 
>> On Thu, 2020-03-05 at 13:43 +0100, Lars-Peter Clausen wrote:
>>> On 3/5/20 1:27 PM, Sa, Nuno wrote:  
>>>>> In my opinion there is should not be a difference in the
>>>>> userspace
>>>>> interface for chips that do support 32-bit burst and those that
>>>>> don't.
>>>>> For devices that don't support 32-bit burst it should be emulated
>>>>> by
>>>>> reading the LSB bits registers manually.  
>>>> Hmm. In terms of interface I think there is no difference. We
>>>> always
>>>> report 32bits channels (for accel and gyro). However, what we do
>>>> right
>>>> know is just to set the LSB to 0 if burst32 is not supported. So,
>>>> we
>>>> can be just ignoring the LSB bits if they are being used...  
>>>
>>> What I meant was that somebody might still want to get the full 32-
>>> bit 
>>> values in buffered mode, even if the device does not support burst32.  
>>
>> They are. Just that the LSB part is always set to 0 :). And that, in my
>> opinion, is wrong. As you say, we should do the manual readings if
>> there are any bits on the LSB registers...
>>
>> - Nuno Sá
>>> In 
>>> that case you can first do a 16-bit burst read to get the MSBs and
>>> then 
>>> do manual reads of all the LSB registers and then put both into the
>>> buffer.
>>> - Lars
>>>   
>>
> Thanks Lars and Nuno, I'd not grasped exactly what this was.
> 
> Hmm.  Not allowing for variable bit widths has bitten us a few times in the
> past.  Howwever, it's a really nasty thing to try and add to the core now
> unfortunately.
> 
> In some cases we've just padded the smaller bitwidth buffer but that
> is costly to actually do.  You get fast reads from the hardware then loose
> at least some of the benefit respacing the data.
> 
> Still it is definitely a policy decision so not DT.  It's ugly but if
> we want to support it and can't do it at runtime, perhaps a module parameter
> is the best option?
>

So, we can decide this at runtime. As Lars pointed out, the LSB bits are not
used by default (decimation and FIR filters disabled). However, applications can
change this by changing the sampling frequency (affects the decimation filter)
and the low_pass_filter_3db_freq (affects the FIR filter). If one of these filters
is used, then the LSB bits are meaningful and makes sense to use burst32. For parts
that do not support burst32, we should manually read the data.

I started to prepare the version 2 of this series and Im starting to have mixed
feelings. For now, I can see 3 ways of handling this:

1) If we assume that changing from burst32 to burst mode can occur at any
time, we need some special handling. We need to realloc the buffer used
on the spi transfer and readjust the spi xfer length. I'm not a big fan of the
realloc part...

2) Alternatively, we could introduce a `burst_max_len` in the library that could be
used in devices with different burst modes with different sizes. Max len would just
hold the maximum burst len (as the name implies) and would be used to allocate
the buffer to use on the spi tranfer. On the spi xfer we would then use the real
burst length. With this we would not need to care about reallocs...

3) More conservative, we would not allow changing burst modes if buffering is
ongoing... Changing a filter setting that would lead to burst mode change when
buffering would return -EPERM...

Either way, I will probably just send the v2 patch with 1) and then everyone can have
a better look on how it looks and we can discuss improvements/other mechanism in the
v2 thread.

- Nuno Sá
> Thanks,
> 
> Jonathan
> 
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2020-03-07 20:48 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-25 12:41 [PATCH 0/5] Support ADIS16475 and similar IMUs Nuno Sá
2020-02-25 12:41 ` [PATCH 1/5] iio: imu: adis: Add Managed device functions Nuno Sá
2020-03-03 20:38   ` Jonathan Cameron
2020-03-04 17:28     ` Sa, Nuno
2020-02-25 12:41 ` [PATCH 2/5] iio: imu: adis: Add irq mask variable Nuno Sá
2020-03-03 20:40   ` Jonathan Cameron
2020-03-04 17:29     ` Sa, Nuno
2020-02-25 12:41 ` [PATCH 3/5] iio: adis: Add adis_update_bits() APIs Nuno Sá
2020-03-03 20:48   ` Jonathan Cameron
2020-03-04 17:32     ` Sa, Nuno
2020-02-25 12:41 ` [PATCH 4/5] iio: imu: Add support for adis16475 Nuno Sá
2020-03-03 21:08   ` Jonathan Cameron
2020-03-04 17:59     ` Sa, Nuno
2020-03-05  9:58       ` Sa, Nuno
2020-03-05 10:39         ` Lars-Peter Clausen
2020-03-07 11:25           ` Jonathan Cameron
2020-03-07 11:27         ` Jonathan Cameron
2020-02-25 12:41 ` [PATCH 5/5] dt-bindings: iio: Add adis16475 documentation Nuno Sá
2020-03-02 22:22   ` Rob Herring
2020-03-03  9:43     ` Sa, Nuno
2020-03-03  9:59       ` Sa, Nuno
2020-03-03 16:34         ` Rob Herring
2020-03-04 17:25           ` Sa, Nuno
2020-03-03 21:10   ` Jonathan Cameron
2020-03-04 18:00     ` Sa, Nuno
2020-03-05 10:34       ` Lars-Peter Clausen
2020-03-05 12:27         ` Sa, Nuno
2020-03-05 12:43           ` Lars-Peter Clausen
2020-03-05 13:04             ` Sa, Nuno
2020-03-07 11:33               ` Jonathan Cameron
2020-03-07 20:47                 ` nunojsa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.