Skip to content
View in the app

A better way to browse. Learn more.

Armbian Community Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Mainline Kernel 6.18 (Rock Pi S): rockchip-i2s-tdm fails to claim I2S0 MCLK/SCLK pins (m0 mapping) with passive S/PDIF transmitter

Featured Replies

Mainline Kernel 6.18 (Rock Pi S): rockchip-i2s-tdm registers locked in UNCLAIMED state with passive S/PDIF transverters (m0 mapping)

 

Hardware Setup

SoC: Rockchip RK3308 (Radxa Rock Pi S)

Audio Extension: 3 separate Wolfson WM8805 boards (I2S to S/PDIF TOSLINK), wired in parallel to the primary I2S0 bus for a multi-channel setup.

Pin Mapping (m0): Explicitly hardwired to m0 alternative function:

Pin 35 = GPIO2_A4 = I2S0_8CH_MCLK_M0 (pin 68 in pinctrl)

Pin 33 = GPIO2_A5 = I2S0_8CH_SCLK_M0 (pin 69 in pinctrl)

 

Software Environment

OS: Modern Armbian (Debian Trixie)

Kernel: Stable Mainline Linux 6.18.43-current-rockchip64

Sound Card Configuration: Registered via decompiled Device Tree using simple-audio-card with linux,spdif-dit as a passive dummy codec backend.

 

The Problem Description

While the ALSA layer registers the multi-channel device flawlessly and playback initiates without any software errors, the physical TOSLINK TX diodes remain completely dark.

Live kernel tracing exposes a strict power-gating and pinctrl-locking mechanism inside the mainline rockchip-i2s-tdm driver architecture when facing a headless/passive audio layout.

Deep-Dive Diagnostic Logs (Live under Stream Load)

When executing an 8-channel stream (speaker-test -D hw:1,0 -c 8), we verified the following states:

Clock Subsystem (/sys/kernel/debug/clk/clk_summary)
The internal audio PLL dividers calculate and lock perfectly onto the exact target frequency (48kHz multiple), and the reference counter increments from 3 to 4:

 

clk_i2s0_8ch_tx_src        1       1        0        12288000    0          0     50000      Y            deviceless                      no_connection_id

clk_i2s0_8ch_tx_mux     1       1        0        12288000    0          0     50000      Y               deviceless                      no_connection_id

clk_i2s0_8ch_tx      4       4        0        12288000    0          0     50000      Y                  i2s@ff300000                    no_connection_id      

clk_i2s0_8ch_tx_out 0       0        0        12288000    0          0     50000      N                     deviceless                      no_connection_id 

 

However, the physical output gate clk_i2s0_8ch_tx_out remains strictly locked at N (Disabled) and is flagged as deviceless.

Pin Controller State (/sys/kernel/debug/pinctrl/.../pinmux-pins)
Even during active ALSA playback, the pinmux controller completely refuses to route the active internal clocks out to the physical balls of the SoC:

 

pin 68 (gpio2-4): ff300000.i2s (GPIO UNCLAIMED) function i2s_8ch_0 group i2s-8ch-0-mclk

pin 69 (gpio2-5): ff300000.i2s (GPIO UNCLAIMED) function i2s_8ch_0 group i2s-8ch-0-sclktx

 

 

The alternative functions are assigned correctly (function i2s_8ch_0), but the driver leaves them flagged as GPIO UNCLAIMED.

Extensive Troubleshooting & Root Cause Analysis

We have thoroughly tested the limits of the Device Tree and Runtime modifications:

DTS Bindings Failed: Injecting properties like simple-audio-card,continuous-clock, frame-master, bitclock-master, or explicitly binding the clock output to the codec node via clocks = <&i2s0_8ch 0>; has absolutely zero effect. The primitive spdif_dit.c driver has no .probe or .set_sysclk routines to request the clock.

Driver Patching (Trigger Routine): We patched the driver's rockchip_i2s_tdm_trigger routine to forcefully call clk_prepare_enable(i2s_tdm->mclk_tx). The reference counter successfully increments to 4, but the CCF/Power Management layer suppresses the physical output because no hardware handshake is returned from the passive transmitter.

Direct Register Override Hack: We deployed a custom runtime kernel module executing a direct iowrite32(0x40000000, cru_reg) onto the CRU hardware register CLKGATE_CON5 (0xff500314). While dmesg confirms the hardware register write is successful and the physical gate opens on the silicon level, the pinctrl layer still isolates the pads in an UNCLAIMED state.

 

3. Pin Configuration State (`/sys/kernel/debug/pinctrl/.../pinconf-pins`)

A live register dump of the pad configurations confirms that the m0-muxing is successfully applied on the silicon layer, and electrical drive stages are actively provisioned:

pin 68 (gpio2-4): input bias disabled, output drive strength (2 mA), input schmitt enabled, slew rate (0x0), mux (0x1)

pin 69 (gpio2-5): input bias disabled, output drive strength (2 mA), input schmitt enabled, slew rate (0x0), mux (0x1)

 

This proves the issue is purely a logical lock within the ASoC / Pinctrl driver handshake, as the physical multiplexer is correctly set to mux (0x1) for I2S0 m0.

 

The Question to the Maintainers

In the old legacy vendor BSP kernels (Linux 4.4/5.10), the Rockchip driver forced the pin configurations blindly into output mode.

In Mainline 6.18, the dynamic handshake locks passive audio configurations out completely.

What is the officially intended mainline approach to bypass this dynamic power-saving guardrail for headless/passive setups?

How can we force rockchip-i2s-tdm to permanently transition the pinctrl states to claimed and enable clk_i2s0_8ch_tx_out without a physical I2C/SPI control loop?

 

This is a very well researched and thorough bug report.  Thank you.

Unfortunately, I don't have access to the hardware needed to verify it.

 

I am the maintainer of this particular board.

 

Do you believe this is a board specific problem, or one that is common to all Armbian Rockchip boards?

 

Do you feel it is related to power-saving logic?

 

(Have you tried replicating this problem on another Rockchip board?)

 

To your last questions:

I don't know the officially intended mainline policy.

 

Could you explain what you mean by "physical I2C/SPI control loop?"

Could you point me to an example of such?

 

  • Author

Hi brentr,

 

Thank you for your fast response! To answer your questions based on my tests with this specific board:

 

  • Board-specific vs. common Armbian Rockchip issue:

This is very likely an issue common to all modern Mainline Rockchip audio drivers (specifically rockchip-i2s-tdm) when handling a passive/headless configuration. The driver's power-saving/runtime PM logic expects an active digital handshake from a smart codec (usually via I2C/SPI control loops) to fully claim the pins and keep the clocks alive.

 

  • Power-saving logic:

Yes, it is deeply related to the modern Kernel's runtime power management and clock gating. Without an active external codec answering to control commands, the ASoC framework doesn't receive the "active" trigger state back from the passive hardware side, causing the CCF layer to keep clk_i2s0_8ch_tx_out at N (gated) and leaving the pinctrl states at UNCLAIMED even though ALSA reports active playback.

 

  • What I mean by "physical I2C/SPI control loop":

In a standard layout, a smart DAC/Codec (like a Wolfson/Cirrus WM8804 or similar configured as an I2C slave) is actively queried by the kernel during driver initializing. If the kernel probes the device via I2C and it responds, the sound card enters a fully established state, which automatically triggers the pinctrl driver to transition from UNCLAIMED to claimed and signals the CCF to un-gate the MCLK output.

 

In my headless/passive setup, the DAC inputs are purely wire-bound (listening to MCLK/BCLK/Data passively).

There is no microcontroller or I2C bus connected to talk back to the Rock Pi S.

 

My main obstacle right now:
Since the device tree parser completes successfully and ALSA creates the card device (card 1: rockchip,rk3308-toslink), the parsing stage is fully intact.

Is there an official device-tree property or driver flag within the mainline rockchip-i2s-tdm implementation to force a "dummy-handshake" or configure the controller into an un-gated, always-on clock master state for headless designs?

Edited by g.coach

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.