iio: adc: ADEMA124/ADEMA127 driver with hardware-triggered SPI Offload streaming for SC846 - #3481
iio: adc: ADEMA124/ADEMA127 driver with hardware-triggered SPI Offload streaming for SC846#3481mhennerich wants to merge 16 commits into
Conversation
0939d42 to
d3dd87c
Compare
This comment was marked as resolved.
This comment was marked as resolved.
0f92425 to
b46abee
Compare
531fe7f to
3f89a33
Compare
b46abee to
f7043f1
Compare
This comment was marked as resolved.
This comment was marked as resolved.
3f89a33 to
6fbda9d
Compare
2bf52d8 to
29888e7
Compare
6fbda9d to
8f1da79
Compare
29888e7 to
282fc95
Compare
Add DT binding for the Analog Devices ADEMA124 and ADEMA127 poly-phase energy metering ADCs. Both parts share the same SPI command / long-frame response protocol and are keyed at runtime by the PRODUCT_ID register. The binding describes SPI mode 3, the DREADY line (either as a "dready" interrupt or as dready-gpios, preferred on SoCs whose pin-interrupt blocks observe the pad behind an input-buffer enable), an optional active-low RESET GPIO, the mandatory XTALIN clock (typically a fixed-clock at 16.384 MHz), the optional adi,offload-frames-per-interrupt default for SPI-offload streaming, and per-channel override nodes for the analog input gain and polarity invert settings. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
282fc95 to
4c22029
Compare
LLM reviewThis series adds the ADEMA124/ADEMA127 poly-phase energy-metering ADC run: 31366180363 This is a rebased revision of the series previously reviewed twice on PR
|
Add a Linux IIO driver for the Analog Devices ADEMA124 (4-channel) and ADEMA127 (7-channel) 24-bit simultaneous-sampling sigma-delta ADCs used in poly-phase energy metering. Both parts share the same SPI protocol and are keyed at runtime by the PRODUCT_ID register (0x13 = ADEMA124, 0x16 = ADEMA127). Register access uses a custom regmap bus that implements the 6-byte short-frame command/response protocol with an 8-bit command CRC (polynomial 0x07, xor 0x55) and a 16-bit CCITT-FALSE response CRC. DSP RAM (calibration coefficients, gain/offset, cross-talk) is exposed through the same regmap, gated by the ACCESS_EXTENDED_MMAP window and STATUS2.DSP_MEM_ACCESS_READY handshake. DSP RAM powers up with undefined contents and the chip only loads its ROM defaults once a DSP filter is enabled while the datapath config lock is set, so probe pulses a filter enable once to make every DSP-RAM-backed attribute read its documented default instead of die-random SRAM state. Two sample-capture paths are supported. The default per-DREADY software triggered IIO buffer works on any SPI controller: the DREADY interrupt kicks an IIO trigger whose handler runs one long-frame spi_sync read of STATUS2, validates the trailing CRC-CCITT, unpacks the interleaved channel/status frame and pushes the result. When the underlying SPI controller advertises SPI_OFFLOAD_CAP_TRIGGER + SPI_OFFLOAD_CAP_RX_STREAM_DMA the driver switches to the SPI Offload framework so that the SPI engine autonomously issues the long-frame command on every hardware trigger and streams the response into a DMA channel with no CPU per-sample overhead. Per-channel IIO attributes cover scale, calibbias (channel offset), calibscale (2.22 gain), phase (PHASE_OFFSET), cross-talk gain and aggressor selection, arithmetic shift, DC-block alpha and the six datapath filter enables (HPF/LPF/SCF/comp/allpass/gain_offset_xt). Device-level attributes expose the shared sampling frequency (via the DATARATE table, scaled by the XTAL clock rate reported through the Common Clock Framework), a sync_align write-only button that issues SYNC_SNAP.ALIGN, and a test_pattern selector for the CONFIG0.STREAM_DBG debug modes (normal / static / increment). An optional reset GPIO is used at probe when described in DT, otherwise the driver falls back to a software reset via the SWRST key. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
4c22029 to
657ef6a
Compare
Extend the ADI SC5xx DMA controller driver with per-channel TWAIT
gating so that slave-DMA consumers can stall the channel between work
units until an external TRU trigger arrives. This is the foundation
piece for high-rate hardware-triggered SPI offload consumers such as
the ADEMA124/127 poly-phase energy ADCs, where each DREADY pulse must
gate exactly one SPI transaction with zero CPU involvement.
DMA_CFG.TWAIT is bit 15 (mask 0x00008000) per the ADSP-SC84x HRM
Table 34-22. Bit 18 is NDSIZE[2]; setting it instead of TWAIT in
AUTOBUFFER mode is silently ignored and the channel free-runs without
trigger gating.
Introduce a public header, include/linux/dma/adi-dma.h, exposing an
opt-in slave-config extension:
struct adi_dma_peripheral_config {
unsigned int flags;
};
#define ADI_DMA_PC_WAIT_FOR_TRIGGER BIT(0)
Passed through the standard dmaengine peripheral_config /
peripheral_size fields. The driver copies the flag content out of the
caller-owned struct in device_config so it survives past the call.
Per the SC5xx HRM, in AUTOBUFFER mode the FIRST work unit fires
without waiting for a trigger regardless of TWAIT; the consumer is
responsible for discarding the resulting first sample if that
matters. This is called out in the header kerneldoc.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
The AUTOBUFFER cyclic implementation raises DI_EN_X once per period and cannot express "interrupt only every N trigger-gated work units": with TWAIT gating, each work unit is one peripheral frame, so a 250 SPS..32 kSPS stream costs one interrupt per frame. Implement the DDE descriptor-list mode (HRM "Descriptor List Mode"): when the client's adi_dma_peripheral_config carries a non-zero trigger_granule together with ADI_DMA_PC_WAIT_FOR_TRIGGER, dmaengine_prep_dma_cyclic() builds a coherent ring of 5-word descriptor sets (NDSIZE_4: NXT/ADDRSTART/CFG/XCNT/XMOD), one per granule, each gated on a TRU trigger via CFG.TWAIT, with DI_EN_X only in the last descriptor of each period_len. The ring loops in hardware with no per-work-unit MMR writes; the dmaengine cyclic callback fires once per period. Verified on ADSP-SC846: exactly one interrupt per 128 triggered 32-byte frames at 250 SPS and 8 kSPS. Unlike AUTOBUFFER TWAIT, descriptor-list TWAIT also gates the FIRST descriptor fetch, so there is no spurious untriggered first work unit. The optional ADI_DMA_PC_DISCARD_FIRST flag additionally prepends a non-interrupting head descriptor that steers the first granule into the ring's final slot (rewritten with real data before that slot's period completes), for peripherals whose protocol makes the first response spurious. Freeing a descriptor may now release dma_alloc_coherent memory, so terminate_all collects descriptors under the channel lock but frees them after unlocking — dma_free_coherent() must not be called with interrupts disabled. Clients that do not set trigger_granule keep the existing register-mode AUTOBUFFER behaviour unchanged. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
adi_tru_set_trigger_by_id() rejected master ID 0 as out of range, but per the HRM trigger master ID 0 is reserved and defined as null — writing 0 to a slave's RSR is precisely how that slave is disconnected from its trigger source. Accept it, and fix the error path that printed the slave ID while complaining about an invalid master ID. Needed by the SPI-offload TRU trigger provider, which disconnects the SPI DMA trigger receivers on trigger_disable. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Document the previously undocumented general-purpose timer block binding, including the per-timer clocksource/clockevent roles and the EXTCLK trigger-generator mode (adi,mode-extclk-gen / adi,extclk-active-low) used as the data-ready trigger source for SPI offload streaming. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Allow a GP timer to be dedicated as a trigger generator that converts edges on its TMR pin into TRU trigger pulses: EXTCLK mode with PER=1 fires the timer's TRG output on every counted input edge. Selected per timer via the "adi,mode-extclk-gen" DT property; "adi,extclk-active-low" selects falling-edge counting. The timer is a pure trigger source in this mode — no clocksource, clockevent or userspace-counter registration. Two register-level requirements are easy to miss: * TIMER_TMR[n]_CFG.IRQMODE must be 3 (Period Expired). The HRM warns that "any mismatched combination of IRQMODE and TMODE bits results in no interrupt being generated" — and no TRG output either. IRQMODE=0 (Active Edge) is valid only for PININT mode. * TIMER_TRG_MSK resets to all-masked; the timer's bit must be cleared or the TRG line never reaches the TRU. This provides the DREADY -> TRU trigger source for SPI-offload streaming, e.g. the ADEMA127 energy ADC which pulses DREADY once per sample set. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Binding for the TRU-backed data-ready SPI offload trigger provider on the ADSP-SC59x / SC84x family: routes a TRU generator (typically a GP timer in EXTCLK mode fed by a data-ready pin) to the TRU receiver IDs of a SPI controller's TX/RX DMA channels. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
The TRU routing API is usable by built-in code only: adi_tru_set_trigger_by_id() lacks an export, so the first modular consumer (the SC5xx TRU SPI offload trigger provider, buildable as a module) fails modpost with an undefined reference. Export it like the rest of the adi_tru API. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
The SC59x cannot forward a chip-level DREADY GPIO edge directly to a
SPI DMA channel — the Trigger Routing Unit needs an edge-sensitive
generator (a GP timer in EXTCLK mode driven by DREADY) at one end,
and one or more SPI-DMA receiver IDs at the other. Add a small SPI
Offload framework trigger provider that manages that last hop: it
programs the TRU RSR entries on trigger enable and clears them on
disable, exposing the SPI_OFFLOAD_TRIGGER_DATA_READY trigger type to
consumers such as the ADEMA124/127 IIO driver.
Timer programming is out of scope for v1 — the current
timer-adi-adsp-sc5xx driver has no EXTCLK/PER=1 path. Boot firmware
or a companion timer consumer must set the timer up. What this driver
takes care of is:
* Reading the "adi,tru" phandle, the generator ID and the list of
receiver IDs from DT.
* Registering a DATA_READY spi_offload_trigger via
devm_spi_offload_trigger_register().
* Installing every configured (master → slave) route on .enable(),
tearing them down on .disable(), and cleaning up any partial
routing on error.
Consumer wiring in DT: an SC59x SPI controller node points at this
provider via "trigger-sources", the ADC's IIO driver requests offload
via devm_spi_offload_get() and DATA_READY via
devm_spi_offload_trigger_get().
Companion pieces:
* dmaengine/adi-dma: ADI_DMA_PC_WAIT_FOR_TRIGGER — sets DMA_CFG.TWAIT
* drivers/spi/spi-adi: SPI Offload provider ops
The DT binding is added by the preceding
"dt-bindings: trigger-source: add ADI SC5xx TRU SPI offload trigger"
patch.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Document the previously undocumented ADSP-SC5xx / SC84x SPI3 controller binding, including the SPI Offload extensions: the "offload-tx"/"offload-rx" DMA channel names and the trigger-sources phandle that enables the offload provider on a port. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Add an optional SPI Offload framework provider to the ADI SC5xx SPI3
controller driver so hardware-triggered high-rate ADC sampling can run
autonomously without CPU per-sample cost. Enabled only when the port's
DT node declares "trigger-sources" — existing users on this driver are
unaffected.
Implemented:
* devm_spi_offload_alloc() + get_offload/put_offload host callbacks
* spi_offload_ops:
- trigger_enable — flushes stale FIFO bytes with an explicit
SPI_CTL.EN 1->0 edge (per HRM the receive FIFO is only reset
"when the SPI is disabled after being enabled"; leftover
regmap-response bytes otherwise byte-shift the whole RX
stream), programs the LIVE word counters SPI_TWC/SPI_RWC as
well as the TWCR/RWCR reloads to the transfer length (the
reload registers alone leave TWC=0 and with TWCEN=1 the SPI
never raises a single TX DMA request), keeps duplex lock-step
initiation TTI=RTI=1 (TTI-only initiation waits for
TFIFO-empty before every transfer and collapses streaming to a
fraction of the trigger rate), ASSEL hardware CS framing of
each TWC-long transaction, CTL.EN written last per HRM
programming order
- trigger_disable — inverse, restores SLVSEL idle-high default
- rx_stream_request_dma_chan / tx_stream_request_dma_chan —
return the "offload-rx" / "offload-tx" DMA channels declared
in DT (kept separate from the regular "tx" / "rx" channels
used by normal spi_sync traffic)
* optimize_message hook — captures the single-transfer length for
the word-counter programming above
* Capability advertisement based on which "offload-*" DMA channels
are present in DT: always TRIGGER, plus RX_STREAM_DMA and
optionally TX_STREAM_DMA.
* Hardware chip-select for offload-capable slaves without cs-gpios:
adi_spi_setup() marks them hw_cs and the transfer paths assert the
matching SPI_SLVSEL SSE bit (BIT(cs), SSEL1..7) instead of a GPIO,
so both the regmap short-frame path and the autonomous offload
transactions drive the same dedicated SEL line.
* The regular "tx"/"rx" DMA channels are now optional at probe:
offload-only ports (dma-names = "offload-tx", "offload-rx") fall
back to PIO for non-offload transfers instead of failing to bind.
Companion pieces (in-tree):
* dmaengine/adi-dma: ADI_DMA_PC_WAIT_FOR_TRIGGER — sets DMA_CFG.TWAIT
* drivers/spi/spi-offload-trigger-adi-sc-tru.c: TRU-backed DATA_READY
trigger provider
The offload consumer (e.g. drivers/iio/adc/adema127.c) is responsible
for configuring the handed-off DMA channels with
ADI_DMA_PC_WAIT_FOR_TRIGGER via dmaengine_slave_config, and for
requesting SPI_OFFLOAD_TRIGGER_DATA_READY from the framework.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Complete the SPI-offload capture path so the ADEMA124/127 driver runs autonomously with zero CPU per sample on the ADI SC5xx SPI3 controller with TX + RX stream DMA. TX side: a single one-frame DMA-coherent buffer holds the "READ STATUS2 long" command word (bytes n-4..n-1, zeros before); a self-looping descriptor re-sends it on every DREADY-derived TRU trigger with no interrupts at all. RX side: a ping-pong ring of 2 banks behind the adi-dma hardware descriptor-list mode (trigger_granule = long_frame_len): one trigger-gated descriptor per frame, completion interrupt only from each bank's last descriptor. The bank size follows the IIO buffer watermark (clamped to a cap so a pathological watermark cannot exhaust CMA), so the interrupt rate is sample-rate / watermark and userspace owns the latency-vs-IRQ-rate trade-off through the standard ABI — e.g. watermark 128 at 250 SPS costs ~2 IRQ/s. The ring is allocated per buffer enable since its size depends on the watermark. The bank completion callback pushes the finished bank scan-by-scan into a kfifo IIO buffer. This replaces industrialio-buffer-dmaengine's block-mode slave-sg path, which never completes a block under the TWC-gated one-frame-per-trigger operating model. The ADEMA long-frame protocol is pipelined — the command rides in the tail of TX frame N and the data returns in frame N+1 — so the first RX frame after enable answers a stale pre-stream command. ADI_DMA_PC_DISCARD_FIRST drops it in hardware; every completed bank therefore contains a full watermark of valid scans, which matters because IIO pollers wake on a full watermark of buffer-size scans. Channel layout: the DMA delivers the chip's native 20/32-byte long-frame verbatim (ECHO/STATUS bytes interleaved with 24-bit samples, CRC trailer). Rather than one opaque u8 scan element, expose per-phase channels with scan_type le:s24/32>>8 — the waveform bytes are transmitted WAV_LO/WAV_MD/WAV_HI (little-endian, per the datasheet's Long Format Operation section) after the slot's housekeeping byte, so each sample sits in bits 31:8 of a little-endian 32-bit slot, which the IIO core shifts and sign-extends — plus one be:u32/32 trailer channel (RDD1/RDD0/CRC). available_scan_masks is all-or-none since the wire frame is fixed. The offload channels carry the same control attributes (raw, scale, calibbias/scale, phase, sampling_frequency, ext_info) as the software-triggered path; attribute access uses the regmap short-frame path while the buffer is idle. The streaming backend lives in its own file, adema127-spi-offload.c, compiled into the adema127 module when CONFIG_ADEMA127_SPI_OFFLOAD is set (default y when SPI_OFFLOAD is available). This keeps the vendor DMA coupling (linux/dma/adi-dma.h peripheral_config) out of the core chip driver: without the option, adema_setup_offload() is a static inline stub returning -ENODEV and the core falls back to the software triggered buffer with no offload code built at all. Trigger enable ordering: arm the RX ring first, then the TX loop, then enable the SPI-offload trigger that routes DREADY via the TRU into both DMA channels. Teardown in reverse in buffer_predisable. Companion pieces (all in-tree): * dmaengine/adi-dma: TWAIT + hardware descriptor-list cyclic mode * spi/spi-adi: SPI Offload provider ops on the SC5xx SPI3 * spi/spi-offload-trigger-adi-sc-tru: DATA_READY trigger provider Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
SC846 SOM EZ-Kit with the ADEMA127 daughter card on the SPI0 expansion header: SPI0 with GPIO chip select, DREADY wired to a PINT-capable GPIO (dready-gpios) for the per-DREADY triggered-buffer path, input buffers enabled on the input pins. Relies on the PINT2 GIC mapping fix in sc84x-64.dtsi. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
SC846 SOM EZ-Kit with the ADEMA127 daughter card wired for hardware-triggered SPI offload: * DREADY reworked to PB_07 (TM0_TMR0, ALT0 mux, input enabled) * gptimer0 switched to the EXTCLK trigger-generator mode (falling-edge, one TRG pulse per DREADY) * TRU route TIMER0_TMR00_GEN (173) -> SPI0_TXDMA/SPI0_RXDMA (149/150), IDs from the ADSP-SC84x HRM trigger lists * SPI0 in offload-only configuration: dma-names "offload-tx" / "offload-rx", hardware chip select on SSEL1 (no cs-gpios), regmap short-frame traffic falls back to PIO Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
…gger Enable the ADEMA124/ADEMA127 IIO driver (CONFIG_ADEMA127, which pulls in its SPI offload streaming backend by default) and the SC5xx TRU-backed SPI offload trigger provider used by the hardware-triggered capture path on the SC846 SOM EZ-kit + ADEMA127 boards. Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
657ef6a to
d341ad8
Compare
Adds the Analog Devices ADEMA124/ADEMA127 poly-phase energy metering
ADC driver and the platform plumbing for hardware-triggered SPI
Offload streaming on the ADSP-SC846, validated end-to-end on the SC846
SOM EZ-kit with an ADEMA127 daughter card.
Depends on #3480 (sc84x platform fixes); this PR is stacked on that
branch and should be retargeted to
adsp-6.18.31-yonce #3480 merges.Driver
CRC-protected short-frame SPI protocol, per-channel
scale/calibration/phase/filter controls (DSP-RAM backed attributes
incl. probe-time default load), XTAL-aware sample-rate table,
software-triggered buffer path on the DREADY interrupt.
(
adema127-spi-offload.c,CONFIG_ADEMA127_SPI_OFFLOAD, default y):DREADY-gated DMA descriptor rings stream the chip's native long
frames with one interrupt per bank of samples (IRQ rate =
sample-rate / watermark), no per-sample CPU involvement. Without the
option the core driver falls back to the software path.
the gptimer driver the trigger chain requires).
SPI Offload infrastructure
descriptor-list cyclic mode with per-descriptor interrupt control —
the offload path programs one trigger-gated descriptor per ADC
frame with an IRQ only on each bank's last descriptor.
stream DMA channels + trigger wiring, hardware CS via SLVSEL for
offload slaves).
GP-timer trigger generator (clocked by the ADC's DREADY pin in the
new clocksource EXTCLK mode) through the on-chip Trigger Routing
Unit to the SPI DMA request lines. Includes dt-bindings for the
trigger, the adi,spi3 controller, the gptimers, and the TRU
null-master routing support used to disconnect triggers on disable.
and SPI Offload variants).
Validation
SC846 SOM EZ-kit + ADEMA127: offload path at 250 SPS and 8 kSPS
(interrupt rate = SPS/watermark verified; frame-exact kfifo capture;
sane channel data), software-triggered path via the PINT DREADY
interrupt, attribute access incl. DSP-RAM calibration on both paths.
All SC59x/SC84x DTBs build cleanly.