Skip to content

Commit bdf152e

Browse files
committed
ad4851: add linux support
Add ad485x family pyadi-iio support for the linux driver. https://github.com/torvalds/linux/blob/master/drivers/iio/adc/ad4851.c Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
1 parent 9653f85 commit bdf152e

File tree

9 files changed

+241
-0
lines changed

9 files changed

+241
-0
lines changed

adi/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from adi.ad4130 import ad4130
2121
from adi.ad4170 import ad4170
2222
from adi.ad4630 import ad4630, adaq42xx
23+
from adi.ad4851 import ad4851
2324
from adi.ad4858 import ad4858
2425
from adi.ad5592r import ad5592r
2526
from adi.ad5686 import ad5686

adi/ad4851.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Copyright (C) 2025 Analog Devices, Inc.
2+
#
3+
# SPDX short identifier: ADIBSD
4+
5+
from decimal import Decimal
6+
7+
from adi.attribute import attribute
8+
from adi.context_manager import context_manager
9+
from adi.rx_tx import rx
10+
11+
12+
class ad4851(rx, context_manager):
13+
14+
""" AD4851 ADC """
15+
16+
_complex_data = False
17+
_device_name = ""
18+
channel = [] # type: ignore
19+
20+
def __init__(self, uri="", device_name="ad4851"):
21+
context_manager.__init__(self, uri, self._device_name)
22+
23+
compatible_parts = [
24+
"ad4851",
25+
"ad4852",
26+
"ad4853",
27+
"ad4854",
28+
"ad4855",
29+
"ad4856",
30+
"ad4857",
31+
"ad4858",
32+
"ad4858i",
33+
]
34+
self._ctrl = None
35+
36+
if not device_name:
37+
device_name = compatible_parts[0]
38+
else:
39+
if device_name not in compatible_parts:
40+
raise Exception(f"Not a compatible device: {device_name}")
41+
42+
# Select the device matching device_name as working device
43+
for device in self._ctx.devices:
44+
if device.name == device_name:
45+
self._ctrl = device
46+
self._rxadc = device
47+
break
48+
49+
# Raise an exception if the device isn't found
50+
if not self._ctrl:
51+
raise Exception(f"{device_name} device not found")
52+
53+
if not self._rxadc:
54+
raise Exception("Error in selecting matching device")
55+
56+
self._rx_channel_names = []
57+
self.channel = []
58+
for ch in self._ctrl.channels:
59+
name = ch.id
60+
self._rx_channel_names.append(name)
61+
self.channel.append(self._channel(self._ctrl, name))
62+
63+
rx.__init__(self)
64+
65+
class _channel(attribute):
66+
"""AD4851 channel"""
67+
68+
def __init__(self, ctrl, channel_name):
69+
self.name = channel_name
70+
self._ctrl = ctrl
71+
72+
@property
73+
def scale_available(self):
74+
"""Get Scale available values"""
75+
return self._get_iio_attr(self.name, "scale_available", False)
76+
77+
@property
78+
def scale(self):
79+
"""Get Scale value"""
80+
return self._get_iio_attr(self.name, "scale", False)
81+
82+
@scale.setter
83+
def scale(self, value):
84+
"""Set scale value"""
85+
self._set_iio_attr(self.name, "scale", False, str(Decimal(value).real))
86+
87+
@property
88+
def calibbias(self):
89+
"""Get calibration bias/offset value."""
90+
return self._get_iio_attr(self.name, "calibbias", False)
91+
92+
@calibbias.setter
93+
def calibbias(self, value):
94+
"""Set channel calibration bias/offset."""
95+
self._set_iio_attr(self.name, "calibbias", False, value)
96+
97+
@property
98+
def calibscale(self):
99+
"""Get calibration scale value."""
100+
return self._get_iio_attr(self.name, "calibscale", False)
101+
102+
@calibscale.setter
103+
def calibscale(self, value):
104+
"""Set channel calibration phascalese."""
105+
self._set_iio_attr(self.name, "calibscale", False, value)
106+
107+
@property
108+
def sampling_frequency(self):
109+
"""Get Sampling frequency value"""
110+
return self._get_iio_dev_attr("sampling_frequency", False)
111+
112+
@sampling_frequency.setter
113+
def sampling_frequency(self, value):
114+
"""Set sampling frequency."""
115+
self._set_iio_dev_attr("sampling_frequency", value)
116+
117+
@property
118+
def oversampling_ratio_available(self):
119+
"""Get the oversampling ratio available values"""
120+
return self._get_iio_dev_attr("oversampling_ratio_available", False)
121+
122+
@property
123+
def oversampling_ratio(self):
124+
"""Get the oversampling ratio value"""
125+
return self._get_iio_dev_attr("oversampling_ratio", False)
126+
127+
@oversampling_ratio.setter
128+
def oversampling_ratio(self, value):
129+
"""Set the oversampling ratio value"""
130+
self._set_iio_dev_attr("oversampling_ratio", value)
131+
132+
def reg_read(self, reg):
133+
"""Direct Register Access via debugfs"""
134+
self._set_iio_debug_attr_str("direct_reg_access", reg, self._ctrl)
135+
return self._get_iio_debug_attr_str("direct_reg_access", self._ctrl)
136+
137+
def reg_write(self, reg, value):
138+
"""Direct Register Access via debugfs"""
139+
self._set_iio_debug_attr_str("direct_reg_access", f"{reg} {value}", self._ctrl)

doc/source/devices/adi.ad4851.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ad4851
2+
=================
3+
4+
.. automodule:: adi.ad4851
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

doc/source/devices/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Supported Devices
1919
adi.ad4170
2020
adi.ad4630
2121
adi.ad469x
22+
adi.ad4851
2223
adi.ad5592r
2324
adi.ad5627
2425
adi.ad5686

examples/ad4851_example.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright (C) 2025 Analog Devices, Inc.
2+
#
3+
# All rights reserved.
4+
#
5+
# Redistribution and use in source and binary forms, with or without modification,
6+
# are permitted provided that the following conditions are met:
7+
# - Redistributions of source code must retain the above copyright
8+
# notice, this list of conditions and the following disclaimer.
9+
# - Redistributions in binary form must reproduce the above copyright
10+
# notice, this list of conditions and the following disclaimer in
11+
# the documentation and/or other materials provided with the
12+
# distribution.
13+
# - Neither the name of Analog Devices, Inc. nor the names of its
14+
# contributors may be used to endorse or promote products derived
15+
# from this software without specific prior written permission.
16+
# - The use of this software may or may not infringe the patent rights
17+
# of one or more patent holders. This license does not release you
18+
# from the requirement that you obtain separate licenses from these
19+
# patent holders to use this software.
20+
# - Use of the software either in source or binary form, must be run
21+
# on or directly connected to an Analog Devices Inc. component.
22+
#
23+
# THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24+
# INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
25+
# PARTICULAR PURPOSE ARE DISCLAIMED.
26+
#
27+
# IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY
29+
# RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30+
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
32+
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
34+
import sys
35+
from time import sleep
36+
37+
import matplotlib.pyplot as plt
38+
39+
from adi import ad4851
40+
41+
# Optionally pass URI as command line argument,
42+
# else use default ip:analog.local
43+
my_uri = sys.argv[1] if len(sys.argv) >= 2 else "ip:analog.local"
44+
print("uri: " + str(my_uri))
45+
46+
my_adc = ad4851(uri=my_uri, device_name="ad4858")
47+
# my_adc.rx_buffer_size = 1024
48+
49+
print("Sampling Frequency: ", my_adc.sampling_frequency)
50+
print("Oversampling Ratio: ", my_adc.oversampling_ratio)
51+
print("Enabled Channels: ", my_adc.rx_enabled_channels)
52+
for ch in my_adc.rx_enabled_channels:
53+
print(f"Channel {ch} calibbias value: {my_adc.channel[ch].calibbias}")
54+
print(f"Channel {ch} calibscale value: {my_adc.channel[ch].calibscale}")
55+
print(f"Channel {ch} scale value: {my_adc.channel[ch].scale}")
56+
print(f"Channel {ch} scale available values: {my_adc.channel[ch].scale_available}")
57+
58+
plt.clf()
59+
sleep(0.5)
60+
data = my_adc.rx()
61+
for ch in my_adc.rx_enabled_channels:
62+
plt.plot(range(0, len(data[0])), data[ch], label="voltage" + str(ch))
63+
plt.xlabel("Data Point")
64+
plt.ylabel("ADC counts")
65+
plt.legend(
66+
bbox_to_anchor=(0.0, 1.02, 1.0, 0.102),
67+
loc="lower left",
68+
ncol=4,
69+
mode="expand",
70+
borderaxespad=0.0,
71+
)
72+
plt.show()

supported_parts.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- AD4696
3636
- AD4697
3737
- AD4698
38+
- AD4851
3839
- AD5310R
3940
- AD5311R
4041
- AD5592R

test/emu/devices/ad4851.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE context [<!ELEMENT context (device | context-attribute)*><!ELEMENT context-attribute EMPTY><!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*><!ELEMENT channel (scan-element?, attribute*)><!ELEMENT attribute EMPTY><!ELEMENT scan-element EMPTY><!ELEMENT debug-attribute EMPTY><!ELEMENT buffer-attribute EMPTY><!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED><!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED><!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED><!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED><!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED><!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED value CDATA #IMPLIED><!ATTLIST debug-attribute name CDATA #REQUIRED value CDATA #IMPLIED><!ATTLIST buffer-attribute name CDATA #REQUIRED value CDATA #IMPLIED>]><context name="network" description="10.48.65.134 Linux analog 6.15.0-rc1-00272-g753278a2953a-dirty #261 SMP PREEMPT Thu May 22 12:22:14 EEST 2025 armv7l" ><context-attribute name="hw_model" value="EVAL-AD4858FMCZ on Xilinx Zynq ZED" /><context-attribute name="hw_carrier" value="Avnet ZedBoard board" /><context-attribute name="local,kernel" value="6.15.0-rc1-00272-g753278a2953a-dirty" /><context-attribute name="uri" value="ip:10.48.65.134" /><context-attribute name="ip,ip-addr" value="10.48.65.134" /><device id="hwmon0" name="e000b000ethernetffffffff00" ><channel id="temp1" type="input" ><attribute name="crit" filename="temp1_crit" value="100000" /><attribute name="input" filename="temp1_input" value="47000" /><attribute name="max_alarm" filename="temp1_max_alarm" value="0" /></channel></device><device id="iio:device0" name="ad4858" ><channel id="voltage0-voltage8" type="input" ><scan-element index="0" format="le:s20/32&gt;&gt;0" scale="0.076293" /><attribute name="calibbias" filename="in_voltage0-voltage8_calibbias" value="0" /><attribute name="calibscale" filename="in_voltage0-voltage8_calibscale" value="1.000000000" /><attribute name="scale" filename="in_voltage0-voltage8_scale" value="0.076293" /><attribute name="scale_available" filename="in_voltage0-voltage8_scale_available" value="0.004768 0.009536 0.011920 0.019073 0.023841 0.038146 0.047683 0.076293" /></channel><channel id="voltage1" type="input" ><scan-element index="1" format="le:u20/32&gt;&gt;0" scale="0.038146" /><attribute name="calibbias" filename="in_voltage1_calibbias" value="0" /><attribute name="calibscale" filename="in_voltage1_calibscale" value="1.000000000" /><attribute name="scale" filename="in_voltage1_scale" value="0.038146" /><attribute name="scale_available" filename="in_voltage1_scale_available" value="0.002384 0.004768 0.005960 0.009536 0.011920 0.019073 0.023841 0.038146" /></channel><attribute name="oversampling_ratio" value="1" /><attribute name="oversampling_ratio_available" value="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536" /><attribute name="sampling_frequency" value="1000000.000000000" /><attribute name="waiting_for_supplier" value="0" /><buffer-attribute name="data_available" value="0" /><buffer-attribute name="direction" value="in" /><buffer-attribute name="length_align_bytes" value="8" /><debug-attribute name="direct_reg_access" value="0x10" /></device></context>

test/emu/hardware_map.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,11 @@ ad738x:
721721
- data_devices:
722722
- iio:device0
723723

724+
ad4851:
725+
- ad4851
726+
- pyadi_iio_class_support:
727+
- ad4851
728+
- emulate:
729+
- filename: ad4851.xml
730+
- data_devices:
731+
- iio:device0

test/test_ad4851.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import pytest
2+
3+
hardware = "ad4851"
4+
classname = "adi.ad4851"
5+
6+
#########################################
7+
@pytest.mark.iio_hardware(hardware, True)
8+
@pytest.mark.parametrize("classname", [(classname)])
9+
@pytest.mark.parametrize("channel", [0])
10+
def test_ad4851_rx_data(test_dma_rx, iio_uri, classname, channel):
11+
test_dma_rx(iio_uri, classname, channel)

0 commit comments

Comments
 (0)