[PATCH 3/3] iio: accel: adxl372: add support for ADXL371

Antoniu Miclaus posted 3 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH 3/3] iio: accel: adxl372: add support for ADXL371
Posted by Antoniu Miclaus 1 month, 1 week ago
Add support for the Analog Devices ADXL371, a +-200g 3-axis MEMS
accelerometer sharing the same register map as the ADXL372 but with
different ODR values (320/640/1280/2560/5120 Hz vs 400/800/1600/3200/
6400 Hz), different bandwidth values, and different timer scale
factors for activity/inactivity detection.

Due to a silicon anomaly (er001) causing FIFO data misalignment on
all current ADXL371 silicon, FIFO and triggered buffer support is
disabled for the ADXL371 - only direct mode reads are supported.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
---
 drivers/iio/accel/Kconfig       |  12 +--
 drivers/iio/accel/adxl372.c     | 126 +++++++++++++++++++++-----------
 drivers/iio/accel/adxl372.h     |   4 +-
 drivers/iio/accel/adxl372_i2c.c |   7 +-
 drivers/iio/accel/adxl372_spi.c |   7 +-
 5 files changed, 102 insertions(+), 54 deletions(-)

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 3d3f8d8673dd..4094299e2ed8 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -158,24 +158,24 @@ config ADXL372
 	select IIO_TRIGGERED_BUFFER
 
 config ADXL372_SPI
-	tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
+	tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer SPI Driver"
 	depends on SPI
 	select ADXL372
 	select REGMAP_SPI
 	help
-	  Say yes here to add support for the Analog Devices ADXL372 triaxial
-	  acceleration sensor.
+	  Say yes here to add support for the Analog Devices ADXL371/ADXL372
+	  triaxial acceleration sensor.
 	  To compile this driver as a module, choose M here: the
 	  module will be called adxl372_spi.
 
 config ADXL372_I2C
-	tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
+	tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer I2C Driver"
 	depends on I2C
 	select ADXL372
 	select REGMAP_I2C
 	help
-	  Say yes here to add support for the Analog Devices ADXL372 triaxial
-	  acceleration sensor.
+	  Say yes here to add support for the Analog Devices ADXL371/ADXL372
+	  triaxial acceleration sensor.
 	  To compile this driver as a module, choose M here: the
 	  module will be called adxl372_i2c.
 
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index d1f957adea64..10eb5bf14dad 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * ADXL372 3-Axis Digital Accelerometer core driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer core driver
  *
  * Copyright 2018 Analog Devices Inc.
  */
@@ -182,6 +182,14 @@ enum adxl372_odr {
 	ADXL372_ODR_6400HZ,
 };
 
+enum adxl371_odr {
+	ADXL371_ODR_320HZ,
+	ADXL371_ODR_640HZ,
+	ADXL371_ODR_1280HZ,
+	ADXL371_ODR_2560HZ,
+	ADXL371_ODR_5120HZ,
+};
+
 enum adxl372_bandwidth {
 	ADXL372_BW_200HZ,
 	ADXL372_BW_400HZ,
@@ -222,6 +230,29 @@ static const int adxl372_bw_freq_tbl[5] = {
 	200, 400, 800, 1600, 3200,
 };
 
+static const int adxl371_samp_freq_tbl[5] = {
+	320, 640, 1280, 2560, 5120,
+};
+
+static const int adxl371_bw_freq_tbl[5] = {
+	160, 320, 640, 1280, 2560,
+};
+
+const struct adxl372_chip_info adxl371_chip_info = {
+	.name = "adxl371",
+	.samp_freq_tbl = adxl371_samp_freq_tbl,
+	.bw_freq_tbl = adxl371_bw_freq_tbl,
+	.num_freqs = ARRAY_SIZE(adxl371_samp_freq_tbl),
+	.act_time_scale_us = 4125,
+	.act_time_scale_low_us = 8250,
+	.inact_time_scale_ms = 16,
+	.inact_time_scale_low_ms = 32,
+	.max_odr = ADXL371_ODR_5120HZ,
+	/* Silicon erratum (er001) causes FIFO data misalignment on ADXL371 */
+	.fifo_supported = false,
+};
+EXPORT_SYMBOL_NS_GPL(adxl371_chip_info, "IIO_ADXL372");
+
 const struct adxl372_chip_info adxl372_chip_info = {
 	.name = "adxl372",
 	.samp_freq_tbl = adxl372_samp_freq_tbl,
@@ -232,6 +263,7 @@ const struct adxl372_chip_info adxl372_chip_info = {
 	.inact_time_scale_ms = 13,
 	.inact_time_scale_low_ms = 26,
 	.max_odr = ADXL372_ODR_6400HZ,
+	.fifo_supported = true,
 };
 EXPORT_SYMBOL_NS_GPL(adxl372_chip_info, "IIO_ADXL372");
 
@@ -1227,10 +1259,15 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
 
 	indio_dev->channels = adxl372_channels;
 	indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
-	indio_dev->available_scan_masks = adxl372_channel_masks;
 	indio_dev->name = chip_info->name;
 	indio_dev->info = &adxl372_info;
-	indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+
+	if (chip_info->fifo_supported) {
+		indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+		indio_dev->available_scan_masks = adxl372_channel_masks;
+	} else {
+		indio_dev->modes = INDIO_DIRECT_MODE;
+	}
 
 	ret = adxl372_setup(st);
 	if (ret < 0) {
@@ -1238,50 +1275,52 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
 		return ret;
 	}
 
-	ret = devm_iio_triggered_buffer_setup_ext(dev,
-						  indio_dev, NULL,
-						  adxl372_trigger_handler,
-						  IIO_BUFFER_DIRECTION_IN,
-						  &adxl372_buffer_ops,
-						  adxl372_fifo_attributes);
-	if (ret < 0)
-		return ret;
-
-	if (st->irq) {
-		st->dready_trig = devm_iio_trigger_alloc(dev,
-							 "%s-dev%d",
-							 indio_dev->name,
-							 iio_device_id(indio_dev));
-		if (st->dready_trig == NULL)
-			return -ENOMEM;
-
-		st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
-							       "%s-dev%d-peak",
-							       indio_dev->name,
-							       iio_device_id(indio_dev));
-		if (!st->peak_datardy_trig)
-			return -ENOMEM;
-
-		st->dready_trig->ops = &adxl372_trigger_ops;
-		st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
-		iio_trigger_set_drvdata(st->dready_trig, indio_dev);
-		iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
-		ret = devm_iio_trigger_register(dev, st->dready_trig);
+	if (chip_info->fifo_supported) {
+		ret = devm_iio_triggered_buffer_setup_ext(dev,
+							  indio_dev, NULL,
+							  adxl372_trigger_handler,
+							  IIO_BUFFER_DIRECTION_IN,
+							  &adxl372_buffer_ops,
+							  adxl372_fifo_attributes);
 		if (ret < 0)
 			return ret;
 
-		ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
-		if (ret < 0)
-			return ret;
+		if (st->irq) {
+			st->dready_trig = devm_iio_trigger_alloc(dev,
+								 "%s-dev%d",
+								 indio_dev->name,
+								 iio_device_id(indio_dev));
+			if (!st->dready_trig)
+				return -ENOMEM;
+
+			st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
+								       "%s-dev%d-peak",
+								       indio_dev->name,
+								       iio_device_id(indio_dev));
+			if (!st->peak_datardy_trig)
+				return -ENOMEM;
+
+			st->dready_trig->ops = &adxl372_trigger_ops;
+			st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
+			iio_trigger_set_drvdata(st->dready_trig, indio_dev);
+			iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
+			ret = devm_iio_trigger_register(dev, st->dready_trig);
+			if (ret < 0)
+				return ret;
+
+			ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
+			if (ret < 0)
+				return ret;
 
-		indio_dev->trig = iio_trigger_get(st->dready_trig);
+			indio_dev->trig = iio_trigger_get(st->dready_trig);
 
-		ret = devm_request_irq(dev, st->irq,
-				       iio_trigger_generic_data_rdy_poll,
-				       IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
-				       indio_dev->name, st->dready_trig);
-		if (ret < 0)
-			return ret;
+			ret = devm_request_irq(dev, st->irq,
+					       iio_trigger_generic_data_rdy_poll,
+					       IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
+					       indio_dev->name, st->dready_trig);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	return devm_iio_device_register(dev, indio_dev);
@@ -1289,5 +1328,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
 EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372");
 
 MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372.h b/drivers/iio/accel/adxl372.h
index 3ce06609446c..353a8b3a9d76 100644
--- a/drivers/iio/accel/adxl372.h
+++ b/drivers/iio/accel/adxl372.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * ADXL372 3-Axis Digital Accelerometer
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer
  *
  * Copyright 2018 Analog Devices Inc.
  */
@@ -20,8 +20,10 @@ struct adxl372_chip_info {
 	unsigned int inact_time_scale_ms;
 	unsigned int inact_time_scale_low_ms;
 	unsigned int max_odr;
+	bool fifo_supported;
 };
 
+extern const struct adxl372_chip_info adxl371_chip_info;
 extern const struct adxl372_chip_info adxl372_chip_info;
 
 int adxl372_probe(struct device *dev, struct regmap *regmap,
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
index 3f97126a87a1..40acfa611c83 100644
--- a/drivers/iio/accel/adxl372_i2c.c
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * ADXL372 3-Axis Digital Accelerometer I2C driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer I2C driver
  *
  * Copyright 2018 Analog Devices Inc.
  */
@@ -46,12 +46,14 @@ static int adxl372_i2c_probe(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adxl372_i2c_id[] = {
+	{ "adxl371", (kernel_ulong_t)&adxl371_chip_info },
 	{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
 
 static const struct of_device_id adxl372_of_match[] = {
+	{ .compatible = "adi,adxl371", .data = &adxl371_chip_info },
 	{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
 	{ }
 };
@@ -69,6 +71,7 @@ static struct i2c_driver adxl372_i2c_driver = {
 module_i2c_driver(adxl372_i2c_driver);
 
 MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer I2C driver");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("IIO_ADXL372");
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index 0e199feb405e..438e2bef5b77 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * ADXL372 3-Axis Digital Accelerometer SPI driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer SPI driver
  *
  * Copyright 2018 Analog Devices Inc.
  */
@@ -37,12 +37,14 @@ static int adxl372_spi_probe(struct spi_device *spi)
 }
 
 static const struct spi_device_id adxl372_spi_id[] = {
+	{ "adxl371", (kernel_ulong_t)&adxl371_chip_info },
 	{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
 
 static const struct of_device_id adxl372_of_match[] = {
+	{ .compatible = "adi,adxl371", .data = &adxl371_chip_info },
 	{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
 	{ }
 };
@@ -60,6 +62,7 @@ static struct spi_driver adxl372_spi_driver = {
 module_spi_driver(adxl372_spi_driver);
 
 MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer SPI driver");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("IIO_ADXL372");
-- 
2.43.0
Re: [PATCH 3/3] iio: accel: adxl372: add support for ADXL371
Posted by Jonathan Cameron 1 month, 1 week ago
On Mon, 2 Mar 2026 14:20:59 +0200
Antoniu Miclaus <antoniu.miclaus@analog.com> wrote:

> Add support for the Analog Devices ADXL371, a +-200g 3-axis MEMS
> accelerometer sharing the same register map as the ADXL372 but with
> different ODR values (320/640/1280/2560/5120 Hz vs 400/800/1600/3200/
> 6400 Hz), different bandwidth values, and different timer scale
> factors for activity/inactivity detection.
> 
> Due to a silicon anomaly (er001) causing FIFO data misalignment on
> all current ADXL371 silicon, FIFO and triggered buffer support is
> disabled for the ADXL371 - only direct mode reads are supported.

Ouch.

> 

> diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
> index d1f957adea64..10eb5bf14dad 100644
> --- a/drivers/iio/accel/adxl372.c
> +++ b/drivers/iio/accel/adxl372.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  /*
> - * ADXL372 3-Axis Digital Accelerometer core driver
> + * ADXL371/ADXL372 3-Axis Digital Accelerometer core driver
>   *
>   * Copyright 2018 Analog Devices Inc.
>   */
> @@ -182,6 +182,14 @@ enum adxl372_odr {
>  	ADXL372_ODR_6400HZ,
>  };
>  
> +enum adxl371_odr {
> +	ADXL371_ODR_320HZ,
> +	ADXL371_ODR_640HZ,
> +	ADXL371_ODR_1280HZ,
> +	ADXL371_ODR_2560HZ,
> +	ADXL371_ODR_5120HZ,
> +};
> +
>  enum adxl372_bandwidth {
>  	ADXL372_BW_200HZ,
>  	ADXL372_BW_400HZ,
> @@ -222,6 +230,29 @@ static const int adxl372_bw_freq_tbl[5] = {
>  	200, 400, 800, 1600, 3200,
>  };
>  
> +static const int adxl371_samp_freq_tbl[5] = {
> +	320, 640, 1280, 2560, 5120,
It might be a good idea to make the association of ordering an element
explicit via
	[ADXL371_ODR_320HZ] = 320,
etc

> +};
> +
> +static const int adxl371_bw_freq_tbl[5] = {

I assume these are indexed off the odr enum. If so then
	[ADXL371_ODR_320HZ] = 160, 
etc here may make sense as well.

> +	160, 320, 640, 1280, 2560,
> +};

> +		if (st->irq) {
It might be worth factoring out this block (maybe the earlier bit as well)
as a helper function in a precursor patch.  
The indent is getting rather large for such long lines.

> +			st->dready_trig = devm_iio_trigger_alloc(dev,
> +								 "%s-dev%d",
> +								 indio_dev->name,
> +								 iio_device_id(indio_dev));
> +			if (!st->dready_trig)
> +				return -ENOMEM;
> +
> +			st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
> +								       "%s-dev%d-peak",
> +								       indio_dev->name,
> +								       iio_device_id(indio_dev));
> +			if (!st->peak_datardy_trig)
> +				return -ENOMEM;
> +
> +			st->dready_trig->ops = &adxl372_trigger_ops;
> +			st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
> +			iio_trigger_set_drvdata(st->dready_trig, indio_dev);
> +			iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
> +			ret = devm_iio_trigger_register(dev, st->dready_trig);
> +			if (ret < 0)
> +				return ret;
> +
> +			ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
> +			if (ret < 0)
> +				return ret;
>  
> -		indio_dev->trig = iio_trigger_get(st->dready_trig);
> +			indio_dev->trig = iio_trigger_get(st->dready_trig);
>  
> -		ret = devm_request_irq(dev, st->irq,
> -				       iio_trigger_generic_data_rdy_poll,
> -				       IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
> -				       indio_dev->name, st->dready_trig);
> -		if (ret < 0)
> -			return ret;
> +			ret = devm_request_irq(dev, st->irq,
> +					       iio_trigger_generic_data_rdy_poll,
> +					       IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
> +					       indio_dev->name, st->dready_trig);
> +			if (ret < 0)
> +				return ret;
> +		}
>  	}
>  
>  	return devm_iio_device_register(dev, indio_dev);