Activate soundcard with ALSA UCM

Hi,

I built my own image based on torizon-minimal with Yocto.
On our carrier board we have an TLV320AIC3100 as sound card and I want to activate it with ALSA UCM since it is the recommended way since BSP6.7.

The kernel module is loaded correctly

$ lsmod | grep snd
snd_soc_fsl_sai        40960  2
snd_soc_tlv320aic31xx    61440  1

and the sound card is present on the system:

$cat /proc/asound/cards
 0 [tlv320aic3100  ]: simple-card - tlv320aic3100
                      tlv320aic3100
$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=tlv320aic3100
    tlv320aic3100, 30020000.sai-tlv320aic31xx-hifi tlv320aic31xx-hifi-0
    Default Audio Device
sysdefault:CARD=tlv320aic3100
    tlv320aic3100, 30020000.sai-tlv320aic31xx-hifi tlv320aic31xx-hifi-0
    Default Audio Device

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: tlv320aic3100 [tlv320aic3100], device 0: 30020000.sai-tlv320aic31xx-hifi tlv320aic31xx-hifi-0 [30020000.sai-tlv320aic31xx-hifi tlv320aic31xx-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

I looked at the example implementation in meta-toradex-bsp-common for the WM8904 and NAU8822 and added the following files to the system:

$ cat /usr/share/alsa/ucm2/cbt3/tlv320aic3100/tlv320aic3100.conf
Syntax 4

SectionUseCase."HiFi" {
        File "/cbt3/tlv320aic3100/tlv320aic3100-HiFi.conf"
        Comment "Default"
}
$ cat /usr/share/alsa/ucm2/cbt3/tlv320aic3100/tlv320aic3100-HiFi.conf
SectionDevice."Speaker" {
        Comment "Speaker"

       BootSequence [
               cset "name='Speaker Analog Playback Volume' 95"
       ]

        EnableSequence [
                cset "name='Speaker Switch' on"
        ]

        DisableSequence [
                cset "name='Speaker Switch' off"
        ]
}
$ ls -l /usr/share/alsa/ucm2/conf.d/simple-card/
total 0
lrwxrwxrwx 2 root root 51 Sep  5  2025 'Librem 5 Devkit.conf' -> '../../NXP/iMX8/Librem_5_Devkit/Librem 5 Devkit.conf'
lrwxrwxrwx 2 root root 43 Sep  5  2025  tlv320aic3100.conf -> ../../cbt3/tlv320aic3100/tlv320aic3100.conf
lrwxrwxrwx 2 root root 41 Sep  5  2025  verdin-nau8822.conf -> ../../Toradex/nau8822/verdin-nau8822.conf
lrwxrwxrwx 2 root root 39 Sep  5  2025  verdin-wm8904.conf -> ../../Toradex/wm8904/verdin-wm8904.conf

The main config is registered correctly:

$ alsaucm -c tlv320aic3100 list _verbs
  0: HiFi
    Default

But there are no devices available:

$ alsaucm -c tlv320aic3100 list _devices
alsaucm: error failed to get list _devices: No such file or directory

And activating the speaker fails:

$ alsaucm -c tlv320aic3100 set _verb HiFi
$ alsaucm -c tlv320aic3100 set _dev Speaker
alsaucm: error failed to set _dev=Speaker: Invalid argument

What am I doing wrong?

Best regards,
Markus

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


ALSA UCM Configuration Issue with TLV320AIC3100

Based on your configuration, I can see several potential issues with your ALSA UCM setup for the TLV320AIC3100 codec.

Understanding Toradex Audio Support

The Toradex BSP uses the regular Linux audio subsystem Advanced Linux Sound Architecture (ALSA) (1). The ALSA subsystem can be configured using amixer or alsamixer whereas playing and recording is possible using the ALSA utilities aplay and arecord (1).

Potential Issues with Your UCM Configuration

1. Missing SectionDevice Declaration in Main Config

Your main configuration file tlv320aic3100.conf only references the HiFi use case but doesn’t declare the available devices. The UCM system needs to know about the Speaker device at the top level.

2. Control Name Verification

The control names in your UCM configuration need to match exactly what the codec driver provides. You can verify the available controls with:

amixer -c 0 controls

3. Missing PlaybackPCM/CapturePCM Definitions

Your UCM configuration is missing the PCM device definitions that tell ALSA which hardware device to use for playback.

Recommended Approach

Since you’re working with a custom Yocto build based on torizon-minimal (2), I recommend:

  1. Verify Control Names: Use amixer to list all available controls for your TLV320AIC3100 and ensure your UCM configuration uses the exact control names.

  2. Test Basic Audio First: Before implementing UCM, verify that basic audio works using the standard ALSA approach shown in the Toradex documentation (1):

# List available audio devices
cat /proc/asound/cards

# Test audio playback
aplay -D sysdefault:CARD=tlv320aic3100 your_audio_file.wav
  1. Reference Working Examples: Study the working UCM implementations in meta-toradex-bsp-common more closely, particularly focusing on how they define PCM devices and device declarations.

Next Steps

  1. Verify your codec driver is exposing the correct ALSA controls
  2. Test basic audio functionality without UCM first
  3. Add proper PCM device definitions to your UCM configuration
  4. Ensure all control names match exactly what the driver provides

The fact that your kernel module loads correctly and the sound card appears in /proc/asound/cards indicates the hardware integration is working - the issue is likely in the UCM configuration syntax or control name mismatches.

Best regards,
Toradex AI Assistant.

Hello @Mowlwurf,

Comparing with a few examples, maybe the following tlv320aic3100-HiFi.conf could work:

Syntax 4

SectionVerb {
    EnableSequence [ ]
    DisableSequence [ ]
}

SectionDevice."Speaker" {
    Comment "Speaker"

    BootSequence [
        cset "name='Speaker Analog Playback Volume' 95"
    ]
    EnableSequence [
        cset "name='Speaker Switch' on"
    ]
    DisableSequence [
        cset "name='Speaker Switch' off"
    ]
    Value {
        PlaybackPriority 200
        PlaybackPCM "hw:${CardId}"   # == hw:tlv320aic3100,0
        PlaybackChannels 2
    }
}

The following ucm commands should set it up correctly for testing:

alsaucm open tlv320aic3100
alsaucm reset
alsaucm set _verb HiFi
alsaucm list _devices
alsaucm set _enadev Speaker

Please let me know if this works.

Best Regards,
Bruno

Hello @bruno.tx,

thank you for your fast respone.
I changed the HiFi.conf as you proposed. But it don’t work either:

$ alsaucm open tlv320aic3100
$ alsaucm reset
$ alsaucm list _verbs
  0: HiFi
    Default
$ alsaucm set _verb HiFi
$ alsaucm list _devices
alsaucm: error failed to get list _devices: No such file or directory
$ alsaucm set _enadev Speaker
alsaucm: error failed to set _enadev=Speaker: No such file or directory

The control names seems to be correct:

$ amixer -c 0 sget 'Speaker'
Simple mixer control 'Speaker',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [off]

$ amixer -c 0 sget 'Speaker Analog'
Simple mixer control 'Speaker Analog',0
  Capabilities: pvolume pvolume-joined
  Playback channels: Mono
  Limits: Playback 0 - 127
  Mono: Playback 0 [0%] [-63.50dB]

Even when I comment out the cset lines in the HiFi.conf I get the error message that there is no device.

Best regards,
Markus

Hello @Mowlwurf,

Noted, I will check internally if someone has some more insights into this.

Best Regards,
Bruno

I made some progress. Enabling the verb HiFi seems to work, but when I try to read the set verb I get an error:

$ alsaucm -c hw:0 list _verbs
  0: HiFi
    Default
$ alsaucm -c hw:0 set _verb HiFi
$ alsaucm -c hw:0 get _verb
alsaucm: error failed to get _verb: No such file or directory

But when I call these commands in interactive mode it works:

$ alsaucm -i -c hw:0
alsaucm: Interacive mode - 'q' to quit
alsaucm>> list _verbs
  0: HiFi
    Default
alsaucm>> set _verb HiFi
alsaucm>> get _verb
  _verb=HiFi
alsaucm>> list _devices
  0: Speaker
    Speaker
alsaucm>> set _enadev Speaker
alsaucm>> q

Now the speaker is enabled:

amixer -c 0 sget 'Speaker'
Simple mixer control 'Speaker',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]

but the volume level is still 0:

$ amixer -c 0 sget 'Speaker Analog'
Simple mixer control 'Speaker Analog',0
  Capabilities: pvolume pvolume-joined
  Playback channels: Mono
  Limits: Playback 0 - 127
  Mono: Playback 0 [0%] [-63.50dB]

It seems that the BootSequence from the config file is not executed. When I set the volume by hand it works:

$ amixer cset name='Speaker Analog Playback Volume' 95
numid=7,iface=MIXER,name='Speaker Analog Playback Volume'
  ; type=INTEGER,access=rw---R--,values=1,min=0,max=127,step=0
  : values=95
  | dBscale-min=-63.50dB,step=0.50dB,mute=0

$ amixer -c 0 sget 'Speaker Analog'
Simple mixer control 'Speaker Analog',0
  Capabilities: pvolume pvolume-joined
  Playback channels: Mono
  Limits: Playback 0 - 127
  Mono: Playback 95 [75%] [-16.00dB]

Best regards,
Markus

Dear @Mowlwurf,

Apologies for not getting back to you sooner. We have experienced a high amount of requests as of late. I wanted to ask you what the current standing regarding this issue is. Did you manage to solve it in the meantime?
If not, could you tell me what remaining hurdles you are facing?

Best regards,
Collin

Hello @collin.tx,

thank you for checking back.

I was able to activate my soundcard with the following command that is executed every boot: printf 'open tlv320aic3100\nset _verb HiFi\nset _enadev Speaker\n' | alsaucm -n -b -

My /usr/share/alsa/ucm2/cbt3/tlv320aic3100/tlv320aic3100.conf is as follows:

Syntax 4

SectionUseCase."HiFi" {
        File "/cbt3/tlv320aic3100/tlv320aic3100-HiFi.conf"
        Comment "Default"
}

and the tlv320aic3100-HiFi.conf:

Syntax 4

SectionVerb {
	BootSequence [ ]
    EnableSequence [ ]
    DisableSequence [ ]
	
    Value {
        PlaybackPriority 200
        PlaybackPCM "hw:${CardId}"
        PlaybackChannels 2
    }
}

SectionDevice."Speaker" {
	Comment "Speaker"

	BootSequence [ ]

	EnableSequence [
		cset "name='Speaker Switch' on"

		# TODO these commands should actually be in the BootSequence
		# but since this is not executed, the default values are set every time the device starts
		cset "name='Speaker Analog Playback Volume' 95"
		cset "name='Speaker Driver Playback Switch' on"
		cset "name='Speaker Driver Playback Volume' 1"
		# Since kernel version 5.15.183 this command no longer works, because the check of the passed parameter
		# in sound/soc/soc-ops.c has changed. For the TLV320AIC3100, this results in a return value of "invalid argument"
		# As the level is already set to the desired value by default, the command can be omitted.
		#cset "name='DAC Playback Volume' 127,127"
		cset "name='DAC Left Input' 'Left Data'"
		cset "name='DAC Right Input' 'Right Data'"
		cset "name='HP Analog Playback Volume' 0,0"
		cset "name='HP Driver Playback Switch' off,off"
		cset "name='HP Driver Playback Volume' 0,0"
		cset "name='HP Left Switch' off"
		cset "name='HP Output Driver Power-On time' '304ms'"
		cset "name='HP Output Driver Ramp-up step' '3.9ms'"
		cset "name='HP Right Switch' off"
		cset "name='MIC1LM M-Terminal' Off"
		cset "name='MIC1LM P-Terminal' Off"
		cset "name='MIC1LP P-Terminal' Off"
		cset "name='MIC1RP P-Terminal' Off"
		cset "name='Output Left From Left DAC' on"
		cset "name='Output Left From MIC1LP' off"
		cset "name='Output Left From MIC1RP' off"
		cset "name='Output Right From MIC1RP' off"
		cset "name='Output Right From Right DAC' on"
		cset "name='Volume Soft Stepping' fast"
		
		cset "name='ADC Fine Capture Volume' 4"
		cset "name='ADC Capture Switch' off"
		cset "name='ADC Capture Volume' 24"
		cset "name='Mic PGA Capture Volume' 0"
	]

	DisableSequence [
		cset "name='Speaker Switch' off"
	]
}

I had to made two workarounds to get it working.

First: the BootSequence isn’t executed at all. Therefore I have to add the commands for the default settings of the sound card to the EnableSequence. This has the disadvantage that the user settings aren’t stored between two bootups. It would be great if you have an solution for this.

The second problem was, that the command cset "name='DAC Playback Volume' 127,127stops working with kernel version 5.15.183. It results in an ìnvalid argument error because a more strict verification was added to sound/soc/soc-ops.c. I think the driver for the tlv320aic3100 is not programmed quite correctly at this point. But since the DAC playback volume is already set to the wanted value by default, this is no critical problem.

Best regards,

Markus

Dear @Mowlwurf,

I believe there might be an issue in the setup. You mentioned that the bootSequence is not executed at all, yet it should always be executed during booting. You will likely have to make sure the paths are correct and the proper driver is being called.

Best regards,
Collin

Dear @Mowlwurf,

Were you able to solve the issue you were facing or is there anything else we could help you with?

Best regards,
Collin