Adding MAX98357A I2S DAC to a custom carrier board

Hi,

On a custom carrier board using a Verdin IMX8MP SoM we added a MAX98357a I2S audio DAC/AMP to be able to connect a small speaker to the board.
So far I ran into some issues trying to get data out on the I2S bus.

The card seems to be recognizes in Linux, based on the dmesg output:

[ 1.816719] debugfs: Directory ‘30c10000.sai’ with parent ‘max98357a’ already present!
[ 1.824786] asoc-simple-card sound-card: HiFi <-> 30c10000.sai mapping ok
[ 1.831624] asoc-simple-card sound-card: ASoC: no DMI vendor name!

and in alsamixed I see the sound card, which has no controls as expected.
But if I try to play audio or run speaker-test I get the following message:

speaker-test 1.2.1

Playback device is default
Stream paramet[ 298.905978] fsl-sai 30c10000.sai: ASoC: can’t open component 30c10000.sai: -6
ers are 48000Hz, S16_LE, 1 channels
Using 16 octaves of pink noise
ALSA lib …/…/…/alsa-lib-1.2.1.2/src/pcm/pcm_dmix.c:1089:(snd_pcm_dmix_open) unable to open slave
Playback open error: -6,No such device or address

Could you give us some pointers on what this could be?

We are using Yocto, BSP 5.7.2 and I changed the following for the sound card:

I added the codec driver in Linux

│ Symbol: SND_SOC_MAX98357A [=y]                                                                                                      
  │ Type  : tristate                                                                                                                    
  │ Prompt: Maxim MAX98357A CODEC                                                                                                       
  │   Location:                                                                                                                         
  │     -> Device Drivers                                                                                                               
  │       -> Sound card support (SOUND [=y])                                                                                            
  │         -> Advanced Linux Sound Architecture (SND [=y])                                                                             
  │           -> ALSA for SoC audio support (SND_SOC [=y])                                                                              
  │ (6)         -> CODEC drivers     
  

And I added it to the device tree as follows:

	codec_ext: max98357a@0 {
		compatible = "maxim,max98357a";
		#sound-dai-cells = <0>;
		clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1>;
		clock-names = "mclk";
	};

	sound_card: sound-card {
		compatible = "simple-audio-card";
		simple-audio-card,bitclock-master = <&dailink_master>;
		simple-audio-card,format = "i2s";
		simple-audio-card,frame-master = <&dailink_master>;
		simple-audio-card,name = "max98357a";

		dailink_master: simple-audio-card,codec {
			sound-dai = <&codec_ext>;
			clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1>;
		};

		simple-audio-card,cpu {
			sound-dai = <&sai1>;
		};
	};

I also changed the asound.conf to the following:

pcm.speakerbonnet {
   type hw card 0
}

pcm.dmixer {
   type dmix
   ipc_key 1024
   ipc_perm 0666
   slave {
     pcm "speakerbonnet"
     period_time 0
     period_size 1024
     buffer_size 8192
     rate 44100
     channels 2
   }
}

ctl.dmixer {
    type hw card 0
}

pcm.softvol {
    type softvol
    slave.pcm "dmixer"
    control.name "PCM"
    control.card 0
}

ctl.softvol {
    type hw card 0
}

pcm.!default {
    type             plug
    slave.pcm       "softvol"
}

Best regards,

Rik

Hello @rikte

Maybe the post by eoin_oc1 in this post can help you :

Best regards,
Josep

Hi @rikte ,

Happy New Year :tada:

Were you able to solve this?

Best Regards
Kevin

Hi Kevin,

Due to the holidays I haven’t spend too much time on it, but I tried a few things:

I tried a device tree like in the post linked by Josep, or based on the following:
https://community.toradex.com/t/max98357a-on-imx7s-with-simple-audio-card/
Which for me looks like this:

	codec_ext: max98357a@0 {
		compatible = "maxim,max98357a";
		#sound-dai-cells = <0>;
	};

	sound {
		compatible = "simple-audio-card";
		simple-audio-card,name = "max98357a";
		simple-audio-card,format = "i2s";
		simple-audio-card,bitclock-master = <&dailink_master_cpu>;
		simple-audio-card,frame-master = <&dailink_master_cpu>;


		simple-audio-card,codec {
			sound-dai = <&codec_ext>;
		};


		dailink_master_cpu: simple-audio-card,cpu {
			sound-dai = <&sai1>;
		};

	};

But sadly with the same results.

Hello @rikte ,
In our blog section we have an article about MAX98357A and iMX6ULL. Unfortunately is only in Chinese, but I have asked internally to publish an English version too

Best regards,
Josep

Hi Joseph,

The blog was helpful, especially the last part concerning the clocks.
If I understand it correctly, and the translation via google is correct. The clock for sai is off, and the devmem2 command it used to turn it on.

Of course the CCM peripheral for the imx6ull and the imx8mp is very different, and there is no CCM Clock Output Source Register (CCM_CCOSR) register or such on the imx8mp.
Is the devmem2 command indeed to turn the clock on, and how would I do that for the imx8mp?

Hello @rikte ,
I passed your question internally to the author of the article. Meanwhile we ordered a MAX98357A to do some tests ourselves. We will keep you updated.

Best regards,
Josep

Hi @rikte , I used to bring up MAX98357A on Colibri iMX6ULL and on Verdin iMX8MP, I did the same again. Here is what I do.
First, max98357a driver needed to be added to Linux kernel.

~# zcat /proc/config.gz |grep MAX98357
CONFIG_SND_SOC_MAX98357A=m

Then in the device tree, the codec on our carrier board is disabled, add MAX98357A node and enable SAI3.
imx8mp-verdin-dahlia.dtsi (4.2 KB)

Finally, deploy the kernel module and device tree binary to the board. The kernel(Image.gz) itself may also need to be compiled.

With a reboot, MAX98357A connected to SAI3(SODIMM42, 44, 46) is listed in system and it is able to play an audio file.

~# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: max98357a [max98357a], device 0: 30c30000.sai-HiFi HiFi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

~# aplay -D sysdefault:CARD=max98357a LRMonoPhase4.wav -vv
Playing WAVE 'LRMonoPhase4.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Plug PCM: Hardware PCM card 0 'max98357a' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 16384
  period_size  : 4096
  period_time  : 85333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 4096
  period_event : 0
  start_threshold  : 16384
  stop_threshold   : 16384
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0
###############   +                                | 35%

Tips: MAX98357A is not 1.8V compatible. The level shift is required, e.g. X40/X39 on Verdin Development Board.

Hello @rikte ,
Did the answer from @benjamin.tx solve your issue? If so, could you mark his answer as solution?

Best regards,
Josep

Hi @josep.tx

I have not had time to try it, I will do so later this week and report back to you.

I had some time to gave it a try.

I checked out the kernel ( toradex_5.4-2.3.x-imx ) and set

CONFIG_SND_SOC_MAX98357A=y

This so it’s in the kernel and not a loadable module.
I used the exact device tree as supplied and aplay -l gives me the same result

~# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: max98357a [max98357a], device 0: 30c30000.sai-HiFi HiFi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Sadly playing any audio gives a similar error as before.
I do not have the DAC hooked up to SAI3, but to SAI1 but as it’s a simple DAC with no feedback I think that should not be an issue and I should at least be able to play audio and see I2S data using a scope.

Could you tell me what version of the kernel and such you used, then we can try to recreate that on our side. Or perhaps for a test include the build kernel, module and dtb?

Best regards,

Rik

Hi @rikte . My kernel was also fetched from toradex_5.4-2.3.x-imx branch. It is 5.4.193. By default, SAI1 is routed to a codec NAU88C22YG on Verdin Development or WM8904CGEFL on Dahlia. The two carrier boards have their own device tree binaries where the codec is configured. The imx8mp-verdin-dahlia.dtsi provided above only uses SAI3. For SAI1, it should be modified. Which carrier board do you have now? And which device tree is applied? You can check it on the serial console during U-Boot loading.

## Executing script at 47000000
Loading DeviceTree: imx8mp-verdin-nonwifi-dev.dtb
88435 bytes read in 11 ms (7.7 MiB/s)
86 bytes read in 7 ms (11.7 KiB/s)
Applying Overlay: verdin-imx8mp_native-hdmi_overlay.dtbo
1860 bytes read in 15 ms (121.1 KiB/s)
Applying Overlay: verdin-imx8mp_lt8912_overlay.dtbo
1987 bytes read in 17 ms (113.3 KiB/s)
10643094 bytes read in 102 ms (99.5 MiB/s)

Hello @rikte ,
Were you able to solve your issue with the info provided by @benjamin.tx ?

Best regards,
Josep

Hi Josep,

Due to holidays on my side I have not been able to continue with this issue lately. I will let you know when I have.

Best regards,

Rik

Hi @rikte ,

Thanks for the update. @josep.tx is attending embedded world this week.

I will try to keep an eye on it here.

Best Regards
Kevin

Hello @rikte ,

Were you able to do some progress on this topic? Do you need more help on our side?

Best regards,
Josep

Hi @josep.tx

I had some time to look into it and have solved the issue. My steps:

  1. Flash the multimedia reference image.
  2. Checkout toradex_5.4-2.3.x-imx, add the MAX98357a driver, change the device tree to the one supplied above and compile.
  3. Swap out the Image.gz and device tree blob

After this I still got the issue that it could not open component 30c10000.sai.
It took me some debugging, but the issue is that my kernel, being checked out, changed and build, has a -dirty flag.
But the folder in /lib/modules/ with the modules was of course called 5.4.193-5.7.2+git.b60d3160fd04
So the modules just never got loaded.

After renaming that folder to match my kernel name and changing the device tree so it used SAI1, I got sound out. Next is integrating it in our own Yocto build, I will keep you posted on that.

Hello @rikte ,
Thank you very much for your feedback and the detailed explanation :slight_smile:

Best regards,
Josep

Hello,

I am doing a similar exercise of adding the MAX98357A to a custom board but cannot understand the following.

  1. Flash the multimedia reference image. - ok.
  2. Checkout toradex_5.4-2.3.x-imx- how is this done??, add the MAX98357a driver, change the device tree to the one supplied above and compile.
  3. Swap out the Image.gz and device tree blob - how is this done??

Hi,

I’ll try and add a bit more detail:

  1. You can clone the git repo via:
    git clone git://git.toradex.com/linux-toradex.git
    And after it is done, use git checkout to switch to the toradex_5.4-2.3.x-imx- branch.
    A guide on how to build and such is here: Build Linux Kernel from Source Code | Toradex Developer Center

3: I just copy the binaries to a USB stick, insert in the board and use “cp” to copy them to the /boot/ folder on the board.

@josep.tx
We recently switched to Kirkstone and BSP 6 for our boards, but with the identical approach and settings, I get a new error:

[ 6.044363] snd_soc_fsl_sai: disagrees about version of symbol devm_snd_soc_register_component
[ 6.056164] snd_soc_fsl_sai: Unknown symbol devm_snd_soc_register_component (err -22)

I can’t find much online about it. Do you have any ideas perhaps?

Rik