Skip to content

iio: adc: ADEMA124/ADEMA127 driver with hardware-triggered SPI Offload streaming for SC846 - #3481

Open
mhennerich wants to merge 16 commits into
adsp-6.18.31-yfrom
staging/sc846-adema127-offload
Open

iio: adc: ADEMA124/ADEMA127 driver with hardware-triggered SPI Offload streaming for SC846#3481
mhennerich wants to merge 16 commits into
adsp-6.18.31-yfrom
staging/sc846-adema127-offload

Conversation

@mhennerich

Copy link
Copy Markdown
Contributor

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-y once #3480 merges.

Driver

  • dt-bindings + ADEMA124/ADEMA127 IIO driver: regmap over the chip's
    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.
  • The SPI Offload streaming backend lives in its own file
    (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.
  • docs + defconfig enablement (ADEMA127, the TRU offload trigger and
    the gptimer driver the trigger chain requires).

SPI Offload infrastructure

  • dmaengine: adi-dma: trigger-gated transfers (TWAIT) and a hardware
    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.
  • spi: adi: optional SPI Offload framework provider (offload-tx/rx
    stream DMA channels + trigger wiring, hardware CS via SLVSEL for
    offload slaves).
  • spi: offload: TRU-backed data-ready trigger provider: routes a
    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.
  • Board device trees for the EZ-kit + ADEMA127 (software-triggered
    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.

@mhennerich mhennerich added sc846 Support for the ADSP-SC846 llm review Request a review from a LLM Reviewer labels Aug 6, 2026
@mhennerich
mhennerich requested review from a team August 6, 2026 11:20
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch 2 times, most recently from 0939d42 to d3dd87c Compare August 6, 2026 11:41
@github-actions

This comment was marked as resolved.

@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch 2 times, most recently from 0f92425 to b46abee Compare August 6, 2026 13:12
@mhennerich
mhennerich force-pushed the staging/sc84x-platform-fixes branch from 531fe7f to 3f89a33 Compare August 6, 2026 15:21
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch from b46abee to f7043f1 Compare August 6, 2026 15:23
@nunojsa nunojsa added llm review Request a review from a LLM Reviewer and removed llm review Request a review from a LLM Reviewer labels Aug 7, 2026
@github-actions

This comment was marked as resolved.

@mhennerich
mhennerich force-pushed the staging/sc84x-platform-fixes branch from 3f89a33 to 6fbda9d Compare August 7, 2026 09:33
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch 2 times, most recently from 2bf52d8 to 29888e7 Compare August 7, 2026 10:39
@pamolloy pamolloy added this to ADSP Aug 7, 2026
@mhennerich
mhennerich force-pushed the staging/sc84x-platform-fixes branch from 6fbda9d to 8f1da79 Compare August 7, 2026 15:47
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch from 29888e7 to 282fc95 Compare August 7, 2026 15:47
Base automatically changed from staging/sc84x-platform-fixes to adsp-6.18.31-y August 10, 2026 06:18
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>
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch from 282fc95 to 4c22029 Compare August 10, 2026 06:28
@gastmaier gastmaier added llm review Request a review from a LLM Reviewer and removed llm review Request a review from a LLM Reviewer labels Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

LLM review

This series adds the ADEMA124/ADEMA127 poly-phase energy-metering ADC
driver (software-triggered + SPI-Offload streaming paths), a new SPI
Offload provider for the ADI SC5xx SPI3 controller, a TRU-backed
DATA_READY trigger provider, TWAIT/descriptor-list-cyclic support in
adi-dma, an EXTCLK trigger-generator mode for the SC5xx GP timers, a TRU
null-master routing fix, new DT bindings, two SC846 SOM EZ-Kit boards, and
defconfig wiring.

run: 31366180363

This is a rebased revision of the series previously reviewed twice on PR
#3481 (runs 31096870873, 31155852024). All previously reported issues
are confirmed fixed here: the long-frame byte-order bug, the duplicate
include, the dead MODULE_IMPORT_NS, the two dt-bindings schema failures,
the adi_sc_tru_probe() IS_ERR()/PTR_ERR() fix, the stale dts
comments, and the endianness doc-comment mismatch.

bd2392097c34f - dmaengine: adi-dma: add TWAIT support for SPI-offload triggers

Misleading comment: the comment added to adi_prep_cyclic() claims "In
AUTOBUFFER mode bit 18 of DMA_CFG is TWAIT; the same bit becomes NDSIZE_4
in descriptor-list mode". Per the ADSP-SC84x HRM (Table 34-22) this is
wrong: DMA_CFG.TWAIT is always bit 15 (CFG_TWAIT = 0x8000) and bit 18
is always the top bit of the unrelated NDSIZE field, regardless of flow
mode. The code is correct (CFG_TWAIT is used in both the AUTOBUFFER and
descriptor-list paths), and the commit message itself has the right bit
numbers ("DMA_CFG.TWAIT is bit 15... Bit 18 is NDSIZE[2]") — only the
in-code comment contradicts it. Comment-only, but worth fixing before it
misleads someone into "fixing" working code.

CI warnings

checkpatch --strict is clean of new issues (0 errors); the remaining
warnings/checks (MAINTAINERS reminders, DTS >100-col comment-aligned
lines, _idx macro-arg-reuse, open-paren alignment CHECKs) are the same
ones already annotated by CI and unchanged from prior rounds. The
icc.c:76 put_device coccicheck error and the timer-adi-adsp-sc5xx.c
%pe suggestion sit in code not touched by this range (confirmed via git log -L on the relevant lines) — pre-existing, out of scope.

Verification data

Built sc846-som_defconfig (full kernel + all modules, gcc_aarch64) with
0 warnings/errors, including after the fixup. Ran make dtbs_check
(dtschema) on both new boards — no schema violations on any
adema127/spi3/gptimer/TRU-trigger node; remaining messages are
pre-existing on the base board. Ran coccicheck on the touched
subsystems. Cross-checked the TRU trigger IDs, EXTCLK timer register
programming, SPI TWC/RWC/word-counter sequencing, and DMA TWAIT semantics
against the ADSP-SC84x HRM, and the ADEMA127/124 long-frame byte layout
against adema124-127.pdf (fetched from the ADI docling mirror and
converted to Markdown) — all match the datasheet/HRM text verbatim; this
cross-check is what surfaced the TWAIT/NDSIZE comment bug above.

Suggested patches

Apply the suggested patches with:

cd path/to/repository
export GITHUB_TOKEN=ghp_***
apply-patches --repo=analogdevicesinc/linux 31366180363
Install instructions

The following one-liner installs the script if not present already:

curl -fSsL "https://raw.githubusercontent.com/analogdevicesinc/doctools/refs/heads/main/ci/scripts/apply-patches.sh"      -o ~/.local/bin/apply-patches.sh &&   grep -q "/apply-patches.sh" ~/.bashrc || echo "source ~/.local/bin/apply-patches.sh" >> $_ ; . $_

More information at AI Usage.

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>
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch from 4c22029 to 657ef6a Compare August 10, 2026 10:38
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>
@mhennerich
mhennerich force-pushed the staging/sc846-adema127-offload branch from 657ef6a to d341ad8 Compare August 10, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llm review Request a review from a LLM Reviewer sc846 Support for the ADSP-SC846

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants