Adding MAX98357A I2S DAC to a custom carrier board

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,

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

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,

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


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,


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,

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,


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

Hello @rikte ,

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

Best regards,

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,


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??


I’ll try and add a bit more detail:

  1. You can clone the git repo via:
    git clone 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.

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?


Hello @rikte ,
About this error:

It could be that the module is built for another kernel version, as in this case:

Best regards,

Hello @rikte ,
Do you have any updates on this topic?

Best regards,

Hi @josep.tx

I verified that I have the exact same kernel, modules and such. So I am not sure if that is the issue.
I used the steps I mentioned in my previous post to build the kernel with driver.
if someone on your side would be able to validate or check if they can reproduce it, that would be very appreciated.

Hi @rikte ,
Since BSP6, we have provided downstream and upstream kernels for Verdin IMX8MP. You have to check BSP installed on your Verdin iMX8MP and the Linux source code you downloaded.

Hi @benjamin.tx
This is all based on the downstream BSP 6.1, so using the toradex_5.15-2.1.x-imx branch.