Page 1 of 1

Getting the maxim98089 to work with Raspberry Pi

Posted: Wed Mar 28, 2018 3:15 pm
by gadgetoid
I'm attempting to get the Maxim max98089 up and running. I'm using the TQFN evaluation kit, and have successfully got it to produce sound using the `hifiberry-dac` dtoverlay, combined with some manual control of the DAC itself over i2c to configure the audio pipeline.

I am now attempting to get it to work with the proper max98089 driver/codec which I have obtained from here: ... max98088.c

I've built this against the running kernel (stock Raspbian 4.9.80) by pulling the source into a DKMS package.

I can get the module to load ( it shows in lsmod and the "i2cdetect -y 1" shows the i2c address as reserved "UU" ) but I can't seem to make it appear as a functioning audio output within ALSA.

My device-tree overlay currently looks like this:

Code: Select all


/ {

        compatible = "brcm,bcm2708";

        fragment@0 {
                target = <&i2s>;
                __overlay__ {
                        status = "okay";

        fragment@1 {
                target = <&i2c1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        max98089@10 {
                                #sound-dai-cells = <0>;
                                compatible = "maxim,max98089", "maxim,max98088";
                                reg = <0x10>;
                                status = "okay";

        fragment@2 {
                target =  <&sound>;
                productname: __overlay__ {
                        compatible = "manufacturer,product-name";
                        i2c-controller = <&i2c>;
                        status = "okay";

Most of this I kind-of understand, save for "fragment@2" which contains names in the "compatible" property that don't appear to relate to anything else in the overlay, or on the system? For example "allo-piano-dac" uses:

Code: Select all

	fragment@2 {
		target = <&sound>;
		piano_dac: __overlay__ {
			compatible = "allo,piano-dac";
			i2s-controller = <&i2s>;
			status = "okay";
But where does the "allo" and "piano-dac" come from? Is this just the device name exposed to ALSA?

So, to summarise:
  • I've got as far as a loading module, but how can I make this function as an audio output(/input) device?
  • What's the purpose/meaning/source of the names used in "fragment@2"?
In fact, after a little bit of searching it's clear the names in question 2 relate to the "device driver"? IE, this file here: ... iano-dac.c

So presumably that's the missing piece of the puzzle?

Re: Getting the maxim98089 to work with Raspberry Pi

Posted: Wed Mar 28, 2018 4:02 pm
by gadgetoid
Caught my stupid typo in the dts source and corrected:

Code: Select all

i2c-controller = <&i2c>;

Code: Select all

i2s-controller = <&i2s>;
I used "sudo cat /sys/kernel/debug/asoc/codecs" to get the correct name for the max98089 codec (it doesn't seem to have a friendly-name like some of these DACs do) and hacked up the hifiberry-dac driver to bring it online:

Code: Select all

 * ASoC Driver for HifiBerry DAC
 * Author:      Florian Meier <>
 *              Copyright 2013
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * General Public License for more details.

#include <linux/module.h>
#include <linux/platform_device.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>

static int snd_rpi_test_dac_init(struct snd_soc_pcm_runtime *rtd)
        return 0;

static int snd_rpi_test_dac_hw_params(struct snd_pcm_substream *substream,
                                       struct snd_pcm_hw_params *params)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

        unsigned int sample_bits =

        return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);

/* machine stream operations */
static struct snd_soc_ops snd_rpi_test_dac_ops = {
        .hw_params = snd_rpi_test_dac_hw_params,

static struct snd_soc_dai_link snd_rpi_test_dac_dai[] = {
        .name           = "Test DAC",
        .stream_name    = "Test DAC HiFi",
        .cpu_dai_name   = "bcm2708-i2s.0",
        .codec_dai_name = "HiFi",
        .platform_name  = "bcm2708-i2s.0",
        .codec_name     = "max98088.1-0010",
        .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
        .ops            = &snd_rpi_test_dac_ops,
        .init           = snd_rpi_test_dac_init,

/* audio machine driver */
static struct snd_soc_card snd_rpi_test_dac = {
        .name         = "snd_rpi_test_dac",
        .driver_name  = "TestDac",
        .owner        = THIS_MODULE,
        .dai_link     = snd_rpi_test_dac_dai,
        .num_links    = ARRAY_SIZE(snd_rpi_test_dac_dai),

static int snd_rpi_test_dac_probe(struct platform_device *pdev)
        int ret = 0; = &pdev->dev;

        if (pdev->dev.of_node) {
            struct device_node *i2s_node;
            struct snd_soc_dai_link *dai = &snd_rpi_test_dac_dai[0];
            i2s_node = of_parse_phandle(pdev->dev.of_node,
                                        "i2s-controller", 0);

            if (i2s_node) {
                dai->cpu_dai_name = NULL;
                dai->cpu_of_node = i2s_node;
                dai->platform_name = NULL;
                dai->platform_of_node = i2s_node;

        ret = snd_soc_register_card(&snd_rpi_test_dac);
        if (ret && ret != -EPROBE_DEFER)
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);

        return ret;

static int snd_rpi_test_dac_remove(struct platform_device *pdev)
        return snd_soc_unregister_card(&snd_rpi_test_dac);

static const struct of_device_id snd_rpi_test_dac_of_match[] = {
        { .compatible = "test,test-dac", },
MODULE_DEVICE_TABLE(of, snd_rpi_test_dac_of_match);

static struct platform_driver snd_rpi_test_dac_driver = {
        .driver = {
                .name   = "snd-test-dac",
                .owner  = THIS_MODULE,
                .of_match_table = snd_rpi_test_dac_of_match,
        .probe          = snd_rpi_test_dac_probe,
        .remove         = snd_rpi_test_dac_remove,


MODULE_AUTHOR("Florian Meier <>");
MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC");
It's ugly, but it works!

(Thank you invisible internet rubber ducks ;)

Re: Getting the maxim98089 to work with Raspberry Pi

Posted: Wed Mar 28, 2018 4:15 pm
by PhilE
Cool - I knew if I gave you enough time you'd figure it out.

Now that you've got that working, you might want to consider using the simple-card driver instead - it is a generic driver that should be capable of supporting your board, so all you need is a custom overlay (and the codec driver). There are several examples of simple-card overlays in the 4.9 and 4.14 trees:

If you change the name and substitute your codec details it should just work...

Re: Getting the maxim98089 to work with Raspberry Pi

Posted: Tue Apr 03, 2018 8:48 am
by gadgetoid
Thank you! I'll have another sprint on this soon and see where I get. My current solution did not survive removal of power, which means it's not setting up the device properly and the registers were preserved from my previous attempts to set them up manually. I see snippets in your linked examples that allude to the fix, though, so with any luck I'll get the codec to configure the board correctly on boot.