From 4a7ae1d7eb08fc2b0463c755a4d6c20f33415926 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:02 -0300 Subject: [PATCH 01/12] dt-bindings: iio: adc: ad4130: Document interrupts property The Data Ready/FIFO interrupt has a special behavior that inverts the IRQ polarity when devices with FIFO support enter FIFO mode, while using normal polarity for data ready. Document the interrupts property to clarify this special behavior for users. Acked-by: Krzysztof Kozlowski Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml index d00690a8d3fbd9..fcc00e5cfd543e 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml @@ -32,6 +32,10 @@ properties: interrupts: maxItems: 1 + description: | + Data Ready / FIFO interrupt. For devices with FIFO support, the + interrupt polarity specified here is inverted when the device enters + FIFO mode, and normal for data ready. interrupt-names: description: | From a040ecea5ecee70b2b118a8f6f2c7d16a1bbc5ed Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:12 -0300 Subject: [PATCH 02/12] dt-bindings: iio: adc: ad4130: Add new supported parts Extend binding support for AD4129-4/8, AD4130-4, and AD4131-4/8 ADC variants. Dropped a reference to driver in the binding whilst here. Acked-by: Krzysztof Kozlowski Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad4130.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml index fcc00e5cfd543e..cc38617bb8295c 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml @@ -5,19 +5,30 @@ $id: http://devicetree.org/schemas/iio/adc/adi,ad4130.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices AD4130 ADC device driver +title: Analog Devices AD4130 family ADCs maintainers: - Cosmin Tanislav description: | - Bindings for the Analog Devices AD4130 ADC. Datasheet can be found here: + Bindings for the Analog Devices AD4130 family ADCs. + Datasheets can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4129-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4129-8.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4130-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD4130-8.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4131-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4131-8.pdf properties: compatible: enum: + - adi,ad4129-4 + - adi,ad4129-8 + - adi,ad4130-4 - adi,ad4130 + - adi,ad4131-4 + - adi,ad4131-8 reg: maxItems: 1 From 3a4b593674dabd758df46e90bf1a221872e8b0c1 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:12:38 -0300 Subject: [PATCH 03/12] arm: dts: xilinx: Add devicetree for AD4129-4 on Coraz7s Enables using the AD4129-4 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4129-4.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-4.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-4.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-4.dts new file mode 100644 index 00000000000000..fdfe4fc353745d --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-4.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4129-4 + * https://www.analog.com/en/products/ad4129-4.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4129_4@0 { + compatible = "adi,ad4129-4"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN0, AIN1 */ + diff-channels = <0 1>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN4, AIN5 */ + diff-channels = <4 5>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From 7c89a82dc38bc61d388083d71f07794fe2f94caa Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:17:55 -0300 Subject: [PATCH 04/12] arm: dts: xilinx: Add devicetree for AD4129-8 on Coraz7s Enables using the AD4129-8 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4129-8.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-8.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-8.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-8.dts new file mode 100644 index 00000000000000..4604aa4a17bec7 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4129-8.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4129-8 + * https://www.analog.com/en/products/ad4129-8.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4129_8@0 { + compatible = "adi,ad4129-8"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN8, AIN9 */ + diff-channels = <8 9>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN10, AIN11 */ + diff-channels = <10 11>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From 1b1fa100d9d01c5f1075eedf4a2e724dd43c6854 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:18:54 -0300 Subject: [PATCH 05/12] arm: dts: xilinx: Add devicetree for AD4130-4 on Coraz7s Enables using the AD4130-4 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4130-4.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-4.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-4.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-4.dts new file mode 100644 index 00000000000000..f1879326224988 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-4.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4130-4 + * https://www.analog.com/en/products/ad4130-4.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4130_4@0 { + compatible = "adi,ad4130-4"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN0, AIN1 */ + diff-channels = <0 1>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN4, AIN5 */ + diff-channels = <4 5>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From eb90773217c71da3c7dc9e36fe2ed4227502b9ba Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:19:23 -0300 Subject: [PATCH 06/12] arm: dts: xilinx: Add devicetree for AD4130-8 on Coraz7s Enables using the AD4130-8 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4130-8.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-8.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-8.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-8.dts new file mode 100644 index 00000000000000..f95380c2429741 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4130-8.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4130-8 + * https://www.analog.com/en/products/ad4130-8.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4130@0 { + compatible = "adi,ad4130"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN8, AIN9 */ + diff-channels = <8 9>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN10, AIN11 */ + diff-channels = <10 11>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From 07e45e232d5596d5eec05b370b7fcda68f719de6 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:20:02 -0300 Subject: [PATCH 07/12] arm: dts: xilinx: Add devicetree for AD4131-4 on Coraz7s Enables using the AD4131-4 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4131-4.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-4.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-4.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-4.dts new file mode 100644 index 00000000000000..30ef28c705bc99 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-4.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4131-4 + * https://www.analog.com/en/products/ad4131-4.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4131_4@0 { + compatible = "adi,ad4131-4"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN0, AIN1 */ + diff-channels = <0 1>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN4, AIN5 */ + diff-channels = <4 5>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From ee0f7297c7d2eb696f14255de70e27a51584c812 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Tue, 14 Jul 2026 16:20:44 -0300 Subject: [PATCH 08/12] arm: dts: xilinx: Add devicetree for AD4131-8 on Coraz7s Enables using the AD4131-8 device on Coraz7s. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-ad4131-8.dts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-8.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-8.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-8.dts new file mode 100644 index 00000000000000..95c506bb5558c9 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-ad4131-8.dts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices AD4131-8 + * https://www.analog.com/en/products/ad4131-8.html + * + * hdl_project: + * + * Copyright (C) 2026 Analog Devices, Inc. + */ +/dts-v1/; +#include "zynq-coraz7s.dtsi" +#include +#include + +&spi0 { + status = "okay"; + + ad4131_8@0 { + compatible = "adi,ad4131-8"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <5000000>; + interrupts = <85 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + channel@0 { + reg = <0>; + + adi,reference-select = <2>; + + /* AIN8, AIN9 */ + diff-channels = <8 9>; + }; + + channel@1 { + reg = <1>; + + adi,reference-select = <2>; + + /* AIN10, AIN11 */ + diff-channels = <10 11>; + }; + + channel@2 { + reg = <2>; + + adi,reference-select = <2>; + + /* Temperature Sensor, DGND */ + diff-channels = <16 19>; + }; + + channel@3 { + reg = <3>; + + adi,reference-select = <2>; + + /* Internal reference, DGND */ + diff-channels = <18 19>; + }; + + channel@4 { + reg = <4>; + + adi,reference-select = <2>; + + /* DGND, DGND */ + diff-channels = <19 19>; + }; + }; +}; From 1058089245afcaeddb3f13034b15043cbebc1913 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 28 Feb 2025 15:14:03 +0200 Subject: [PATCH 09/12] iio: adc: Include cleanup.h when using guard() Directly include the cleanup.h for the guard() instead of relying it to be included via other files. Signed-off-by: Matti Vaittinen Link: https://patch.msgid.link/5b352ce7241e5904a317dd26950c7cd4daa59fc0.1740748394.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 712f95f53c9ecd..b1ea9153b52d87 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include From f47732974a79174f63ce9e687c7b9f5147d99963 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:22 -0300 Subject: [PATCH 10/12] iio: adc: ad4130: Add SPI device ID table Add SPI device ID table to enable non-device tree based device binding. The id_table provides a fallback matching mechanism when of_match_table cannot be used, which is required for proper SPI driver registration. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index b1ea9153b52d87..44aacb0cb51006 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -2099,12 +2099,19 @@ static const struct of_device_id ad4130_of_match[] = { }; MODULE_DEVICE_TABLE(of, ad4130_of_match); +static const struct spi_device_id ad4130_id_table[] = { + { "ad4130" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad4130_id_table); + static struct spi_driver ad4130_driver = { .driver = { .name = AD4130_NAME, .of_match_table = ad4130_of_match, }, .probe = ad4130_probe, + .id_table = ad4130_id_table, }; module_spi_driver(ad4130_driver); From f18501694119ee80bb4b6e962841263f4f7a199a Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:34 -0300 Subject: [PATCH 11/12] iio: adc: ad4130: introduce chip info for future multidevice support Introduce a chip_info structure to abstract device-specific parameters and prepare the driver for supporting multiple AD4130 family variants. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 44aacb0cb51006..3f280c30e3a148 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -224,6 +224,14 @@ enum ad4130_pin_function { AD4130_PIN_FN_VBIAS = BIT(3), }; +struct ad4130_chip_info { + const char *name; + unsigned int max_analog_pins; + const struct iio_info *info; + const unsigned int *reg_size; + const unsigned int reg_size_length; +}; + /* * If you make adaptations in this struct, you most likely also have to adapt * ad4130_setup_info_eq(), too. @@ -268,6 +276,7 @@ struct ad4130_state { struct regmap *regmap; struct spi_device *spi; struct clk *mclk; + const struct ad4130_chip_info *chip_info; struct regulator_bulk_data regulators[4]; u32 irq_trigger; u32 inv_irq_trigger; @@ -394,10 +403,10 @@ static const char * const ad4130_filter_modes_str[] = { static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg, unsigned int *size) { - if (reg >= ARRAY_SIZE(ad4130_reg_size)) + if (reg >= st->chip_info->reg_size_length) return -EINVAL; - *size = ad4130_reg_size[reg]; + *size = st->chip_info->reg_size[reg]; return 0; } @@ -1280,6 +1289,14 @@ static const struct iio_info ad4130_info = { .debugfs_reg_access = ad4130_reg_access, }; +static const struct ad4130_chip_info ad4130_8_chip_info = { + .name = "ad4130-8", + .max_analog_pins = 16, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), +}; + static int ad4130_buffer_postenable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); @@ -1493,7 +1510,7 @@ static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) return dev_err_probe(dev, -EINVAL, "Invalid differential channel %u\n", pin); - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return 0; if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL) @@ -1525,7 +1542,7 @@ static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid excitation pin %u\n", pin); @@ -1543,7 +1560,7 @@ static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n", pin); @@ -1719,7 +1736,7 @@ static int ad4310_parse_fw(struct iio_dev *indio_dev) ret = device_property_count_u32(dev, "adi,vbias-pins"); if (ret > 0) { - if (ret > AD4130_MAX_ANALOG_PINS) + if (ret > st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Too many vbias pins %u\n", ret); @@ -1983,6 +2000,8 @@ static int ad4130_probe(struct spi_device *spi) st = iio_priv(indio_dev); + st->chip_info = device_get_match_data(dev); + memset(st->reset_buf, 0xff, sizeof(st->reset_buf)); init_completion(&st->completion); mutex_init(&st->lock); @@ -2000,9 +2019,9 @@ static int ad4130_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, ARRAY_SIZE(st->fifo_xfer)); - indio_dev->name = AD4130_NAME; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &ad4130_info; + indio_dev->info = st->chip_info->info; st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config); if (IS_ERR(st->regmap)) @@ -2046,7 +2065,7 @@ static int ad4130_probe(struct spi_device *spi) ad4130_fill_scale_tbls(st); st->gc.owner = THIS_MODULE; - st->gc.label = AD4130_NAME; + st->gc.label = st->chip_info->name; st->gc.base = -1; st->gc.ngpio = AD4130_MAX_GPIOS; st->gc.parent = dev; @@ -2094,13 +2113,14 @@ static int ad4130_probe(struct spi_device *spi) static const struct of_device_id ad4130_of_match[] = { { .compatible = "adi,ad4130", + .data = &ad4130_8_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4130_of_match); static const struct spi_device_id ad4130_id_table[] = { - { "ad4130" }, + { "ad4130", (kernel_ulong_t)&ad4130_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4130_id_table); From 029042ff21a34afa8769b921e151996970e5ecc5 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:50 -0300 Subject: [PATCH 12/12] iio: adc: ad4130: add new supported parts Add support for AD4129-4/8, AD4130-4, and AD4131-4/8 variants. The AD4129 series supports the same FIFO interface as the AD4130 but with reduced resolution (16-bit). The AD4131 series lacks FIFO support, so triggered buffer functionality is introduced. The 4-channel variants feature fewer analog inputs, GPIOs, and sparse pin mappings for VBIAS, analog inputs, and excitation currents. The driver now handles these differences with chip-specific configurations, including pin mappings and GPIO counts. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 446 ++++++++++++++++++++++++++++++++------- 1 file changed, 373 insertions(+), 73 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 3f280c30e3a148..3df29ddec7dd46 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -30,6 +32,9 @@ #include #include #include +#include +#include +#include #define AD4130_NAME "ad4130" @@ -40,6 +45,7 @@ #define AD4130_ADC_CONTROL_REG 0x01 #define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14) #define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13) +#define AD4130_ADC_CONTROL_CONT_READ_MASK BIT(11) #define AD4130_INT_REF_2_5V 2500000 #define AD4130_INT_REF_1_25V 1250000 #define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9) @@ -54,7 +60,9 @@ #define AD4130_IO_CONTROL_REG 0x03 #define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8) #define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4) +#define AD4130_4_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 6) #define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0) +#define AD4130_4_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 2) #define AD4130_VBIAS_REG 0x04 @@ -125,6 +133,28 @@ #define AD4130_INVALID_SLOT -1 +static const unsigned int ad4129_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, + [AD4130_FIFO_CONTROL_REG] = 3, + [AD4130_FIFO_STATUS_REG] = 1, + [AD4130_FIFO_THRESHOLD_REG] = 3, + [AD4130_FIFO_DATA_REG] = 2, +}; + static const unsigned int ad4130_reg_size[] = { [AD4130_STATUS_REG] = 1, [AD4130_ADC_CONTROL_REG] = 2, @@ -147,6 +177,24 @@ static const unsigned int ad4130_reg_size[] = { [AD4130_FIFO_DATA_REG] = 3, }; +static const unsigned int ad4131_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, +}; + enum ad4130_int_ref_val { AD4130_INT_REF_VAL_2_5V, AD4130_INT_REF_VAL_1_25V, @@ -224,12 +272,26 @@ enum ad4130_pin_function { AD4130_PIN_FN_VBIAS = BIT(3), }; +/* Pin mapping for AIN0..AIN7, VBIAS_0..VBIAS_7 */ +static const u8 ad4130_4_pin_map[] = { + 0x00, 0x01, 0x04, 0x05, 0x0A, 0x0B, 0x0E, 0x0F, /* 0 - 7 */ +}; + +/* Pin mapping for AIN0..AIN15, VBIAS_0..VBIAS_15 */ +static const u8 ad4130_8_pin_map[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0 - 7 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 8 - 15 */ +}; + struct ad4130_chip_info { const char *name; unsigned int max_analog_pins; + unsigned int num_gpios; const struct iio_info *info; const unsigned int *reg_size; const unsigned int reg_size_length; + const u8 *pin_map; + bool has_fifo; }; /* @@ -303,6 +365,7 @@ struct ad4130_state { u32 mclk_sel; bool int_ref_en; bool bipolar; + bool buffer_wait_for_irq; unsigned int num_enabled_channels; unsigned int effective_watermark; @@ -310,6 +373,7 @@ struct ad4130_state { struct spi_message fifo_msg; struct spi_transfer fifo_xfer[2]; + struct iio_trigger *trig; /* * DMA (thus cache coherency maintenance) requires any transfer @@ -321,9 +385,13 @@ struct ad4130_state { u8 reg_write_tx_buf[4]; u8 reg_read_tx_buf[1]; u8 reg_read_rx_buf[3]; - u8 fifo_tx_buf[2]; - u8 fifo_rx_buf[AD4130_FIFO_SIZE * - AD4130_FIFO_MAX_SAMPLE_SIZE]; + union { + struct { + u8 fifo_tx_buf[2]; + u8 fifo_rx_buf[AD4130_FIFO_SIZE * AD4130_FIFO_MAX_SAMPLE_SIZE]; + }; + IIO_DECLARE_BUFFER_WITH_TS(u32, scan_channels, AD4130_MAX_CHANNELS); + }; }; static const char * const ad4130_int_pin_names[] = { @@ -514,7 +582,8 @@ static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc, /* * Output-only GPIO functionality is available on pins AIN2 through - * AIN5. If these pins are used for anything else, do not expose them. + * AIN5 for some parts and AIN2 through AIN3 for others. If these pins + * are used for anything else, do not expose them. */ for (i = 0; i < ngpios; i++) { unsigned int pin = i + AD4130_AIN2_P1; @@ -535,8 +604,14 @@ static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct ad4130_state *st = gpiochip_get_data(gc); - unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, - BIT(offset)); + unsigned int mask; + + if (st->chip_info->num_gpios == AD4130_MAX_GPIOS) + mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); + else + mask = FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask, value ? mask : 0); @@ -597,10 +672,43 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct ad4130_state *st = iio_priv(indio_dev); - if (iio_buffer_enabled(indio_dev)) - ad4130_push_fifo_data(indio_dev); - else + if (iio_buffer_enabled(indio_dev)) { + if (st->chip_info->has_fifo) + ad4130_push_fifo_data(indio_dev); + else if (st->buffer_wait_for_irq) + complete(&st->completion); + else + iio_trigger_poll(st->trig); + } else { complete(&st->completion); + } + + return IRQ_HANDLED; +} + +static irqreturn_t ad4130_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad4130_state *st = iio_priv(indio_dev); + unsigned int data_reg_size = ad4130_data_reg_size(st); + struct spi_transfer xfer = { }; + unsigned int num_en_chn; + int ret; + + num_en_chn = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + xfer.rx_buf = st->scan_channels; + xfer.len = data_reg_size * num_en_chn; + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret < 0) + goto err_out; + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_channels, + iio_get_time_ns(indio_dev)); + +err_out: + iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } @@ -1289,12 +1397,77 @@ static const struct iio_info ad4130_info = { .debugfs_reg_access = ad4130_reg_access, }; +static const struct iio_info ad4131_info = { + .read_raw = ad4130_read_raw, + .read_avail = ad4130_read_avail, + .write_raw_get_fmt = ad4130_write_raw_get_fmt, + .write_raw = ad4130_write_raw, + .update_scan_mode = ad4130_update_scan_mode, + .debugfs_reg_access = ad4130_reg_access, +}; + +static const struct ad4130_chip_info ad4129_4_chip_info = { + .name = "ad4129-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4129_8_chip_info = { + .name = "ad4129-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4130_4_chip_info = { + .name = "ad4130-4", + .max_analog_pins = 16, + .num_gpios = 2, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + static const struct ad4130_chip_info ad4130_8_chip_info = { .name = "ad4130-8", .max_analog_pins = 16, + .num_gpios = 4, .info = &ad4130_info, .reg_size = ad4130_reg_size, .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4131_4_chip_info = { + .name = "ad4131-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4131_8_chip_info = { + .name = "ad4131-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_8_pin_map, }; static int ad4130_buffer_postenable(struct iio_dev *indio_dev) @@ -1304,44 +1477,89 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev) guard(mutex)(&st->lock); - ret = ad4130_set_watermark_interrupt_en(st, true); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = ad4130_set_watermark_interrupt_en(st, true); + if (ret) + return ret; - ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); - if (ret) - return ret; + ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); + if (ret) + return ret; + + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); + if (ret) + return ret; + } - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); + ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); if (ret) return ret; - return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); + /* + * When using triggered buffer, Entering continuous read mode must + * be the last command sent. No configuration changes are allowed until + * exiting this mode. + */ + if (!st->chip_info->has_fifo) { + ret = regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG, + AD4130_ADC_CONTROL_CONT_READ_MASK, + FIELD_PREP(AD4130_ADC_CONTROL_CONT_READ_MASK, 1)); + if (ret) + return ret; + } + + return 0; } static int ad4130_buffer_predisable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); unsigned int i; + u32 temp; int ret; guard(mutex)(&st->lock); + if (!st->chip_info->has_fifo) { + temp = 0x42; + reinit_completion(&st->completion); + + /* + * In continuous read mode, when all samples are read, the data + * ready signal returns high until the next conversion result is + * ready. To exit this mode, the command must be sent when data + * ready is low. In order to ensure that condition, wait for the + * next interrupt (when the new conversion is finished), allowing + * data ready to return low before sending the exit command. + */ + st->buffer_wait_for_irq = true; + if (!wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000))) + dev_warn(&st->spi->dev, "Conversion timed out\n"); + st->buffer_wait_for_irq = false; + + /* Perform a read data command to exit continuous read mode (0x42) */ + ret = spi_write(st->spi, &temp, 1); + if (ret) + return ret; + } + ret = ad4130_set_mode(st, AD4130_MODE_IDLE); if (ret) return ret; - ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); + if (ret) + return ret; - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); - if (ret) - return ret; + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); + if (ret) + return ret; - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* * update_scan_mode() is not called in the disable path, disable all @@ -1416,6 +1634,34 @@ static const struct iio_dev_attr *ad4130_fifo_attributes[] = { NULL }; +static const struct iio_trigger_ops ad4130_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad4130_triggered_buffer_setup(struct iio_dev *indio_dev) +{ + struct ad4130_state *st = iio_priv(indio_dev); + int ret; + + st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad4130_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + &iio_pollfunc_store_time, + &ad4130_trigger_handler, + &ad4130_buffer_ops); +} + static int _ad4130_find_table_index(const unsigned int *tbl, size_t len, unsigned int val) { @@ -1502,6 +1748,17 @@ static int ad4130_parse_fw_setup(struct ad4130_state *st, return 0; } +static unsigned int ad4130_translate_pin(struct ad4130_state *st, + unsigned int logical_pin) +{ + /* For analog input pins, use the chip-specific pin mapping */ + if (logical_pin < st->chip_info->max_analog_pins) + return st->chip_info->pin_map[logical_pin]; + + /* For internal channels, pass through unchanged */ + return logical_pin; +} + static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; @@ -1920,9 +2177,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) * function of P2 takes priority over the GPIO out function. */ val = 0; - for (i = 0; i < AD4130_MAX_GPIOS; i++) - if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) - val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + for (i = 0; i < st->chip_info->num_gpios; i++) { + if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) { + if (st->chip_info->num_gpios == 2) + val |= FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + else + val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + } + } val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel); @@ -1932,21 +2194,23 @@ static int ad4130_setup(struct iio_dev *indio_dev) val = 0; for (i = 0; i < st->num_vbias_pins; i++) - val |= BIT(st->vbias_pins[i]); + val |= BIT(ad4130_translate_pin(st, st->vbias_pins[i])); ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val); if (ret) return ret; - ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, - AD4130_FIFO_CONTROL_HEADER_MASK); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, + AD4130_FIFO_CONTROL_HEADER_MASK); + if (ret) + return ret; - /* FIFO watermark interrupt starts out as enabled, disable it. */ - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + /* FIFO watermark interrupt starts out as enabled, disable it. */ + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* Setup channels. */ for (i = 0; i < indio_dev->num_channels; i++) { @@ -1954,10 +2218,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) struct iio_chan_spec *chan = &st->chans[i]; unsigned int val; - val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) | - FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) | - FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) | - FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1); + val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, + ad4130_translate_pin(st, chan->channel)) | + FIELD_PREP(AD4130_CHANNEL_AINM_MASK, + ad4130_translate_pin(st, chan->channel2)) | + FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, + ad4130_translate_pin(st, chan_info->iout0)) | + FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, + ad4130_translate_pin(st, chan_info->iout1)); ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val); if (ret) @@ -2007,17 +2275,19 @@ static int ad4130_probe(struct spi_device *spi) mutex_init(&st->lock); st->spi = spi; - /* - * Xfer: [ XFR1 ] [ XFR2 ] - * Master: 0x7D N ...................... - * Slave: ...... DATA1 DATA2 ... DATAN - */ - st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; - st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; - st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); - st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; - spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, - ARRAY_SIZE(st->fifo_xfer)); + if (st->chip_info->has_fifo) { + /* + * Xfer: [ XFR1 ] [ XFR2 ] + * Master: 0x7D N ...................... + * Slave: ...... DATA1 DATA2 ... DATAN + */ + st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; + st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; + st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); + st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; + spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, + ARRAY_SIZE(st->fifo_xfer)); + } indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; @@ -2067,7 +2337,7 @@ static int ad4130_probe(struct spi_device *spi) st->gc.owner = THIS_MODULE; st->gc.label = st->chip_info->name; st->gc.base = -1; - st->gc.ngpio = AD4130_MAX_GPIOS; + st->gc.ngpio = st->chip_info->num_gpios; st->gc.parent = dev; st->gc.can_sleep = true; st->gc.init_valid_mask = ad4130_gpio_init_valid_mask; @@ -2078,9 +2348,12 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, - &ad4130_buffer_ops, - ad4130_fifo_attributes); + if (st->chip_info->has_fifo) + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &ad4130_buffer_ops, + ad4130_fifo_attributes); + else + ret = ad4130_triggered_buffer_setup(indio_dev); if (ret) return ret; @@ -2090,37 +2363,64 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "Failed to request irq\n"); - /* - * When the chip enters FIFO mode, IRQ polarity is inverted. - * When the chip exits FIFO mode, IRQ polarity returns to normal. - * See datasheet pages: 65, FIFO Watermark Interrupt section, - * and 71, Bit Descriptions for STATUS Register, RDYB. - * Cache the normal and inverted IRQ triggers to set them when - * entering and exiting FIFO mode. - */ - st->irq_trigger = irq_get_trigger_type(spi->irq); - if (st->irq_trigger & IRQF_TRIGGER_RISING) - st->inv_irq_trigger = IRQF_TRIGGER_FALLING; - else if (st->irq_trigger & IRQF_TRIGGER_FALLING) - st->inv_irq_trigger = IRQF_TRIGGER_RISING; - else - return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", - st->irq_trigger); + if (st->chip_info->has_fifo) { + /* + * When the chip enters FIFO mode, IRQ polarity is inverted. + * When the chip exits FIFO mode, IRQ polarity returns to normal. + * See datasheet pages: 65, FIFO Watermark Interrupt section, + * and 71, Bit Descriptions for STATUS Register, RDYB. + * Cache the normal and inverted IRQ triggers to set them when + * entering and exiting FIFO mode. + */ + st->irq_trigger = irq_get_trigger_type(spi->irq); + if (st->irq_trigger & IRQF_TRIGGER_RISING) + st->inv_irq_trigger = IRQF_TRIGGER_FALLING; + else if (st->irq_trigger & IRQF_TRIGGER_FALLING) + st->inv_irq_trigger = IRQF_TRIGGER_RISING; + else + return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", + st->irq_trigger); + } return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad4130_of_match[] = { + { + .compatible = "adi,ad4129-4", + .data = &ad4129_4_chip_info + }, + { + .compatible = "adi,ad4129-8", + .data = &ad4129_8_chip_info + }, + { + .compatible = "adi,ad4130-4", + .data = &ad4130_4_chip_info + }, { .compatible = "adi,ad4130", .data = &ad4130_8_chip_info }, + { + .compatible = "adi,ad4131-4", + .data = &ad4131_4_chip_info + }, + { + .compatible = "adi,ad4131-8", + .data = &ad4131_8_chip_info + }, { } }; MODULE_DEVICE_TABLE(of, ad4130_of_match); static const struct spi_device_id ad4130_id_table[] = { + { "ad4129-4", (kernel_ulong_t)&ad4129_4_chip_info }, + { "ad4129-8", (kernel_ulong_t)&ad4129_8_chip_info }, + { "ad4130-4", (kernel_ulong_t)&ad4130_4_chip_info }, { "ad4130", (kernel_ulong_t)&ad4130_8_chip_info }, + { "ad4131-4", (kernel_ulong_t)&ad4131_4_chip_info }, + { "ad4131-8", (kernel_ulong_t)&ad4131_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4130_id_table);