iio: adc: ad4000: Add SPI offload support
Marcelo Schmitt
maintainerv2 cover iio: adc: ad4000: Add SPI offload support
This patch series extends the ad4000 driver to support SPI offloading. In addition to that, ad4000 IIO documentation is expanded to:
- list PulSAR parts supported by the ad4000 driver.
- describe some characteristics of AD4000 IIO device.
- describe changes when SPI offload is being used.
v2 changes were tested with ADAQ4003 on CoraZ7 setup running Linux built from IIO testing branch.
Link to v1: https://lore.kernel.org/linux-iio/[email protected]/
Change log v1 -> v2
- Fixed passing inappropriate pointer instead of ret to dev_err_probe().
- [new patch] Set transfer bits_per_word to have data in CPU endianness.
- Set iio_dev num_channels close to where channels is set.
- Complement offload message comment about first sample being invalid.
- Documented why the first buffer sample is invalid when offloading.
- Added blank line before a 'simple return'.
Instead of changing bits_per_word according to buffer endianness, I set bits_per_word for other SPI transfers and updated IIO channels to always use CPU endianness (the new patch). With that, bits_per_word no longer needs be updated according to buffer endianness or, in other words, buffer endianness is no longer related to bits_per_word.
Marcelo Schmitt (5):
iio: adc: ad400: Set transfer bits_per_word to have data in CPU
endianness
iio: adc: ad4000: Add support for SPI offload
Documentation: iio: ad4000: Add new supported parts
Documentation: iio: ad4000: Add IIO Device characteristics section
Documentation: iio: ad4000: Describe offload support
Documentation/iio/ad4000.rst | 86 +++++- drivers/iio/adc/Kconfig | 7 +- drivers/iio/adc/ad4000.c | 509 +++++++++++++++++++++++++++++------ 3 files changed, 512 insertions(+), 90 deletions(-)
base-commit: af94f401e26f686f7391ce79b38a6129417c22dc
prerequisite-patch-id: 3d517eef53a799adba5922815fe684b913e36773
Signature · 1 line
2.47.2
Marcelo Schmitt
maintainerPATCH v2 1/5 iio: adc: ad400: Set transfer bits_per_word to have data in CPU endianness
When SPI bits_per_word is not set, SPI transfers default 8-bit word size and ADC data gets stored in big-endian format in memory. Because of that, the IIO driver requests ADC data to be rearranged from BE to CPU endianness. However, with bits_per_word set to the number of ADC precision bits, transfers use larger word sizes that get stored in 'in-memory wordsizes' and can be read in CPU endianness.
Use proper bits_per_word size for SPI transfers thus saving the driver from requesting endianness conversions. With that, shifting the buffer data is also no longer needed. This change has no impact on IIO device functionality.
--- drivers/iio/adc/ad4000.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/iio/adc/ad4000.c +8 -10
@@ -50,8 +50,7 @@ .sign = _sign, \ .realbits = _real_bits, \ .storagebits = _storage_bits, \ - .shift = _storage_bits - _real_bits, \ - .endianness = IIO_BE, \ + .endianness = IIO_CPU, \ }, \ }
@@ -79,8 +78,7 @@ .sign = _sign, \ .realbits = _real_bits, \ .storagebits = _storage_bits, \ - .shift = _storage_bits - _real_bits, \ - .endianness = IIO_BE, \ + .endianness = IIO_CPU, \ }, \ }
@@ -411,8 +409,8 @@ struct ad4000_state {*/ struct {union { -__be16 sample_buf16; -__be32 sample_buf32; +u16 sample_buf16; +u32 sample_buf32; } data;aligned_s64 timestamp; } scan__aligned(IIO_DMA_MINALIGN) ;
@@ -516,11 +514,9 @@ static int ad4000_single_conversion(struct iio_dev *indio_dev,return ret;if (chan->scan_type.storagebits >16 ) - sample =be32_to_cpu (st->scan.data.sample_buf32); + sample = st->scan.data.sample_buf32;else - sample =be16_to_cpu (st->scan.data.sample_buf16); - - sample >>= chan->scan_type.shift; + sample = st->scan.data.sample_buf16;if (chan->scan_type.sign =='s' ) *val =sign_extend32 (sample, chan->scan_type.realbits -1 );
@@ -689,6 +685,7 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st, xfers[0 ].cs_change_delay.unit =SPI_DELAY_UNIT_NSECS ; xfers[1 ].rx_buf = &st->scan.data; + xfers[1 ].bits_per_word = chan->scan_type.realbits; xfers[1 ].len =BITS_TO_BYTES (chan->scan_type.storagebits); xfers[1 ].delay.value = st->time_spec->t_quiet2_ns; xfers[1 ].delay.unit =SPI_DELAY_UNIT_NSECS ;
@@ -719,6 +716,7 @@ static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st, xfers[0 ].delay.unit =SPI_DELAY_UNIT_NSECS ; xfers[1 ].rx_buf = &st->scan.data; + xfers[1 ].bits_per_word = chan->scan_type.realbits; xfers[1 ].len =BITS_TO_BYTES (chan->scan_type.storagebits);spi_message_init_with_transfers (&st->msg, st->xfers,2 );
Signature · 1 line
2.47.2
David Lechner
reviewerRe: [PATCH v2 1/5] iio: adc: ad400: Set transfer bits_per_word to have data in CPU endianness
Quoted 7 lines · Marcelo Schmitt
When SPI
bits_per_wordis not set, SPI transfers default 8-bit word size and ADC data gets stored in big-endian format in memory. Because of that, the IIO driver requests ADC data to be rearranged from BE to CPU endianness. However, withbits_per_wordset to the number of ADC precision bits, transfers use larger word sizes that get stored in 'in-memory wordsizes' and can be read in CPU endianness.
Quoted 7 lines
Use proper
bits_per_wordsize for SPI transfers thus saving the driver from requesting endianness conversions. With that, shifting the buffer data is also no longer needed. This change has no impact on IIO device functionality.Signed-off-by Marcelo Schmitt <[email protected]>---
This is a breaking change. Some SPI controllers, like RPi can only do 8-bit transfers, so this driver would stop working on those platforms. Also, if anyone made software already that depended on the big-endian ordering without checking the scan_type attribute, it would break that software.
I would leave this as-is (drop this patch) and just make it:
.endianness = _offl ? IIO_CPU : IIO_BE,
in the next patch.
Re: [PATCH v2 1/5] iio: adc: ad400: Set transfer bits_per_word to have data in CPU endianness
Quoted 13 lines · David Lechner
Quoted 12 lines · Marcelo Schmitt
When SPI
bits_per_wordis not set, SPI transfers default 8-bit word size and ADC data gets stored in big-endian format in memory. Because of that, the IIO driver requests ADC data to be rearranged from BE to CPU endianness. However, withbits_per_wordset to the number of ADC precision bits, transfers use larger word sizes that get stored in 'in-memory wordsizes' and can be read in CPU endianness.Use proper
bits_per_wordsize for SPI transfers thus saving the driver from requesting endianness conversions. With that, shifting the buffer data is also no longer needed. This change has no impact on IIO device functionality.
Quoted 7 lines
Quoted 2 lines
Signed-off-by Marcelo Schmitt <[email protected]>---
This is a breaking change. Some SPI controllers, like RPi can only do 8-bit transfers, so this driver would stop working on those platforms. Also, if anyone made software already that depended on the big-endian ordering without checking the
scan_typeattribute, it would break that software.
Hmm, if user space software doesn't check deviceX/scan_elements/in_<channel_type>_type, nor deviceX/bufferY/in_<channel_type>Y_type, then I'd say that's already somewhat broken since at least buffer scan_element type attributes are documented
https://web.git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/Documentation/ABI/testing/sysfs-bus-iio?h=testing#n1470.
Anyway, this patch it indeed broke RPi support so I'll revert buffer endianness and SPI transfer bits_per_word configurations the way it was in v1.
Adding possible failure due to controller not supporting specific bits_per_word size to my list of peculiarities related to that field.
Quoted 6 lines
I would leave this as-is (drop this patch) and just make it:
.endianness =
_offl?IIO_CPU:IIO_BE,in the next patch.
Marcelo Schmitt
maintainerPATCH v2 2/5 iio: adc: ad4000: Add support for SPI offload
In reply to Marcelo SchmittFPGA HDL projects can include a PWM generator in addition to SPI-Engine. The PWM IP is used to trigger SPI-Engine offload modules that in turn set SPI-Engine to execute transfers to poll data from the ADC. That allows data to be read at the maximum sample rates. Also, it is possible to set a specific sample rate by setting the proper PWM duty cycle and related state parameters, thus allowing an adjustable ADC sample rate when a PWM (offload trigger) is used in combination with SPI-Engine.
Add support for SPI offload.
---
Instead of changing bits_per_word according to buffer endianness, I set bits_per_word for other SPI transfers and updated IIO channels to always use CPU endianness (the first patch in the series). With that, bits_per_word no longer needs be updated according to buffer endianness or, in other words, buffer endianness is no longer related to bits_per_word.
drivers/iio/adc/Kconfig | 7 +- drivers/iio/adc/ad4000.c | 491 ++++++++++++++++++++++++++++++++------- 2 files changed, 419 insertions(+), 79 deletions(-)
drivers/iio/adc/Kconfig +6 -1
@@ -25,10 +25,15 @@ config AD4000 tristate "Analog Devices AD4000 ADC Driver" depends on SPI select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD4000 high speed - SPI analog to digital converters (ADC). + SPI analog to digital converters (ADC). If intended to use with + SPI offloading support, it is recommended to enable + CONFIG_SPI_AXI_SPI_ENGINE, CONFIG_PWM_AXI_PWMGEN, and + CONFIG_SPI_OFFLOAD_TRIGGER_PWM. To compile this driver as a module, choose M here: the module will be called ad4000.
drivers/iio/adc/ad4000.c +413 -78
821 lines not on this page · raw message
Signature · 1 line
2.47.2
David Lechner
reviewerRe: [PATCH v2 2/5] iio: adc: ad4000: Add support for SPI offload
Quoted 8 lines · Marcelo Schmitt
FPGA HDL projects can include a PWM generator in addition to SPI-Engine. The PWM IP is used to trigger SPI-Engine offload modules that in turn set SPI-Engine to execute transfers to poll data from the ADC. That allows data to be read at the maximum sample rates. Also, it is possible to set a specific sample rate by setting the proper PWM duty cycle and related state parameters, thus allowing an adjustable ADC sample rate when a PWM (offload trigger) is used in combination with SPI-Engine.
Quoted 4 lines
Add support for SPI offload.
Signed-off-by Marcelo Schmitt <[email protected]>---
I'm surprised I'm not on the CC for this series. scripts/get_maintainer.pl should have picked me up due to K: spi_offload which matches this patch.
Quoted 5 lines
Instead of changing
bits_per_wordaccording to buffer endianness, I setbits_per_wordfor other SPI transfers and updated IIO channels to always use CPU endianness (the first patch in the series). With that,bits_per_wordno longer needs be updated according to buffer endianness or, in other words, buffer endianness is no longer related tobits_per_word.
As mentioned in my reply to the previous patch, this is a breaking change, so probably not the best choice.
Quoted 13 lines
drivers/iio/adc/Kconfig | 7 +- drivers/iio/adc/ad4000.c | 491 ++++++++++++++++++++++++++++++++------- 2 files changed, 419 insertions(+), 79 deletions(-)drivers/iio/adc/Kconfig +0
-0@@ -25,10 +25,15 @@ config AD4000 tristate "Analog Devices AD4000 ADC Driver" depends on SPI select IIO_BUFFER
drivers/iio/adc/Kconfig config AD4000 · line 36
Quoted 10 lines
drivers/iio/adc/Kconfig +6
-1+ select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD4000 high speed - SPI analog to digital converters (ADC). + SPI analog to digital converters (ADC). If intended to use with + SPI offloading support, it is recommended to enable + CONFIG_SPI_AXI_SPI_ENGINE, CONFIG_PWM_AXI_PWMGEN, and + CONFIG_SPI_OFFLOAD_TRIGGER_PWM.
I guess this is fine here, but people might be more likely to see it on the ADI wiki where the HDL project that has these requirements is described.
Quoted 8 lines
drivers/iio/adc/Kconfig +0
-0To compile this driver as a module, choose M here: the module will be called ad4000.drivers/iio/adc/ad4000.c +0
-0
drivers/iio/adc/ad4000.c line 28
Quoted 8 lines
drivers/iio/adc/ad4000.c +2
-0@@ -21,9 +21,12 @@#include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> +#include <linux/spi/offload/consumer.h>
Why not before #include <linux/spi/spi.h> ?
Quoted 6 lines
drivers/iio/adc/ad4000.c +1
-0+#define AD4000_READ_COMMAND 0x54#define AD4000_WRITE_COMMAND 0x14@@ -32,10 +35,15 @@/* AD4000 Configuration Register programmable bits */
drivers/iio/adc/ad4000.c line 44
Quoted 10 lines
drivers/iio/adc/ad4000.c +4
-1#define AD4000_CFG_SPAN_COMP BIT(3)/* Input span compression */ #define AD4000_CFG_HIGHZ BIT(2)/* High impedance mode */ +#define AD4000_CFG_TURBO BIT(1)/* Turbo mode */ #define AD4000_SCALE_OPTIONS 2 -#define __AD4000_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, _reg_access) \ +#define AD4000_TQUIET1_NS 190 +#define AD4000_TQUIET2_NS 60 +#define AD4000_TCONV_NS 320
Does this actually work for every single chip? For example, the AD7983 datasheet give the max as 500 ns for this timing parameter. Might need to put this in the chip_info to account for differences.
Also AD7983 doesn't have any quite time in the datasheet, so those might not be needed in some cases?
Quoted 20 lines
drivers/iio/adc/ad4000.c +5
-2+ +#define __AD4000_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, _reg_access, _offl)\ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \@@ -43,8 +51,9 @@ .channel = 0, \ .channel2 = 1, \ .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ +BIT (IIO_CHAN_INFO_SCALE ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = (_reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0),\ .scan_index = 0, \ .scan_type = { \ .sign = _sign, \@@ -54,25 +63,28 @@ }, \ }
drivers/iio/adc/ad4000.c line 71
Quoted 10 lines
drivers/iio/adc/ad4000.c +4
-3-#define AD4000_DIFF_CHANNEL (_sign, _real_bits, _reg_access) \ +#define AD4000_DIFF_CHANNEL (_sign, _real_bits, _reg_access, _offl) \ __AD4000_DIFF_CHANNEL((_sign), (_real_bits), \ - ((_real_bits) > 16 ? 32 : 16), (_reg_access)) + (((_offl) || ((_real_bits) > 16)) ? 32 : 16), \ + (_reg_access), (_offl)) -#define AD4000_DIFF_CHANNELS (_sign, _real_bits, _reg_access) \ +#define AD4000_DIFF_CHANNELS (_sign, _real_bits, _reg_access, _offl) \
We always pass 0 to _offl here, so we can leave out this parameter and just hard-code the 0 below. We will never have a case with offload + soft timestamp.
Quoted 10 lines
drivers/iio/adc/ad4000.c +3
-2{ \ -AD4000_DIFF_CHANNEL (_sign, _real_bits, _reg_access), \ +AD4000_DIFF_CHANNEL (_sign, _real_bits, _reg_access, _offl), \IIO_CHAN_SOFT_TIMESTAMP (1 ), \ } -#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\ +#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, \ + _reg_access, _offl) \ { \
drivers/iio/adc/ad4000.c line 87
Quoted 10 lines
drivers/iio/adc/ad4000.c +3
-2.type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = 0, \ .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \BIT (IIO_CHAN_INFO_SCALE ) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ +BIT (IIO_CHAN_INFO_OFFSET ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = (_reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0),\
Unrelated change (adding braces)?
Also, could be nice to have sampling_frequency_available so that userspace can discover the max sample rate.
Quoted 6 lines
drivers/iio/adc/ad4000.c +0
-0.scan_index = 0, \ .scan_type = { \ .sign = _sign, \@@ -82,13 +94,14 @@ }, \ }
drivers/iio/adc/ad4000.c line 102
Quoted 10 lines
drivers/iio/adc/ad4000.c +4
-3-#define AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _reg_access) \ +#define AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _reg_access, _offl) \ __AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \ - ((_real_bits) > 16 ? 32 : 16), (_reg_access)) + (((_offl) || ((_real_bits) > 16)) ? 32 : 16),\ + (_reg_access), (_offl)) -#define AD4000_PSEUDO_DIFF_CHANNELS (_sign, _real_bits, _reg_access) \ +#define AD4000_PSEUDO_DIFF_CHANNELS (_sign, _real_bits, _reg_access, _offl) \
ditto about hard-coding _offl here
Quoted 5 lines
drivers/iio/adc/ad4000.c +1
-1{ \ -AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _reg_access), \ +AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _reg_access, _offl), \ IIO_CHAN_SOFT_TIMESTAMP(1), \ }
...
drivers/iio/adc/ad4000.c struct ad4000_chip_info { · line 460
Quoted 7 lines
static const struct
ad4000_chip_infoad7983_chip_info= {drivers/iio/adc/ad4000.c +3
-1.dev_name = "ad7983", - .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1330 * KILO,
This is actually 752 ns period when 750 is allowed. Could make it 1 * MEGA + 333
* KILO + 333 or 1333333.
drivers/iio/adc/ad4000.c struct ad4000_chip_info { · line 468
Quoted 9 lines
};
static const struct
ad4000_chip_infoad7984_chip_info= {drivers/iio/adc/ad4000.c +3
-1.dev_name = "ad7984", - .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1330 * KILO,
ditto
Quoted 2 lines
};
...
drivers/iio/adc/ad4000.c static const struct iio_info ad4000_reg_access_info = { · line 831
Quoted 12 lines
drivers/iio/adc/ad4000.c +12
-0+static int ad4000_offload_buffer_postdisable (struct iio_dev *indio_dev) +{ +struct ad4000_state *st =iio_priv (indio_dev); + +spi_offload_trigger_disable (st->offload, st->offload_trigger); + +return 0 ; +} + +static const struct iio_buffer_setup_ops ad4000_offload_buffer_setup_ops = { + .postenable = &ad4000_offload_buffer_postenable, + .postdisable = &ad4000_offload_buffer_postdisable,
Needs to be predisable to correctly balance postenable.
Quoted 53 lines
drivers/iio/adc/ad4000.c +53
-0+}; + +static int ad4000_spi_offload_setup (struct iio_dev *indio_dev, +struct ad4000_state *st) +{ +struct spi_device *spi = st->spi; +struct device *dev = &spi->dev; +struct dma_chan *rx_dma; +int ret; + + st->offload_trigger =devm_spi_offload_trigger_get (dev, st->offload, +SPI_OFFLOAD_TRIGGER_PERIODIC ); +if (IS_ERR (st->offload_trigger)) +return dev_err_probe (dev,PTR_ERR (st->offload_trigger), +"Failed to get offload trigger\n" ); + + ret =ad4000_set_sampling_freq (st, st->max_rate_hz); +if (ret) +return dev_err_probe (dev, ret, +"Failed to set sampling frequency\n" ); + + rx_dma =devm_spi_offload_rx_stream_request_dma_chan (dev, st->offload); +if (IS_ERR (rx_dma)) +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 ); +if (ret) +return dev_err_probe (dev, ret,"Failed to setup DMA buffer\n" ); + +return 0 ; +} + +/* +* This executes a data sample transfer when using SPI offloading for when the +* device connections are in "3-wire" mode, selected when the adi,sdi-pin device +* tree property is absent. In this connection mode, the ADC SDI pin is +* connected to MOSI or to VIO and ADC CNV pin is connected to a SPI controller +* CS (it can't be connected to a GPIO). +* +* In order to achieve the maximum sample rate, we only do one transfer per +* SPI offload trigger. Because the ADC output has a one sample latency (delay) +* when the device is wired in "3-wire" mode and only one transfer per sample is +* being made in turbo mode, the first data sample is not valid because it +* contains the output of an earlier conversion result. We also set transfer +* `bits_per_word` to achieve higher throughput by using the minimum number of +* SCLK cycles. Also, a delay is added to make sure we meet the minimum quiet +* time before releasing the CS line. Plus the CS change delay is set to ensure +* that we meet the minimum quiet time before asserting CS again. +* +* This timing is only valid if turbo mode is enabled (reading during conversion). +*/
drivers/iio/adc/ad4000.c static const struct iio_info ad4000_reg_access_info = { · line 894
Quoted 10 lines
drivers/iio/adc/ad4000.c +10
-0+static int ad4000_prepare_offload_turbo_message (struct ad4000_state *st, +const struct iio_chan_spec *chan) +{ +struct spi_transfer *xfers = st->offload_xfers; + +/* Have to do a short CS toggle to trigger conversion. */ + xfers[0 ].cs_change =1 ; + xfers[0 ].cs_change_delay.value =AD4000_TQUIET1_NS ; + xfers[0 ].cs_change_delay.unit =SPI_DELAY_UNIT_NSECS ; + xfers[0 ].offload_flags =SPI_OFFLOAD_XFER_RX_STREAM ;
There is no data transferred in this xfer, so we don't need to set this flag.
Quoted 13 lines
drivers/iio/adc/ad4000.c +13
-0+ + xfers[1 ].offload_flags =SPI_OFFLOAD_XFER_RX_STREAM ; + xfers[1 ].bits_per_word = chan->scan_type.realbits; + xfers[1 ].len = chan->scan_type.realbits >16 ?4 :2 ; + xfers[1 ].delay.value =AD4000_TQUIET2_NS ; + xfers[1 ].delay.unit =SPI_DELAY_UNIT_NSECS ; + +spi_message_init_with_transfers (&st->offload_msg, xfers,2 ); + st->offload_msg.offload = st->offload; + +return devm_spi_optimize_message (&st->spi->dev, st->spi, &st->offload_msg); +} +
...
drivers/iio/adc/ad4000.c static int ad4000_probe(struct spi_device *spi) · line 1134
Quoted 13 lines
drivers/iio/adc/ad4000.c +7
-2@@ -804,19 +1125,39 @@ static int ad4000_probe(struct spi_device *spi)break ;case AD4000_SDI_VIO : - indio_dev->info = &ad4000_info; - indio_dev->channels = chip->chan_spec; +if (st->using_offload) { + indio_dev->info = &ad4000_offload_info; + indio_dev->channels = &chip->offload_chan_spec; + indio_dev->num_channels =1 ; + + spi->cs_hold.value =AD4000_TCONV_NS ; + spi->cs_hold.unit =SPI_DELAY_UNIT_NSECS ;
Modifying spi is suspicious. Normally, this would come from the devicetree. And this isn't used by all SPI drivers - notably the AXI SPI Engine ignores it. Better to just handle this in individual spi xfer structs.
drivers/iio/adc/ad4000.c static int ad4000_probe(struct spi_device *spi) · line 1143
Quoted 9 lines
drivers/iio/adc/ad4000.c +9
-0+ ret =ad4000_prepare_offload_message (st, indio_dev->channels); +if (ret) +return dev_err_probe (dev, ret, +"Failed to optimize SPI msg\n" ); + }else { + indio_dev->info = &ad4000_info; + indio_dev->channels = chip->chan_spec; + indio_dev->num_channels =ARRAY_SIZE (chip->chan_spec); + }
nit: add extra blank line here
Quoted 7 lines
drivers/iio/adc/ad4000.c +2
-1ret =ad4000_prepare_3wire_mode_message (st, &indio_dev->channels[0 ]);if (ret) -return ret; +return dev_err_probe (dev, ret, +"Failed to optimize SPI msg\n" );break ;
Re: [PATCH v2 2/5] iio: adc: ad4000: Add support for SPI offload
Quoted 9 lines · David Lechner
Quoted 8 lines · Marcelo Schmitt
FPGA HDL projects can include a PWM generator in addition to SPI-Engine. The PWM IP is used to trigger SPI-Engine offload modules that in turn set SPI-Engine to execute transfers to poll data from the ADC. That allows data to be read at the maximum sample rates. Also, it is possible to set a specific sample rate by setting the proper PWM duty cycle and related state parameters, thus allowing an adjustable ADC sample rate when a PWM (offload trigger) is used in combination with SPI-Engine.
Quoted 7 lines
Quoted 4 lines
Add support for SPI offload.
Signed-off-by Marcelo Schmitt <[email protected]>---
I'm surprised I'm not on the CC for this series.
scripts/get_maintainer.plshould have picked me up due to K:spi_offloadwhich matches this patch.
get_maintainers doesn't list you if run over ad4000.c.
If run over the patch file, get_maintainers lists many developers. Some of them don't seem to be related to this series, so I cropped the list to avoid churn. Will CC you on the next versions.
Quoted 9 lines
Quoted 6 lines
Instead of changing
bits_per_wordaccording to buffer endianness, I setbits_per_wordfor other SPI transfers and updated IIO channels to always use CPU endianness (the first patch in the series). With that,bits_per_wordno longer needs be updated according to buffer endianness or, in other words, buffer endianness is no longer related tobits_per_word.As mentioned in my reply to the previous patch, this is a breaking change, so probably not the best choice.
Ack
Quoted 19 lines
Quoted 19 lines
drivers/iio/adc/Kconfig | 7 +- drivers/iio/adc/ad4000.c | 491 ++++++++++++++++++++++++++++++++------- 2 files changed, 419 insertions(+), 79 deletions(-)drivers/iio/adc/Kconfig +2
-0@@ -25,10 +25,15 @@ config AD4000 tristate "Analog Devices AD4000 ADC Driver" depends on SPI select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD4000 high speed
Quoted 8 lines
drivers/iio/adc/Kconfig config AD4000 · line 36
Quoted 5 lines
drivers/iio/adc/Kconfig +4
-1- SPI analog to digital converters (ADC). + SPI analog to digital converters (ADC). If intended to use with + SPI offloading support, it is recommended to enable + CONFIG_SPI_AXI_SPI_ENGINE, CONFIG_PWM_AXI_PWMGEN, and + CONFIG_SPI_OFFLOAD_TRIGGER_PWM.I guess this is fine here, but people might be more likely to see it on the ADI wiki where the HDL project that has these requirements is described.
I don't see any word about that at
https://analogdevicesinc.github.io/hdl/projects/pulsar_adc/index.html
If no one opposes to that, I'd like to keep the piece of advice.
Quoted 11 lines
Quoted 11 lines
drivers/iio/adc/Kconfig +0
-0To compile this driver as a module, choose M here: the module will be called ad4000.drivers/iio/adc/ad4000.c +0
-0@@ -21,9 +21,12 @@#include <linux/iio/iio.h>
Quoted 8 lines
drivers/iio/adc/ad4000.c line 28
Quoted 6 lines
drivers/iio/adc/ad4000.c +2
-0#include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> +#include <linux/spi/offload/consumer.h> Why not before #include <
linux/spi/spi.h> ?
Okay, will put it there.
Quoted 1 line
...
Quoted 10 lines
drivers/iio/adc/ad4000.c line 44
Quoted 5 lines
drivers/iio/adc/ad4000.c +3
-1-#define __AD4000_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, _reg_access) \ +#define AD4000_TQUIET1_NS 190 +#define AD4000_TQUIET2_NS 60 +#define AD4000_TCONV_NS 320Does this actually work for every single chip? For example, the AD7983 datasheet give the max as 500 ns for this timing parameter. Might need to put this in the
chip_infoto account for differences.
Quoted 2 lines
Also AD7983 doesn't have any quite time in the datasheet, so those might not be needed in some cases?
I've tested the series with AD7687 and ADAQ4003 and got good readings. I'll check the timing specifications again and provide a delay long enough for AD7983 and any other device with longer TCONV.
Quoted 1 line
...
Quoted 5 lines
drivers/iio/adc/ad4000.c line 71
Quoted 2 lines
drivers/iio/adc/ad4000.c +1
-1-#define AD4000_DIFF_CHANNELS (_sign, _real_bits, _reg_access) \ +#define AD4000_DIFF_CHANNELS (_sign, _real_bits, _reg_access, _offl) \We always pass 0 to
_offlhere, so we can leave out this parameter and just hard-code the 0 below. We will never have a case with offload + soft timestamp.
Good catch. Will apply the simplification.
Quoted 1 line
...
Quoted 8 lines
Quoted 8 lines
drivers/iio/adc/ad4000.c +2
-1-#define __AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, _reg_access)\ +#define __AD4000_PSEUDO_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, \ + _reg_access, _offl) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = 0, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
Quoted 8 lines
drivers/iio/adc/ad4000.c line 87
Quoted 6 lines
drivers/iio/adc/ad4000.c +3
-2BIT (IIO_CHAN_INFO_SCALE ) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ +BIT (IIO_CHAN_INFO_OFFSET ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = (_reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0),\Unrelated change (adding braces)?
Oops, will undo.
Quoted 3 lines
Also, could be nice to have
sampling_frequency_availableso that userspace can discover the max sample rate.
I don't think we should have sampling_frequency_available in this case because there is no clear list of sample frequency values nor they can always be expressed as "[min step max]" triad.
https://web.git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/Documentation/ABI/testing/sysfs-bus-iio?h=testing#n121
Quoted 1 line
...
Quoted 4 lines
drivers/iio/adc/ad4000.c line 102
Quoted 2 lines
drivers/iio/adc/ad4000.c +1
-1-#define AD4000_PSEUDO_DIFF_CHANNELS (_sign, _real_bits, _reg_access) \ +#define AD4000_PSEUDO_DIFF_CHANNELS (_sign, _real_bits, _reg_access, _offl) \ditto about hard-coding
_offlhere
Ack
Quoted 1 line
...
Quoted 10 lines
drivers/iio/adc/ad4000.c struct ad4000_chip_info { · line 460
Quoted 7 lines
static const struct
ad4000_chip_infoad7983_chip_info= {drivers/iio/adc/ad4000.c +3
-1.dev_name = "ad7983", - .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), + .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0, 0), + .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1330 * KILO,This is actually 752 ns period when 750 is allowed. Could make it 1 * MEGA + 333
* KILO + 333 or 1333333.
Ack
Quoted 12 lines
drivers/iio/adc/ad4000.c struct ad4000_chip_info { · line 468
Quoted 10 lines
};
static const struct
ad4000_chip_infoad7984_chip_info= {drivers/iio/adc/ad4000.c +3
-1.dev_name = "ad7984", - .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), + .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0, 0), + .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1), .time_spec = &ad7983_t_spec, + .max_rate_hz = 1330 * KILO,ditto
Ack
Quoted 1 line
...
Quoted 5 lines
drivers/iio/adc/ad4000.c static const struct iio_info ad4000_reg_access_info = { · line 831
Quoted 3 lines
drivers/iio/adc/ad4000.c +3
-0+static const struct iio_buffer_setup_ops ad4000_offload_buffer_setup_ops = { + .postenable = &ad4000_offload_buffer_postenable, + .postdisable = &ad4000_offload_buffer_postdisable,Needs to be predisable to correctly balance postenable.
Ack
Quoted 1 line
...
Quoted 4 lines
Quoted 4 lines
drivers/iio/adc/ad4000.c +4
-0+static int ad4000_prepare_offload_turbo_message (struct ad4000_state *st, +const struct iio_chan_spec *chan) +{ +struct spi_transfer *xfers = st->offload_xfers;
Quoted 8 lines
drivers/iio/adc/ad4000.c static const struct iio_info ad4000_reg_access_info = { · line 894
Quoted 6 lines
drivers/iio/adc/ad4000.c +6
-0+ +/* Have to do a short CS toggle to trigger conversion. */ + xfers[0 ].cs_change =1 ; + xfers[0 ].cs_change_delay.value =AD4000_TQUIET1_NS ; + xfers[0 ].cs_change_delay.unit =SPI_DELAY_UNIT_NSECS ; + xfers[0 ].offload_flags =SPI_OFFLOAD_XFER_RX_STREAM ;There is no data transferred in this xfer, so we don't need to set this flag.
Ack
Quoted 1 line
...
Quoted 6 lines
Quoted 6 lines
drivers/iio/adc/ad4000.c +3
-2case AD4000_SDI_VIO : - indio_dev->info = &ad4000_info; - indio_dev->channels = chip->chan_spec; +if (st->using_offload) { + indio_dev->info = &ad4000_offload_info; + indio_dev->channels = &chip->offload_chan_spec;
Quoted 8 lines
drivers/iio/adc/ad4000.c static int ad4000_probe(struct spi_device *spi) · line 1134
Quoted 4 lines
drivers/iio/adc/ad4000.c +4
-0+ indio_dev->num_channels =1 ; + + spi->cs_hold.value =AD4000_TCONV_NS ; + spi->cs_hold.unit =SPI_DELAY_UNIT_NSECS ;Modifying spi is suspicious. Normally, this would come from the devicetree. And this isn't used by all SPI drivers - notably the AXI SPI Engine ignores it. Better to just handle this in individual spi xfer structs.
Will try that.
Quoted 12 lines
drivers/iio/adc/ad4000.c static int ad4000_probe(struct spi_device *spi) · line 1143
Quoted 10 lines
drivers/iio/adc/ad4000.c +9
-0+ ret =ad4000_prepare_offload_message (st, indio_dev->channels); +if (ret) +return dev_err_probe (dev, ret, +"Failed to optimize SPI msg\n" ); + }else { + indio_dev->info = &ad4000_info; + indio_dev->channels = chip->chan_spec; + indio_dev->num_channels =ARRAY_SIZE (chip->chan_spec); + }nit: add extra blank line here
Ack
Quoted 9 lines
Quoted 8 lines
drivers/iio/adc/ad4000.c +2
-1ret =ad4000_prepare_3wire_mode_message (st, &indio_dev->channels[0 ]);if (ret) -return ret; +return dev_err_probe (dev, ret, +"Failed to optimize SPI msg\n" );break ;
David Lechner
reviewerRe: [PATCH v2 2/5] iio: adc: ad4000: Add support for SPI offload
Quoted 15 lines · Marcelo Schmitt
Quoted 14 lines · David Lechner
Quoted 12 lines · Marcelo Schmitt
FPGA HDL projects can include a PWM generator in addition to SPI-Engine. The PWM IP is used to trigger SPI-Engine offload modules that in turn set SPI-Engine to execute transfers to poll data from the ADC. That allows data to be read at the maximum sample rates. Also, it is possible to set a specific sample rate by setting the proper PWM duty cycle and related state parameters, thus allowing an adjustable ADC sample rate when a PWM (offload trigger) is used in combination with SPI-Engine.
Add support for SPI offload.
Signed-off-by Marcelo Schmitt <[email protected]>---
Quoted 8 lines
Quoted 2 lines
I'm surprised I'm not on the CC for this series.
scripts/get_maintainer.plshould have picked me up due to K:spi_offloadwhich matches this patch.
get_maintainersdoesn't list you if run overad4000.c.
If run over the patch file,get_maintainerslists many developers. Some of them don't seem to be related to this series, so I cropped the list to avoid churn. Will CC you on the next versions.
I use b4 these days, but IIRC, I used to use the --no-git-fallback option of get_maintainer.pl to prune the list while keeping actual matches from the MAINTAINERS file that shouldn't be pruned.
Marcelo Schmitt
maintainerPATCH v2 3/5 Documentation: iio: ad4000: Add new supported parts
In reply to Marcelo SchmittCommit <c3948d090080> ("iio: adc: ad4000: Add support for PulSAR devices"), extended the ad4000 driver supports many single-channel PulSAR devices.
Update IIO ad4000 documentation with the extra list of supported devices.
--- Documentation/iio/ad4000.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
Documentation/iio/ad4000.rst +16 -1
@@ -4,7 +4,7 @@ AD4000 driver ============= -Device driver for Analog Devices Inc. AD4000 series of ADCs. +Device driver for Analog Devices Inc. AD4000 series of ADCs and similar devices. Supported devices =================
@@ -25,6 +25,21 @@ Supported devices * `AD4022 <https://www.analog.com/AD4022>`_ * `ADAQ4001 <https://www.analog.com/ADAQ4001>`_ * `ADAQ4003 <https://www.analog.com/ADAQ4003>`_ +* `AD7685 <https://www.analog.com/AD7685>`_ +* `AD7686 <https://www.analog.com/AD7686>`_ +* `AD7687 <https://www.analog.com/AD7687>`_ +* `AD7688 <https://www.analog.com/AD7688>`_ +* `AD7690 <https://www.analog.com/AD7690>`_ +* `AD7691 <https://www.analog.com/AD7691>`_ +* `AD7693 <https://www.analog.com/AD7693>`_ +* `AD7942 <https://www.analog.com/AD7942>`_ +* `AD7946 <https://www.analog.com/AD7946>`_ +* `AD7980 <https://www.analog.com/AD7980>`_ +* `AD7982 <https://www.analog.com/AD7982>`_ +* `AD7983 <https://www.analog.com/AD7983>`_ +* `AD7984 <https://www.analog.com/AD7984>`_ +* `AD7988-1 <https://www.analog.com/AD7988-1>`_ +* `AD7988-5 <https://www.analog.com/AD7988-5>`_ Wiring connections ------------------
Signature · 1 line
2.47.2
Re: [PATCH v2 3/5] Documentation: iio: ad4000: Add new supported parts
Quoted 7 lines · Marcelo Schmitt
Commit <
c3948d090080> ("iio: adc: ad4000: Add support for PulSAR devices"), extended the ad4000 driver supports many single-channel PulSAR devices.Update IIO ad4000 documentation with the extra list of supported devices.
Signed-off-by Marcelo Schmitt <[email protected]>---
Marcelo Schmitt
maintainerPATCH v2 4/5 Documentation: iio: ad4000: Add IIO Device characteristics section
In reply to Marcelo SchmittComplement ad4000 IIO driver documentation with considerations about ``_scale_available`` attribute and table of typical channel attributes.
--- Documentation/iio/ad4000.rst | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
Documentation/iio/ad4000.rst +47 -0
@@ -144,3 +144,50 @@ Set ``adi,sdi-pin`` to ``"cs"`` to select this mode. ^ | | +--------------------| SCLK | +-------------+ + +IIO Device characteristics +========================== + +The AD4000 series driver supports differential and pseudo-differential ADCs. + +The span compression feature available in AD4000 series devices can be +enabled/disabled by changing the ``_scale_available`` attribute of the voltage +channel. Note that span compression configuration requires writing to AD4000 +configuration register, which is only possible when the ADC is wired in 3-wire +turbo mode, and the SPI controller is ``SPI_MOSI_IDLE_HIGH`` capable. If those +conditions are not met, no ``_scale_available`` attribute is provided. + +Besides that, differential and pseudo-differential voltage channels present +slightly different sysfs interfaces. + +Pseudo-differential ADCs +------------------------ + +Typical voltage channel attributes of a pseudo-differential AD4000 series device: + ++-------------------------------------------+------------------------------------------+ +| Voltage Channel Attributes | Description | ++===========================================+==========================================+ +| ``in_voltage0_raw`` | Raw ADC output code. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_offset`` | Offset to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_scale`` | Scale factor to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0_scale_available`` | Toggles input span compression | ++-------------------------------------------+------------------------------------------+ + +Differential ADCs +----------------- + +Typical voltage channel attributes of a differential AD4000 series device: + ++-------------------------------------------+------------------------------------------+ +| Voltage Channel Attributes | Description | ++===========================================+==========================================+ +| ``in_voltage0-voltage1_raw`` | Raw ADC output code. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0-voltage1_scale`` | Scale factor to convert raw value to mV. | ++-------------------------------------------+------------------------------------------+ +| ``in_voltage0-voltage1_scale_available`` | Toggles input span compression | ++-------------------------------------------+------------------------------------------+
Signature · 1 line
2.47.2
Re: [PATCH v2 4/5] Documentation: iio: ad4000: Add IIO Device characteristics section
Quoted 5 lines · Marcelo Schmitt
Complement ad4000 IIO driver documentation with considerations about ``_scale_available`` attribute and table of typical channel attributes.
Signed-off-by Marcelo Schmitt <[email protected]>---
With or without the suggested change:
Quoted 2 lines
+Differential ADCs
+-----------------
Could say Fully or True differential here to be less ambiguous if you like.
Marcelo Schmitt
maintainerPATCH v2 5/5 Documentation: iio: ad4000: Describe offload support
In reply to Marcelo SchmittWhen SPI offloading is supported, the IIO device provides different sysfs interfaces to allow using the adjusting the sample rate. Document SPI offload support for AD4000 and similar devices.
--- Documentation/iio/ad4000.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
Documentation/iio/ad4000.rst +22 -0
@@ -191,3 +191,25 @@ Typical voltage channel attributes of a differential AD4000 series device: +-------------------------------------------+------------------------------------------+ | ``in_voltage0-voltage1_scale_available`` | Toggles input span compression | +-------------------------------------------+------------------------------------------+ + +SPI offload support +------------------- + +To be able to achieve the maximum sample rate, the driver can be used with the +`AXI SPI Engine`_ to provide SPI offload support. + +.. _AXI SPI Engine: http://analogdevicesinc.github.io/hdl/projects/pulsar_adc/index.html + +When set for SPI offload support, the IIO device will provide different +interfaces. + +* Either ``in_voltage0_sampling_frequency`` or + ``in_voltage0-voltage1_sampling_frequency`` file is provided to allow setting + the sample rate. +* IIO trigger device is not provided (no ``trigger`` directory). +* ``timestamp`` channel is not provided. + +Also, because the ADC output has a one sample latency (delay) when the device is +wired in "3-wire" mode and only one transfer per sample is done when using SPI +offloading, the first data sample in the buffer is not valid because it contains +the output of an earlier conversion result.
Signature · 1 line
2.47.2
Re: [PATCH v2 5/5] Documentation: iio: ad4000: Describe offload support
Quoted 6 lines · Marcelo Schmitt
When SPI offloading is supported, the IIO device provides different sysfs interfaces to allow using the adjusting the sample rate. Document SPI offload support for AD4000 and similar devices.
Signed-off-by Marcelo Schmitt <[email protected]>---