Add MAX22530-MAX22532 ADC Support
Subsystems (3)
cover Add MAX22530-MAX22532 ADC Support
Hello iio/maintainers,
This patch series adds initial support for the Analog Devices Maxim family of MAX22530-MAX22532 ADCs. These are galvanically isolated, 4-channel, multiplexed, 12-bit, analog-to-digital converters (ADC) in the MAXSafe™ family product line. An integrated, isolated, DC-DC converter powers all fieldside circuitry, and this allows field-side diagnostics even when no input signal is present.
The first patch adds the device tree documentation for the ADC. The DT binding has been verified with DT_BINDING_CHECK. The second patch adds the read functionality for raw and average ADC values from registers.
The code was tested with Raspberry Pi5 and MAX22531_EVKIT_A. With the current driver version, it is possible to do single-shot read of ADC sample data. On a preliminary version of the max22531 driver with debugfs_reg_access callbacks, it was also possible to read/write from/to different device registers and obtain the expected results.
Details of the test setup can be found at
https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/max22531
This code was developed as part of the GSoC project for Linux Foundation. Many thanks to my mentors Marcelo Schmitt, Ceclan Dumitru, Jonathan Santos & Dragos Bogdan for their guidance and reviews throughout the course of this programme.
Abhinav Jain (2):
dt-bindings: iio: adc: Add device tree binding for MAX22531 ADC
iio: adc: Add initial support for MAX22531 ADC
.../bindings/iio/adc/adi,max22531.yaml | 75 +++++++ MAINTAINERS | 8 + drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/max22531.c | 191 ++++++++++++++++++ 5 files changed, 285 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml create mode 100644 drivers/iio/adc/max22531.c
base-commit: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
Signature · 1 line
2.34.1
PATCH 1/2 dt-bindings: iio: adc: Add device tree binding for MAX22531 ADC
Add device tree documentation for MAX22530-MAX22532 family of ADCs. The MAX22530–MAX22532 are galvanically isolated, 4-channel, multiplexed, 12-bit, analog-to-digital converters (ADC) in the MAXSafe™ family product line. An integrated, isolated, DC-DC converter powers all fieldside circuitry, and this allows field-side diagnostics even when no input signal is present.
--- .../bindings/iio/adc/adi,max22531.yaml | 75 +++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml
Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml new file +75 -0
@@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2025 Abhinav Jain +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,max22531.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX22530-MAX22532 12-bit Field Isolated ADCs + +maintainers: + - Abhinav Jain <[email protected]> + +description: + Bindings for the Analog Devices Max22530-MAX22532 Field-Side Self-Powered, + 4-Channel, 12-bit, Isolated ADCs. + + Datasheet can be found here + https://www.analog.com/media/en/technical-documentation/data-sheets/max22530-max22532.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,max22530 + - adi,max22531 + - adi,max22532 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 10000000 + description: Maximum SPI frequency (Hz) + + vddl-supply: + description: + Logic power supply. + + vddpl-supply: + description: + Isolated DC-DC converter power supply. + + interrupts: + items: + - description: | + Interrupt for signaling when conversion results exceed the upper + threshold for ADC readings or fall below the lower threshold. The + interrupt source must be attached to one of COUT1 to COUT4 pins. + - description: | + Alert output that asserts low during a number of different error + conditions. The interrupt source must be attached to INT pin. + +required: + - compatible + - reg + - vddl-supply + - vddpl-supply + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + max22531: adc@0 { + compatible = "adi,max22531"; + reg = <0>; + spi-max-frequency = <5000000>; + vddl-supply = <&vddl>; + vddpl-supply = <&vddpl>; + }; + };
MAINTAINERS +7 -0
@@ -14702,6 +14702,13 @@ F: Documentation/userspace-api/media/drivers/max2175.rst F: drivers/media/i2c/max2175* F: include/uapi/linux/max2175.h +MAX22531 ADC DRIVER +M: Abhinav Jain <[email protected]> +L: [email protected] +S: Maintained +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml + MAX31335 RTC DRIVER M: Antoniu Miclaus <[email protected]> L: [email protected]
Signature · 1 line
2.34.1
PATCH 2/2 iio: adc: Add initial support for MAX22531 ADC
In reply to Abhinav JainAdd device support for MAX22530-MAX22531.
Implement scale and read functionality for raw/filtered ADC readings.
--- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/max22531.c | 191 +++++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 drivers/iio/adc/max22531.c
MAINTAINERS +1 -0
@@ -14708,6 +14708,7 @@ L: [email protected] S: Maintained W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml +F: drivers/iio/adc/max22531.c MAX31335 RTC DRIVER M: Antoniu Miclaus <[email protected]>
drivers/iio/adc/Kconfig +10 -0
@@ -933,6 +933,16 @@ config MAX1363 To compile this driver as a module, choose M here: the module will be called max1363. +config MAX22531 + tristate "Analog Devices MAX22531 ADC Driver" + depends on SPI + help + Say yes here to build support for field-side self-powered 12-bit + isolated Maxim ADCs. (max22530, max22531, max22532). + + To compile this driver as a module, choose M here: the module will be + called max22531. + config MAX34408 tristate "Maxim max34408/max344089 ADC driver" depends on I2C
drivers/iio/adc/Makefile +1 -0
@@ -83,6 +83,7 @@ obj-$(CONFIG_MAX11205) += max11205.o obj-$(CONFIG_MAX11410) += max11410.o obj-$(CONFIG_MAX1241) += max1241.o obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MAX22531) += max22531.o obj-$(CONFIG_MAX34408) += max34408.o obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o
drivers/iio/adc/max22531.c new file +191 -0
191 lines not on this page · raw message
Signature · 1 line
2.34.1
kernel test robot
build botRe: [PATCH v1 2/2] iio: adc: Add initial support for MAX22531 ADC
kernel test robot noticed the following build errors:
Hi Abhinav,
kernel test robot noticed the following build errors:
[auto build test ERROR on 19272b37aa4f83ca52bdf9c16d5d81bdd1354494]
url: https://github.com/intel-lab-lkp/linux/commits/Abhinav-Jain/dt-bindings-iio-adc-Add-device-tree-binding-for-MAX22531-ADC/20250826-052702 base: 19272b37aa4f83ca52bdf9c16d5d81bdd1354494 patch link: https://lore.kernel.org/r/edc52c93e0d4e08619ba8a98674aeb7d49e6dd1b.1756115378.git.jain.abhinav177%40gmail.com patch subject: [PATCH v1 2/2] iio: adc: Add initial support for MAX22531 ADC config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20250826/[email protected]/config) compiler: m68k-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250826/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
drivers/iio/adc/max22531.c: In function 'max22531_reg_read':
>> drivers/iio/adc/max22531.c:76:15: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
76 | cmd = FIELD_PREP(MAX22531_REG_ADDR_MASK, reg);
| ^~~~~~~~~~
drivers/iio/adc/max22531.c: In function 'max22531_probe':
>> drivers/iio/adc/max22531.c:154:13: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
154 | FIELD_GET(MAX22531_DEVICE_REV_MSK, prod_id) != MAX22531_DEVICE_REV)
| ^~~~~~~~~vim +/FIELD_PREP +76 drivers/iio/adc/max22531.c
70
71 static int max22531_reg_read(struct max22531 *adc, unsigned int reg,
72 unsigned int *readval)
73 {
74 u8 cmd;
75
> 76 cmd = FIELD_PREP(MAX22531_REG_ADDR_MASK, reg);
77 *readval = spi_w8r16be(adc->spi_dev, cmd);
78 if (*readval < 0)
79 return *readval;
80
81 return 0;
82 }
83
84 static int max22531_read_raw(struct iio_dev *indio_dev,
85 struct iio_chan_spec const *chan,
86 int *val, int *val2, long mask)
87 {
88 struct max22531 *adc = iio_priv(indio_dev);
89 int ret;
90
91 switch (mask) {
92 case IIO_CHAN_INFO_RAW:
93 ret = max22531_reg_read(adc, MAX22531_REG_ADC_CHAN(chan->channel), val);
94 if (ret)
95 return ret;
96 return IIO_VAL_INT;
97
98 case IIO_CHAN_INFO_AVERAGE_RAW:
99 ret = max22531_reg_read(adc, MAX22531_REG_FADC_CHAN(chan->channel), val);
100 if (ret)
101 return ret;
102 return IIO_VAL_INT;
103
104 case IIO_CHAN_INFO_SCALE:
105 *val = MAX22531_VREF_MV;
106 *val2 = 12;
107
108 return IIO_VAL_FRACTIONAL_LOG2;
109
110 default:
111 return -EINVAL;
112 }
113 }
114
115 static const struct iio_info max22531_info = {
116 .read_raw = max22531_read_raw,
117 };
118
119 static int max22531_probe(struct spi_device *spi)
120 {
121 struct iio_dev *indio_dev;
122 struct max22531 *adc;
123 unsigned int prod_id;
124 int ret;
125
126 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
127 if (!indio_dev)
128 return -ENOMEM;
129
130 adc = iio_priv(indio_dev);
131 adc->spi_dev = spi;
132 adc->chip_info = spi_get_device_match_data(spi);
133 if (!adc->chip_info)
134 return dev_err_probe(&spi->dev, -EINVAL,
135 "no chip info\n");
136
137 indio_dev->name = adc->chip_info->name;
138 indio_dev->info = &max22531_info;
139 indio_dev->channels = max22531_channels;
140 indio_dev->num_channels = ARRAY_SIZE(max22531_channels);
141
142 ret = devm_regulator_get_enable(&spi->dev, "vddl");
143 if (ret)
144 return dev_err_probe(&spi->dev, ret,
145 "Failed to retrieve power logic supply.\n");
146
147 ret = devm_regulator_get_enable(&spi->dev, "vddpl");
148 if (ret)
149 return dev_err_probe(&spi->dev, ret,
150 "Failed to retrieve isolated DC-DC supply.\n");
151
152 ret = max22531_reg_read(adc, MAX22531_REG_PROD_ID, &prod_id);
153 if (ret ||
> 154 FIELD_GET(MAX22531_DEVICE_REV_MSK, prod_id) != MAX22531_DEVICE_REV) 155 dev_warn(&spi->dev, "PROD_ID verification failed\n");
156
157 return devm_iio_device_register(&spi->dev, indio_dev);
158 }
159
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Re: [PATCH v1 1/2] dt-bindings: iio: adc: Add device tree binding for MAX22531 ADC
In reply to Abhinav JainQuoted 37 lines · Abhinav Jain
Add device tree documentation for MAX22530-MAX22532 family of ADCs. The MAX22530–MAX22532 are galvanically isolated, 4-channel, multiplexed, 12-bit, analog-to-digital converters (ADC) in the MAXSafe™ family product line. An integrated, isolated, DC-DC converter powers all fieldside circuitry, and this allows field-side diagnostics even when no input signal is present.
Signed-off-by Abhinav Jain <[email protected]>--- .../bindings/iio/adc/adi,max22531.yaml | 75 +++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,max22531.yamlDocumentation/devicetree/bindings/iio/adc/adi,max22531.yaml new file +17
-0@@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2025 Abhinav Jain +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,max22531.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX22530-MAX22532 12-bit Field Isolated ADCs + +maintainers: + - Abhinav Jain <[email protected]> + +description: + Bindings for the Analog Devices Max22530-MAX22532 Field-Side Self-Powered, + 4-Channel, 12-bit, Isolated ADCs. + + Datasheet can be found here
Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml line 27
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,max22531.yaml new file +10
-0+ https://www.analog.com/media/en/technical-documentation/data-sheets/max22530-max22532.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,max22530 + - adi,max22531 + - adi,max22532
Generally this looks okay to me, but I would like you to mention what it is that makes a fallback between these impossible in your commit message.
Re: [PATCH v1 1/2] dt-bindings: iio: adc: Add device tree binding for MAX22531 ADC
In reply to Abhinav JainQuoted 8 lines · Abhinav Jain
Add device tree documentation for MAX22530-MAX22532 family of ADCs. The MAX22530–MAX22532 are galvanically isolated, 4-channel, multiplexed, 12-bit, analog-to-digital converters (ADC) in the MAXSafe™ family product line. An integrated, isolated, DC-DC converter powers all fieldside circuitry, and this allows field-side diagnostics even when no input signal is present.
Signed-off-by Abhinav Jain <[email protected]>
Please do not develop on old trees. You need to rebase your patchset and test it on latest mainline kernel.
You CC-ed an address, which suggests you do not work on mainline kernel or you do not use get_maintainers.pl/b4/patman. Please rebase and always work on mainline or start using mentioned tools, so correct addresses will be used.
Best regards,
Krzysztof
Jonathan Cameron
maintainerRe: [PATCH v1 2/2] iio: adc: Add initial support for MAX22531 ADC
In reply to Abhinav JainQuoted 4 lines · On Tue, 26 Aug 2025 02:55:49 +0530 Abhinav Jain <[email protected]>…
Add device support for MAX22530-MAX22531.
Implement scale and read functionality for raw/filtered ADC readings.Signed-off-by Abhinav Jain <[email protected]>
Hi Abhinav,
A few minor style related things and one question on FADC registers address.
Thanks,
Jonathan
Quoted 6 lines
M: Antoniu Miclaus <[email protected]>
drivers/iio/adc/Kconfig +0
-0
drivers/iio/adc/Kconfig config MAX1363 · line 941
Quoted 9 lines
drivers/iio/adc/Kconfig +6
-0@@ -933,6 +933,16 @@ config MAX1363 To compile this driver as a module, choose M here: the module will be called max1363. +config MAX22531 + tristate "Analog Devices MAX22531 ADC Driver" + depends on SPI + help + Say yes here to build support for field-side self-powered 12-bit + isolated Maxim ADCs. (max22530, max22531, max22532).
Use a list
- max22530
- max22531
etc
because it means new parts being added create less fuzz. We've gotten this wrong in far too many drivers and ended up with messier follow up series as a result!
drivers/iio/adc/Kconfig config MAX1363 · line 944
Quoted 3 lines
drivers/iio/adc/Kconfig +3
-0+ + To compile this driver as a module, choose M here: the module will be + called max22531.
Should be tab index + 2 spaces for whole help block.
Quoted 12 lines
drivers/iio/adc/Kconfig +1
-0+drivers/iio/adc/max22531.c new file +4
-0@@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* MAX22531 SPI ADC Driver +*
drivers/iio/adc/max22531.c line 14
Quoted 10 lines
drivers/iio/adc/max22531.c new file +10
-0+* Copyright (C) 2025 Abhinav Jain +* +* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max22530-max22532.pdf +*/ + +#include <linux/module.h> +#include <linux/unaligned.h> +#include <linux/spi/spi.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h>
As per the build bot report, there are some headers that want to be here and aren't. In general aim for following Include What You Use IWYU principles for kernel code, subject to some fuzz around headers that are always used via an other one.
drivers/iio/adc/max22531.c line 18
Quoted 4 lines
drivers/iio/adc/max22531.c new file +4
-0+ +#define MAX22531_REG_PROD_ID 0x00 +#define MAX22531_REG_ADC_CHAN (x) ((x) + 1) +#define MAX22531_REG_FADC_CHAN (x) ((x) + 1)
I'm confused. Why the same registers for both of these? If they really are the same, perhaps one macro is enough.
Quoted 19 lines
drivers/iio/adc/max22531.c new file +19
-0+ +#define MAX22531_VREF_MV 1800 +#define MAX22531_DEVICE_REV_MSK GENMASK(6, 0) +#define MAX22531_DEVICE_REV 0x01 + +#define MAX22531_REG_ADDR_MASK GENMASK(7, 2) +#define MAX22531_REG_WRITE_MASK BIT(1) + +enum max22531_id { + max22530, + max22531, + max22532, +}; + +struct max22531_chip_info { +const char *name; +}; + +static struct max22531_chip_info max22531_chip_info_tbl[] = {
drivers/iio/adc/max22531.c line 47
Quoted 10 lines
drivers/iio/adc/max22531.c new file +10
-0+ [max22530] = { + .name ="max22530" , + }, + [max22531] = { + .name ="max22531" , + }, + [max22532] = { + .name ="max22532" , + }, +};
See below for reasoning. Split these into separate structures rather than an array.
drivers/iio/adc/max22531.c line 77
Quoted 7 lines
drivers/iio/adc/max22531.c new file +7
-0+static int max22531_reg_read (struct max22531 *adc,unsigned int reg, +unsigned int *readval) +{ +u8 cmd; + + cmd =FIELD_PREP (MAX22531_REG_ADDR_MASK , reg); + *readval =spi_w8r16be (adc->spi_dev, cmd);
Rather than having side effect of leaving a negative in *readval, use a local variable and only assign readval if all is good.
drivers/iio/adc/max22531.c line 153
Quoted 11 lines
drivers/iio/adc/max22531.c new file +9
-0+if (*readval <0 ) +return *readval; + +return 0 ; +} +static int max22531_probe (struct spi_device *spi) +{ + ret =max22531_reg_read (adc,MAX22531_REG_PROD_ID , &prod_id); + if (ret ||
A failure to read is a bug that we should fail on, whereas the value read not matching is indeed something were a warn or info makes sense. So split this check
if (ret) return ret; if (FIELD_GET()... dev_warn
drivers/iio/adc/max22531.c line 163
Quoted 10 lines
drivers/iio/adc/max22531.c new file +10
-0+ FIELD_GET(MAX22531_DEVICE_REV_MSK, prod_id) != MAX22531_DEVICE_REV) +dev_warn (&spi->dev,"PROD_ID verification failed\n" ); + +return devm_iio_device_register (&spi->dev, indio_dev); +} + +static const struct spi_device_id max22531_id[] = { + {"max22530" , (kernel_ulong_t)&max22531_chip_info_tbl[max22530] }, + {"max22531" , (kernel_ulong_t)&max22531_chip_info_tbl[max22531] }, + {"max22532" , (kernel_ulong_t)&max22531_chip_info_tbl[max22532] },
Whilst this style used to be common, over time we've come to the conclusion that an indexed array for these doesn't bring value. Instead just have separate structures with names that indicate which chip they are for. max22532_chip_info etc That allows the enum to be dropped which has the advantage of removing the temptation to use it for anything else (which is usually a bad idea)
Quoted 12 lines
drivers/iio/adc/max22531.c new file +12
-0+ { } +}; +MODULE_DEVICE_TABLE (spi, max22531_id); + +static const struct of_device_id max22531_spi_of_id[] = { + { .compatible ="adi,max22530" , + .data = &max22531_chip_info_tbl[max22530], }, + { .compatible ="adi,max22531" , + .data = &max22531_chip_info_tbl[max22531], }, + { .compatible ="adi,max22532" , + .data = &max22531_chip_info_tbl[max22532], }, + { }