Skip to content

iio: adc: Add initial driver support for MAX22531 #2854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: rpi-6.6.y_GSOC_2025_MAX22531
Choose a base branch
from

Conversation

KernelShinobi
Copy link
Contributor

MAX22531 is a galvanically isolated, field-side self-powered, 4-channel, multiplexed, 12-bit ADC.

PR Description

Basic IIO ADC max22531 driver features:

  • Definitions for register addresses and useful constants (if any).
  • Definitions for the IIO channels.
  • A device state struct.
  • A read_raw function implementation (may be just a mock for now).
  • An iio_info struct populated with a reference to the read_raw function.
  • A probe function to initialize and setup the device.
  • SPI and device tree MODULE_DEVICE_TABLEs

PR Type

  • New feature (a change that adds new functionality)

PR Checklist

  • I have conducted a self-review of my own code changes
  • I could not test the DT overlay and/or the driver probing. However, I have compiled it on my machine and used static tools to ensure the code is okay.

Copy link
Contributor

@machschmitt machschmitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @KernelShinobi , a few comments about this initial driver version.
Note that, aside from the comments above, there are still some improvements that need to be made to make this driver usable (e.g. read ADC sample data, provide scale to convert output codes to mV). Those features shall be implemented next. Though, overall, this looks good to me as an initial driver version.

@machschmitt
Copy link
Contributor

machschmitt commented Jul 27, 2025

Hello, so I've set up MAX2531_EVKIT_A and tested the initial MAX22531 driver version.

MAX2531_EVKIT_A_setup

I've added "brcm,bcm2712" to device tree overlay compatible list and added another dev_info print at the end of driver probe.

Here's the result
max22531_initial_test

@KernelShinobi , please, update the PR code according to the provided suggestions.

Despite the message printed to kernel logs, the MAX22531_REG_PROD_ID read is clearly not successful, as we should get 0x0001 from that register. As we talked about in a previous meeting, drop the regmap implementation and make direct use of SPI transfers to comply with the protocol described on datasheet page 19 correctly.

I'll test it again after you update the driver code and register access functions accordingly.

Improve initial DT Overlay for MAX22530-MAX22532.
Add MAX22530-MAX22532 device tree documentation.

Signed-off-by: Abhinav Jain <[email protected]>
Add device entries for MAX22530 and MAX22532.
Retrieve logic and DC-DC power supplies post fixes in DT overlay.
Add chip_info structure for the device.
Fix regmap_config for SPI read/write commands as per the datasheet.
Implement scale in max22531_read_raw function.
Add boilerplate text to Kconfig for the driver.

Signed-off-by: Abhinav Jain <[email protected]>
Copy link
Contributor

@machschmitt machschmitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @KernelShinobi , the MAX22531 driver is looking pretty good overall.
Aside from a few suggestions of mine, I think there's not much else to do to get to a functional working driver.
I'll add another comment with the code for register access when I get it properly working.
Oh, one more thing, please, also run checkpatch to fix any leftover codestyle issue (if any). E.g.

./scripts/checkpatch.pl --terse --codespell --color=always --strict --file drivers/iio/adc/max22531.c

Cheers,
Marcelo


Datasheet can be found here
https://www.analog.com/media/en/technical-documentation/data-sheets/max22530-max22532.pdf

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference the spi-peripheral-props here

$ref: /schemas/spi/spi-peripheral-props.yaml#

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

Comment on lines +30 to +34
'#address-cells':
const: 1

'#size-cells':
const: 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are currently not needed.
#address-cells and #size-cells may be needed if ADC channels eventually need to be described in dt. For example

properties:
...
  '#address-cells':
    const: 1

  '#size-cells':
    const: 0

patternProperties:
  "^channel@[0-9a-f]$":
    $ref: /schemas/iio/adc/adc.yaml#
...

examples:
  - |
    spi {
      #address-cells = <1>;
      #size-cells = <0>;

      max22531: adc@0 {
        compatible = "adi,max22531";
        ...

        #address-cells = <1>;
        #size-cells = <0>;

        channel@0 {
          reg = <0>;
        };
...

Though, I currently don't see any need to describe MAX22531 channels in dt so would drop #address-cells and #size-cells .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

Comment on lines +50 to +51
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be declared right after the main dt-binding description, as mentioned above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

#address-cells = <1>;
#size-cells = <0>;

max22531: adc@0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have the phandle in the example

-        max22531: adc@0 {
+        max2253adc@0 {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

depends on SPI
help
Say yes here to build support for field-side self-powered 12-bit
isolated Maxim ADCs. (max22530, max22531, max22532).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: is the indentation correct at this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix.

Comment on lines +8 to +11
#define MAX22531_REG_ADC1 0x01
#define MAX22531_REG_ADC2 0x02
#define MAX22531_REG_ADC3 0x03
#define MAX22531_REG_ADC4 0x04
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can become more concise if we add a macro for those

-#define MAX22531_REG_ADC1              0x01
-#define MAX22531_REG_ADC2              0x02
-#define MAX22531_REG_ADC3              0x03
-#define MAX22531_REG_ADC4              0x04
+#define MAX22531_REG_ADC_CHAN(x)       ((x) + 1)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

Comment on lines +96 to +115
switch(chan->channel) {
case 0:
reg = MAX22531_REG_ADC1;
break;
case 1:
reg = MAX22531_REG_ADC2;
break;
case 2:
reg = MAX22531_REG_ADC3;
break;
case 3:
reg = MAX22531_REG_ADC3;
break;
default:
return -EINVAL;
}
ret = regmap_read(adc->regmap, reg, val);
if (ret)
return ret;
return IIO_VAL_INT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then this can be simplified to something like

	ret = regmap_read(adc->regmap, MAX22531_REG_ADC_CHAN(chan->channel), val);
	if (ret)
		return ret;

	return IIO_VAL_INT;

using regmap_read() as a placeholder for the register read function, which might end up not being called through the regmap API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

Comment on lines +117 to +138
case IIO_CHAN_INFO_SCALE:
switch(chan->channel) {
case 0:
reg = MAX22531_REG_FADC1;
break;
case 1:
reg = MAX22531_REG_FADC2;
break;
case 2:
reg = MAX22531_REG_FADC3;
break;
case 3:
reg = MAX22531_REG_FADC4;
break;
default:
return -EINVAL;
}

reg = regmap_read(adc->regmap, reg, val);
if (ret)
return ret;
return IIO_VAL_INT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, the chip data sheet says "Filtering averages the most recent 4 readings." on page 17.
I would use in_Y_mean_raw interface [1] to provide that similarly to non-averaged reads.

	case IIO_CHAN_INFO_AVERAGE_RAW:
		ret = regmap_read(adc->regmap, MAX22531_REG_FADC_CHAN(chan->channel), val);
		if (ret)
			return ret;

		return IIO_VAL_INT;

Again, using regmap_read() as a placeholder. Also, register macro name up to you.
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/Documentation/ABI/testing/sysfs-bus-iio?h=testing#n406

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

Comment on lines +160 to +163
unsigned int ret, prod_id;
const struct max22531_chip_info *info;
struct max22531 *adc;
struct iio_dev *indio_dev;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: Prefer reverse fir tree order, a.k.a. reverse Christmas tree or reverse XMAS tree for local variable declarations.
See
Documentation/process/maintainer-tip.rst
Documentation/process/maintainer-netdev.rst
Documentation/process/maintainer-kvm-x86.rst

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

vddpl-supply:
description:
Isolated DC-DC converter power supply.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the "DO attempt to make bindings complete even if a driver doesn't support some features." guideline, we will also need to document the interrupt.
There should be plenty of examples of devices that can fire interrupts when readings surpass/undergo a threshold.
One device I recall having something similar is AD7091R-2/-4/-5/-8 (see Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml).
I get the impression max22531 interrupt will be a bit trickier to document since the interrupt may be triggered by conditions other than the threshold.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants