Skip to content

Commit 0a2857e

Browse files
PIoandanjic23
authored andcommitted
iio: adc: ad7405: add ad7405 driver
Add support for the AD7405/ADUM770x, a high performance isolated ADC, 1-channel, 16-bit with a second-order Σ-Δ modulator that converts an analog input signal into a high speed, single-bit data stream. Signed-off-by: Pop Ioan Daniel <pop.ioan-daniel@analog.com> Reviewed-by: Nuno Sá <nuno.sa@analog.com> Link: https://patch.msgid.link/20250605150948.3091827-6-pop.ioan-daniel@analog.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
1 parent 1c4fa54 commit 0a2857e

File tree

3 files changed

+264
-0
lines changed

3 files changed

+264
-0
lines changed

drivers/iio/adc/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ config AD7380
266266
To compile this driver as a module, choose M here: the module will be
267267
called ad7380.
268268

269+
config AD7405
270+
tristate "Analog Device AD7405 ADC Driver"
271+
depends on IIO_BACKEND
272+
help
273+
Say yes here to build support for Analog Devices AD7405, ADUM7701,
274+
ADUM7702, ADUM7703 analog to digital converters (ADC).
275+
276+
To compile this driver as a module, choose M here: the module will be
277+
called ad7405.
278+
269279
config AD7476
270280
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
271281
depends on SPI

drivers/iio/adc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ obj-$(CONFIG_AD7291) += ad7291.o
2727
obj-$(CONFIG_AD7292) += ad7292.o
2828
obj-$(CONFIG_AD7298) += ad7298.o
2929
obj-$(CONFIG_AD7380) += ad7380.o
30+
obj-$(CONFIG_AD7405) += ad7405.o
3031
obj-$(CONFIG_AD7476) += ad7476.o
3132
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
3233
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o

drivers/iio/adc/ad7405.c

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Analog Devices AD7405 driver
4+
*
5+
* Copyright 2025 Analog Devices Inc.
6+
*/
7+
8+
#include <linux/clk.h>
9+
#include <linux/device.h>
10+
#include <linux/err.h>
11+
#include <linux/math64.h>
12+
#include <linux/module.h>
13+
#include <linux/mod_devicetable.h>
14+
#include <linux/platform_device.h>
15+
#include <linux/property.h>
16+
#include <linux/regulator/consumer.h>
17+
#include <linux/util_macros.h>
18+
19+
#include <linux/iio/backend.h>
20+
#include <linux/iio/iio.h>
21+
22+
static const unsigned int ad7405_dec_rates_range[] = {
23+
32, 1, 4096,
24+
};
25+
26+
struct ad7405_chip_info {
27+
const char *name;
28+
const unsigned int full_scale_mv;
29+
};
30+
31+
struct ad7405_state {
32+
struct iio_backend *back;
33+
const struct ad7405_chip_info *info;
34+
unsigned int ref_frequency;
35+
unsigned int dec_rate;
36+
};
37+
38+
static int ad7405_set_dec_rate(struct iio_dev *indio_dev,
39+
const struct iio_chan_spec *chan,
40+
unsigned int dec_rate)
41+
{
42+
struct ad7405_state *st = iio_priv(indio_dev);
43+
int ret;
44+
45+
if (dec_rate > 4096 || dec_rate < 32)
46+
return -EINVAL;
47+
48+
if (!iio_device_claim_direct(indio_dev))
49+
return -EBUSY;
50+
51+
ret = iio_backend_oversampling_ratio_set(st->back, chan->scan_index, dec_rate);
52+
iio_device_release_direct(indio_dev);
53+
54+
if (ret < 0)
55+
return ret;
56+
57+
st->dec_rate = dec_rate;
58+
59+
return 0;
60+
}
61+
62+
static int ad7405_read_raw(struct iio_dev *indio_dev,
63+
const struct iio_chan_spec *chan, int *val,
64+
int *val2, long info)
65+
{
66+
struct ad7405_state *st = iio_priv(indio_dev);
67+
68+
switch (info) {
69+
case IIO_CHAN_INFO_SCALE:
70+
*val = st->info->full_scale_mv;
71+
*val2 = indio_dev->channels[0].scan_type.realbits - 1;
72+
return IIO_VAL_FRACTIONAL_LOG2;
73+
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
74+
*val = st->dec_rate;
75+
return IIO_VAL_INT;
76+
case IIO_CHAN_INFO_SAMP_FREQ:
77+
*val = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, st->dec_rate);
78+
return IIO_VAL_INT;
79+
case IIO_CHAN_INFO_OFFSET:
80+
*val = -(1 << (indio_dev->channels[0].scan_type.realbits - 1));
81+
return IIO_VAL_INT;
82+
default:
83+
return -EINVAL;
84+
}
85+
}
86+
87+
static int ad7405_write_raw(struct iio_dev *indio_dev,
88+
struct iio_chan_spec const *chan, int val,
89+
int val2, long info)
90+
{
91+
switch (info) {
92+
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
93+
if (val < 0)
94+
return -EINVAL;
95+
return ad7405_set_dec_rate(indio_dev, chan, val);
96+
default:
97+
return -EINVAL;
98+
}
99+
}
100+
101+
static int ad7405_read_avail(struct iio_dev *indio_dev,
102+
struct iio_chan_spec const *chan,
103+
const int **vals, int *type, int *length,
104+
long info)
105+
{
106+
switch (info) {
107+
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
108+
*vals = ad7405_dec_rates_range;
109+
*type = IIO_VAL_INT;
110+
return IIO_AVAIL_RANGE;
111+
default:
112+
return -EINVAL;
113+
}
114+
}
115+
116+
static const struct iio_info ad7405_iio_info = {
117+
.read_raw = &ad7405_read_raw,
118+
.write_raw = &ad7405_write_raw,
119+
.read_avail = &ad7405_read_avail,
120+
};
121+
122+
static const struct iio_chan_spec ad7405_channel = {
123+
.type = IIO_VOLTAGE,
124+
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
125+
BIT(IIO_CHAN_INFO_OFFSET),
126+
.info_mask_shared_by_all = IIO_CHAN_INFO_SAMP_FREQ |
127+
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
128+
.info_mask_shared_by_all_available =
129+
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
130+
.indexed = 1,
131+
.channel = 0,
132+
.channel2 = 1,
133+
.differential = 1,
134+
.scan_index = 0,
135+
.scan_type = {
136+
.sign = 'u',
137+
.realbits = 16,
138+
.storagebits = 16,
139+
},
140+
};
141+
142+
static const struct ad7405_chip_info ad7405_chip_info = {
143+
.name = "ad7405",
144+
.full_scale_mv = 320,
145+
};
146+
147+
static const struct ad7405_chip_info adum7701_chip_info = {
148+
.name = "adum7701",
149+
.full_scale_mv = 320,
150+
};
151+
152+
static const struct ad7405_chip_info adum7702_chip_info = {
153+
.name = "adum7702",
154+
.full_scale_mv = 64,
155+
};
156+
157+
static const struct ad7405_chip_info adum7703_chip_info = {
158+
.name = "adum7703",
159+
.full_scale_mv = 320,
160+
};
161+
162+
static const char * const ad7405_power_supplies[] = {
163+
"vdd1", "vdd2",
164+
};
165+
166+
static int ad7405_probe(struct platform_device *pdev)
167+
{
168+
struct device *dev = &pdev->dev;
169+
struct iio_dev *indio_dev;
170+
struct ad7405_state *st;
171+
struct clk *clk;
172+
int ret;
173+
174+
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
175+
if (!indio_dev)
176+
return -ENOMEM;
177+
178+
st = iio_priv(indio_dev);
179+
180+
st->info = device_get_match_data(dev);
181+
if (!st->info)
182+
return dev_err_probe(dev, -EINVAL, "no chip info\n");
183+
184+
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies),
185+
ad7405_power_supplies);
186+
if (ret)
187+
return dev_err_probe(dev, ret, "failed to get and enable supplies");
188+
189+
clk = devm_clk_get_enabled(dev, NULL);
190+
if (IS_ERR(clk))
191+
return PTR_ERR(clk);
192+
193+
st->ref_frequency = clk_get_rate(clk);
194+
if (!st->ref_frequency)
195+
return -EINVAL;
196+
197+
indio_dev->name = st->info->name;
198+
indio_dev->channels = &ad7405_channel;
199+
indio_dev->num_channels = 1;
200+
indio_dev->info = &ad7405_iio_info;
201+
202+
st->back = devm_iio_backend_get(dev, NULL);
203+
if (IS_ERR(st->back))
204+
return dev_err_probe(dev, PTR_ERR(st->back),
205+
"failed to get IIO backend");
206+
207+
ret = iio_backend_chan_enable(st->back, 0);
208+
if (ret)
209+
return ret;
210+
211+
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
212+
if (ret)
213+
return ret;
214+
215+
ret = devm_iio_backend_enable(dev, st->back);
216+
if (ret)
217+
return ret;
218+
219+
/*
220+
* Set 256 decimation rate. The default value in the AXI_ADC register
221+
* is 0, so we set the register with a decimation rate value that is
222+
* functional for all parts.
223+
*/
224+
ret = ad7405_set_dec_rate(indio_dev, &indio_dev->channels[0], 256);
225+
if (ret)
226+
return ret;
227+
228+
return devm_iio_device_register(dev, indio_dev);
229+
}
230+
231+
static const struct of_device_id ad7405_of_match[] = {
232+
{ .compatible = "adi,ad7405", .data = &ad7405_chip_info, },
233+
{ .compatible = "adi,adum7701", .data = &adum7701_chip_info, },
234+
{ .compatible = "adi,adum7702", .data = &adum7702_chip_info, },
235+
{ .compatible = "adi,adum7703", .data = &adum7703_chip_info, },
236+
{ }
237+
};
238+
MODULE_DEVICE_TABLE(of, ad7405_of_match);
239+
240+
static struct platform_driver ad7405_driver = {
241+
.driver = {
242+
.name = "ad7405",
243+
.of_match_table = ad7405_of_match,
244+
},
245+
.probe = ad7405_probe,
246+
};
247+
module_platform_driver(ad7405_driver);
248+
249+
MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
250+
MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>");
251+
MODULE_DESCRIPTION("Analog Devices AD7405 driver");
252+
MODULE_LICENSE("GPL");
253+
MODULE_IMPORT_NS("IIO_BACKEND");

0 commit comments

Comments
 (0)