Skip to content

Commit cdc9ecd

Browse files
committed
iio: adc: Add initial support for MAX22531 ADC
Add device support for MAX22530-MAX22531. Implement scale and read/write for raw/filtered ADC readings. Tested on Raspberry Pi5 and reading/writing to/from different ADC registers was noted to be working with expected results. Signed-off-by: Abhinav Jain <[email protected]>
1 parent 6ef096c commit cdc9ecd

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13052,6 +13052,13 @@ F: Documentation/userspace-api/media/drivers/max2175.rst
1305213052
F: drivers/media/i2c/max2175*
1305313053
F: include/uapi/linux/max2175.h
1305413054

13055+
MAX22531 ADC DRIVER
13056+
M: Abhinav Jain <[email protected]>
13057+
13058+
S: Maintained
13059+
W: https://ez.analog.com/linux-software-drivers
13060+
F: drivers/iio/adc/max22531.c
13061+
1305513062
MAX31827 TEMPERATURE SWITCH DRIVER
1305613063
M: Daniel Matyas <[email protected]>
1305713064

drivers/iio/adc/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,16 @@ config MAX1363
11261126
To compile this driver as a module, choose M here: the module will be
11271127
called max1363.
11281128

1129+
config MAX22531
1130+
tristate "Analog Devices MAX22531 ADC Driver"
1131+
depends on SPI
1132+
help
1133+
Say yes here to build support for field-side self-powered 12-bit
1134+
isolated Maxim ADCs. (max22530, max22531, max22532).
1135+
1136+
To compile this driver as a module, choose M here: the module will be
1137+
called max22531.
1138+
11291139
config MAX77541_ADC
11301140
tristate "Analog Devices MAX77541 ADC driver"
11311141
depends on MFD_MAX77541

drivers/iio/adc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ obj-$(CONFIG_MAX11205) += max11205.o
156156
obj-$(CONFIG_MAX11410) += max11410.o
157157
obj-$(CONFIG_MAX1241) += max1241.o
158158
obj-$(CONFIG_MAX1363) += max1363.o
159+
obj-$(CONFIG_MAX22531) += max22531.o
159160
obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
160161
obj-$(CONFIG_MAX9611) += max9611.o
161162
obj-$(CONFIG_MCP320X) += mcp320x.o

drivers/iio/adc/max22531.c

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* iio/adc/max22531.c
4+
*
5+
* MAX22531 SPI ADC Driver
6+
*
7+
* Copyright (C) 2025 Abhinav Jain
8+
*
9+
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max22530-max22532.pdf
10+
*/
11+
12+
#include <asm/unaligned.h>
13+
#include <linux/module.h>
14+
#include <linux/spi/spi.h>
15+
#include <linux/iio/iio.h>
16+
#include <linux/regulator/consumer.h>
17+
18+
#define MAX22531_REG_PROD_ID 0x00
19+
#define MAX22531_REG_ADC_CHAN(x) ((x) + 1)
20+
#define MAX22531_REG_FADC_CHAN(x) ((x) + 1)
21+
#define MAX22531_REG_COUTHI1 0x09
22+
#define MAX22531_REG_COUTHI2 0x0a
23+
#define MAX22531_REG_COUTHI3 0x0b
24+
#define MAX22531_REG_COUTHI4 0x0c
25+
#define MAX22531_REG_COUTLO1 0x0d
26+
#define MAX22531_REG_COUTLO2 0x0e
27+
#define MAX22531_REG_COUTLO3 0x0f
28+
#define MAX22531_REG_COUTLO4 0x10
29+
#define MAX22531_REG_COUT_STATUS 0x11
30+
#define MAX22531_REG_INTERRUPT_STATUS 0x12
31+
#define MAX22531_REG_INTERRUPT_ENABLE 0x13
32+
#define MAX22531_REG_CONTROL 0x14
33+
34+
#define MAX22531_VREF_MV 1800
35+
#define MAX22531_DEVICE_REV_MSK GENMASK(6, 0)
36+
#define MAX22531_DEVICE_REV 0x01
37+
38+
#define MAX22531_REG_ADDR_MASK GENMASK(7, 2)
39+
#define MAX22531_REG_WRITE_MASK BIT(1)
40+
41+
enum max22531_id {
42+
max22530,
43+
max22531,
44+
max22532,
45+
};
46+
47+
struct max22531_chip_info {
48+
const char *name;
49+
};
50+
51+
static struct max22531_chip_info max22531_chip_info_tbl[] = {
52+
[max22530] = {
53+
.name = "max22530",
54+
},
55+
[max22531] = {
56+
.name = "max22531",
57+
},
58+
[max22532] = {
59+
.name = "max22532",
60+
},
61+
};
62+
63+
struct max22531 {
64+
struct spi_device *spi_dev;
65+
const struct max22531_chip_info *chip_info;
66+
};
67+
68+
#define MAX22531_CHANNEL(ch) \
69+
{ \
70+
.type = IIO_VOLTAGE, \
71+
.indexed = 1, \
72+
.channel = (ch), \
73+
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
74+
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
75+
}
76+
77+
static const struct iio_chan_spec max22531_channels[] = {
78+
MAX22531_CHANNEL(0),
79+
MAX22531_CHANNEL(1),
80+
MAX22531_CHANNEL(2),
81+
MAX22531_CHANNEL(3),
82+
};
83+
84+
static int max22531_reg_read(struct max22531 *adc, unsigned int reg,
85+
unsigned int *readval)
86+
{
87+
u8 cmd;
88+
89+
cmd = FIELD_PREP(MAX22531_REG_ADDR_MASK, reg);
90+
*readval = spi_w8r16be(adc->spi_dev, cmd);
91+
if (*readval < 0)
92+
return *readval;
93+
94+
return 0;
95+
}
96+
97+
static int max22531_reg_write(struct max22531 *adc, unsigned int reg,
98+
unsigned int writeval)
99+
{
100+
u8 tx_buf[3];
101+
102+
tx_buf[0] = FIELD_PREP(MAX22531_REG_ADDR_MASK, reg) | MAX22531_REG_WRITE_MASK;
103+
put_unaligned_be16(writeval, &tx_buf[1]);
104+
105+
return spi_write_then_read(adc->spi_dev, tx_buf, ARRAY_SIZE(tx_buf), NULL, 0);
106+
}
107+
108+
static int max22531_read_raw(struct iio_dev *indio_dev,
109+
struct iio_chan_spec const *chan,
110+
int *val, int *val2, long mask)
111+
{
112+
struct max22531 *adc = iio_priv(indio_dev);
113+
int ret;
114+
115+
switch (mask) {
116+
case IIO_CHAN_INFO_RAW:
117+
ret = max22531_reg_read(adc, MAX22531_REG_ADC_CHAN(chan->channel), val);
118+
if (ret)
119+
return ret;
120+
return IIO_VAL_INT;
121+
122+
case IIO_CHAN_INFO_AVERAGE_RAW:
123+
ret = max22531_reg_read(adc, MAX22531_REG_FADC_CHAN(chan->channel), val);
124+
if (ret)
125+
return ret;
126+
return IIO_VAL_INT;
127+
128+
case IIO_CHAN_INFO_SCALE:
129+
*val = MAX22531_VREF_MV;
130+
*val2 = 12;
131+
132+
return IIO_VAL_FRACTIONAL_LOG2;
133+
134+
default:
135+
return -EINVAL;
136+
}
137+
}
138+
139+
static const struct iio_info max22531_info = {
140+
.read_raw = max22531_read_raw,
141+
};
142+
143+
static int max22531_probe(struct spi_device *spi)
144+
{
145+
const struct max22531_chip_info *chip_info;
146+
struct iio_dev *indio_dev;
147+
unsigned int ret, prod_id;
148+
struct max22531 *adc;
149+
150+
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
151+
if (!indio_dev)
152+
return -ENOMEM;
153+
154+
adc = iio_priv(indio_dev);
155+
adc->spi_dev = spi;
156+
adc->chip_info = chip_info;
157+
158+
indio_dev->name = adc->chip_info->name;
159+
indio_dev->info = &max22531_info;
160+
indio_dev->channels = max22531_channels;
161+
indio_dev->num_channels = ARRAY_SIZE(max22531_channels);
162+
163+
ret = devm_regulator_get_enable(&spi->dev, "vddl");
164+
if (ret)
165+
return dev_err_probe(&spi->dev, ret,
166+
"Failed to retrieve power logic supply.\n");
167+
168+
ret = devm_regulator_get_enable(&spi->dev, "vddpl");
169+
if (ret)
170+
return dev_err_probe(&spi->dev, ret,
171+
"Failed to retrieve isolated DC-DC supply.\n");
172+
173+
ret = max22531_reg_read(adc, MAX22531_REG_PROD_ID, &prod_id);
174+
if (ret ||
175+
FIELD_GET(MAX22531_DEVICE_REV_MSK, prod_id) != MAX22531_DEVICE_REV)
176+
dev_warn(&spi->dev, "PROD_ID verification failed\n");
177+
178+
return devm_iio_device_register(&spi->dev, indio_dev);
179+
}
180+
181+
static const struct spi_device_id max22531_id[] = {
182+
{ "max22530", (kernel_ulong_t)&max22531_chip_info_tbl[max22530] },
183+
{ "max22531", (kernel_ulong_t)&max22531_chip_info_tbl[max22531] },
184+
{ "max22532", (kernel_ulong_t)&max22531_chip_info_tbl[max22532] },
185+
{ }
186+
};
187+
MODULE_DEVICE_TABLE(spi, max22531_id);
188+
189+
static const struct of_device_id max22531_spi_of_id[] = {
190+
{ .compatible = "adi,max22530",
191+
.data = &max22531_chip_info_tbl[max22530], },
192+
{ .compatible = "adi,max22531",
193+
.data = &max22531_chip_info_tbl[max22531], },
194+
{ .compatible = "adi,max22532",
195+
.data = &max22531_chip_info_tbl[max22532], },
196+
{ }
197+
};
198+
MODULE_DEVICE_TABLE(of, max22531_spi_of_id);
199+
200+
static struct spi_driver max22531_driver = {
201+
.driver = {
202+
.name = "max22531",
203+
.of_match_table = max22531_spi_of_id,
204+
},
205+
.probe = max22531_probe,
206+
.id_table = max22531_id,
207+
};
208+
module_spi_driver(max22531_driver);
209+
210+
MODULE_AUTHOR("Abhinav Jain <[email protected]>");
211+
MODULE_DESCRIPTION("MAX22531 ADC");
212+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)