Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
812fd7b
arm: dts: zynq-zed-adv7511-adaq4216: Update to new/current SPI-Engine
machschmitt May 21, 2025
3e9b88f
arm: dts: zynq-zed-adv7511-adaq4216: Update to use trigger-sources
machschmitt May 21, 2025
0af26f8
arm: dts: zynq-zed-adv7511-adaq4216: Drop leftover clock props in ADC…
machschmitt May 21, 2025
8440dde
arm: dts: zynq-zed-adv7511-adaq4216: Increase #pwm-cells to 3
machschmitt Jun 23, 2025
ee9c8ce
arm: dts: zynq-zed-adv7511-adaq4216: Make similar to ad4630-24 dts
machschmitt Jun 23, 2025
08ad9cb
arm: dts: zynq-zed-adv7511-adaq4216: Drop unnecessary num-cs
machschmitt Jun 23, 2025
f4bcf0e
iio: adc: ad4630: Update ADAQ channel storage bits to match the DMA w…
machschmitt Jun 13, 2025
f4bf45c
iio: adc: ad4630: Remove sampling frequency available attribute
machschmitt Jun 17, 2025
e5be754
iio: adc: ad4630: Adjust ADAQ4216 output modes mask
machschmitt Jul 15, 2025
c3cf5b5
iio: buffer: Add industrialio-buffer-dmaengine-filtered
machschmitt Jul 23, 2025
3937ab6
iio: adc: ad4630: Use filtered DMA Engine buffer for single-channel ADCs
machschmitt Jul 23, 2025
69ae08b
iio: adc: ad4630: Fix possible use of uninitialized variable
machschmitt Jul 30, 2025
b53b2e7
iio: adc: ad4630: Drop lower bound average mode check
machschmitt Jul 31, 2025
4781720
iio: adc: ad4630: Drop lower bound PGA value check
machschmitt Jul 31, 2025
69dcfc6
iio: adc: ad4630: Drop lower bound calibscale value check
machschmitt Jul 31, 2025
f71869b
iio: adc: ad4630: Use right shift operator for scale calculation
machschmitt Jul 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq4216.dts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
regulator-always-on;
};

trigger_pwm: adc-pwm-trigger {
compatible = "pwm-trigger";
#trigger-source-cells = <0>;
pwms = <&adc_trigger 0 1000000 0>;
};

clocks {
cnv_ext_clk: ext-clk {
#clock-cells = <0x0>;
Expand Down Expand Up @@ -66,6 +72,15 @@
};
};

adc_trigger: pwm@44b00000 {
compatible = "adi,axi-pwmgen-2.00.a";
reg = <0x44b00000 0x1000>;
label = "ad463x_cnv";
#pwm-cells = <3>;
clocks = <&clkc 15>, <&cnv_ext_clk>;
clock-names = "axi", "ext";
};

rx_dma: dma-controller@44a30000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x44a30000 0x1000>;
Expand All @@ -83,47 +98,36 @@
clock-output-names = "spi_clk";
};

axi_pwm_gen: pwm@44b00000 {
compatible = "adi,axi-pwmgen-2.00.a";
reg = <0x44b00000 0x1000>;
label = "ad463x_cnv";
#pwm-cells = <2>;
clocks = <&clkc 15>, <&cnv_ext_clk>;
clock-names = "axi", "ext";
};

axi_spi_engine: spi@44a00000 {
compatible = "adi-ex,axi-spi-engine-1.00.a";
compatible = "adi,axi-spi-engine-1.00.a";
reg = <0x44a00000 0x1FF>;
interrupt-parent = <&intc>;
interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc 15>, <&spi_clk>;
clock-names = "s_axi_aclk", "spi_clk";
num-cs = <1>;
dmas = <&rx_dma 0>;
dma-names = "offload0-rx";
trigger-sources = <&trigger_pwm>;
#address-cells = <0x1>;
#size-cells = <0x0>;

adaq4216: adaq4216@0 {
compatible = "adi,adaq4216";
reg = <0>;
spi-max-frequency = <80000000>;
vdd-supply = <&vref>;
vdd_1_8-supply = <&vdd_1_8>;
vio-supply = <&vio>;
vref-supply = <&vref>;
spi-max-frequency = <80000000>;
reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>;
adi,pga-gpios = <&gpio0 87 GPIO_ACTIVE_HIGH>,
<&gpio0 88 GPIO_ACTIVE_HIGH>;
adi,lane-mode = <1>;
adi,clock-mode = <0>;
adi,out-data-mode = <0>;
adi,spi-trigger;
clocks = <&cnv_ext_clk>;
clock-names = "trigger_clock";
dmas = <&rx_dma 0>;
dma-names = "rx";
pwm-names = "spi_trigger", "cnv";
pwms = <&axi_pwm_gen 0 0>, <&axi_pwm_gen 1 0>;
pwm-names = "cnv";
pwms = <&adc_trigger 1 1000000 0>;
};
};
};
1 change: 1 addition & 0 deletions drivers/iio/adc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ config AD4630
select IIO_BUFFER
select IIO_BUFFER_DMA
select IIO_BUFFER_DMAENGINE
select IIO_BUFFER_DMAENGINE_FILTERED
select SPI_OFFLOAD
help
Say yes here to build support for Analog Devices AD4630 high speed
Expand Down
64 changes: 39 additions & 25 deletions drivers/iio/adc/ad4630.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/iio/buffer.h>
#include <linux/iio/buffer-dma.h>
#include <linux/iio/buffer-dmaengine.h>
#include <linux/iio/buffer-dmaengine-filtered.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/limits.h>
Expand Down Expand Up @@ -337,7 +338,7 @@ static int ad4630_get_avg_frame_len(struct iio_dev *dev, unsigned int *avg_len)
out:
iio_device_release_direct_mode(dev);

return 0;
return ret;
}

static int ad4630_read_raw(struct iio_dev *indio_dev,
Expand Down Expand Up @@ -527,7 +528,6 @@ static int ad4630_set_chan_offset(struct iio_dev *indio_dev, int ch, int offset)
static void ad4630_fill_scale_tbl(struct ad4630_state *st)
{
int val, val2, tmp0, tmp1, i;
u64 tmp2;

val2 = st->chip->modes[st->out_data].channels->scan_type.realbits;
for (i = 0; i < ARRAY_SIZE(ad4630_gains); i++) {
Expand All @@ -536,8 +536,7 @@ static void ad4630_fill_scale_tbl(struct ad4630_state *st)
val = mult_frac(val, ad4630_gains_frac[i][1] * MILLI,
ad4630_gains_frac[i][0]);
/* Would multiply by NANO here but we already multiplied by MILLI */
tmp2 = shift_right((u64)val * MICRO, val2);
tmp0 = (int)div_s64_rem(tmp2, NANO, &tmp1);
tmp0 = (int)div_u64_rem(((u64)val * MICRO) >> val2, NANO, &tmp1);
st->scale_tbl[i][0] = tmp0; /* Integer part */
st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */
}
Expand All @@ -551,7 +550,7 @@ static int ad4630_calc_pga_gain(int gain_int, int gain_fract, int vref,

gain_nano = gain_int * NANO + gain_fract;

if (gain_nano < 0 || gain_nano > ADAQ4224_GAIN_MAX_NANO)
if (gain_nano > ADAQ4224_GAIN_MAX_NANO)
return -EINVAL;

tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << precision, NANO);
Expand Down Expand Up @@ -605,7 +604,7 @@ static int ad4630_set_chan_gain(struct iio_dev *indio_dev, int ch,

gain = gain_int * MICRO + gain_frac;

if (gain < 0 || gain > AD4630_GAIN_MAX)
if (gain > AD4630_GAIN_MAX)
return -EINVAL;

gain = DIV_ROUND_CLOSEST_ULL(gain * 0x8000, 1000000);
Expand Down Expand Up @@ -642,7 +641,7 @@ static int ad4630_set_avg_frame_len(struct iio_dev *dev,
unsigned int last_avg_idx = ARRAY_SIZE(ad4630_average_modes) - 1;
int ret, freq;

if (avg_val < 0 || avg_val > ad4630_average_modes[last_avg_idx])
if (avg_val > ad4630_average_modes[last_avg_idx])
return -EINVAL;

ret = iio_device_claim_direct_mode(dev);
Expand Down Expand Up @@ -767,8 +766,6 @@ static int ad4630_buffer_predisable(struct iio_dev *indio_dev)
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_separate_available = _msk_avail, \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_type = _msk_type | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type_available = _msk_type, \
Expand Down Expand Up @@ -882,20 +879,20 @@ static const struct ad4630_out_mode ad4630_24_modes[] = {
static const struct ad4630_out_mode adaq4216_modes[] = {
[AD4630_16_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 0, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 16, 0, AD4630_CHAN_INFO_NONE),
},
.data_width = 16,
},
[AD4630_16_DIFF_8_COM] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 16, 8, AD4630_CHAN_INFO_NONE),
},
.data_width = 24,
},
[AD4630_30_AVERAGED_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
},
.data_width = 32,
}
Expand All @@ -904,20 +901,20 @@ static const struct ad4630_out_mode adaq4216_modes[] = {
static const struct ad4630_out_mode adaq4220_modes[] = {
[AD4630_16_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 20, 0, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 20, 0, AD4630_CHAN_INFO_NONE),
},
.data_width = 20,
},
[AD4630_16_DIFF_8_COM] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 16, 8, AD4630_CHAN_INFO_NONE),
},
.data_width = 24,
},
[AD4630_30_AVERAGED_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
},
.data_width = 32,
}
Expand All @@ -926,26 +923,26 @@ static const struct ad4630_out_mode adaq4220_modes[] = {
static const struct ad4630_out_mode adaq4224_modes[] = {
[AD4630_24_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 24, 0, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 24, 0, AD4630_CHAN_INFO_NONE),
},
.data_width = 24,
},
[AD4630_16_DIFF_8_COM] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 16, 8, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 16, 8, AD4630_CHAN_INFO_NONE),
},
.data_width = 24,
},
[AD4630_24_DIFF_8_COM] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 24, 8, AD4630_CHAN_INFO_NONE),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 24, 8, AD4630_CHAN_INFO_NONE),
},
.data_width = 32,
},
[AD4630_30_AVERAGED_DIFF] = {
.channels = {
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 64, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
AD4630_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 32, 30, 2,
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)),
},
.data_width = 32,
}
Expand Down Expand Up @@ -1032,7 +1029,7 @@ static const struct ad4630_chip_info ad4630_chip_info[] = {
[ID_ADAQ4216] = {
.available_masks = ad4030_channel_masks,
.modes = adaq4216_modes,
.out_modes_mask = GENMASK(3, 0),
.out_modes_mask = BIT(3) | GENMASK(1, 0),
.name = "adaq4216",
.grade = 0x1E,
.min_offset = (int)BIT(15) * -1,
Expand Down Expand Up @@ -1537,8 +1534,24 @@ static int ad4630_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(rx_dma),
"failed to get offload RX DMA\n");

ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
rx_dma, IIO_BUFFER_DIRECTION_IN);
/*
* The ad4630_fmc HDL project was designed for ADCs with two channels
* and always streams two data channels to DMA (even when the ADC has
* only one physical channel). Though, if the ADC has only one physical
* channel, the data that would come from the second ADC channel comes
* in as noise and has to be discarded. Because of that, when using
* single-channel ADCs, the ADC driver needs to use a special DMA buffer
* that filters out half of the data that reaches DMA memory. With that,
* the ADC sample data can be delivered to user space without any noise
* being added to the IIO buffer.
*/
if (indio_dev->num_channels == 1)
ret = devm_iio_dmaengine_filtered_buffer_setup_with_handle(dev,
indio_dev, rx_dma,
IIO_BUFFER_DIRECTION_IN);
else
ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
rx_dma, IIO_BUFFER_DIRECTION_IN);
if (ret)
return dev_err_probe(dev, ret,
"Failed to get DMA buffer\n");
Expand Down Expand Up @@ -1634,3 +1647,4 @@ MODULE_AUTHOR("Liviu Adace <liviu.adace@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD4630 and ADAQ4224 ADC family driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
MODULE_IMPORT_NS(IIO_DMAENGINE_FILTERED_BUFFER);
13 changes: 13 additions & 0 deletions drivers/iio/buffer/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ config IIO_BUFFER_DMAENGINE

Should be selected by drivers that want to use this functionality.

config IIO_BUFFER_DMAENGINE_FILTERED
tristate "Industrial I/O DMA buffer integration with DMAEngine that filters data"
select IIO_BUFFER_DMA
select IIO_BUFFER_DMAENGINE
help
Provides a bonding of the generic IIO DMA buffer infrastructure with the
DMAEngine framework. This can be used by converter drivers with a DMA port
connected to an external DMA controller which is supported by the
DMAEngine framework.

Should NOT be selected by anything, unless using ADAQ4216 or similar
single-channel ADCs supported by the ad4630.c driver.

config IIO_DMA_BUF_MMAP_LEGACY
bool "Enables I/O DMA buffer legacy MMAP support"
depends on IIO_BUFFER_DMAENGINE
Expand Down
1 change: 1 addition & 0 deletions drivers/iio/buffer/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o
obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o
obj-$(CONFIG_IIO_BUFFER_DMAENGINE_FILTERED) += industrialio-buffer-dmaengine-filtered.o
obj-$(CONFIG_IIO_BUFFER_HW_CONSUMER) += industrialio-hw-consumer.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
Loading
Loading