gadgetoid
Posts: 151
Joined: Wed Mar 07, 2012 9:58 pm

Getting the maxim98089 to work with Raspberry Pi

Wed Mar 28, 2018 3:15 pm

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: https://github.com/raspberrypi/linux/bl ... 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

/dts-v1/;
/plugin/;

/ {

        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: https://github.com/raspberrypi/linux/bl ... iano-dac.c

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

gadgetoid
Posts: 151
Joined: Wed Mar 07, 2012 9:58 pm

Re: Getting the maxim98089 to work with Raspberry Pi

Wed Mar 28, 2018 4:02 pm

Caught my stupid typo in the dts source and corrected:

Code: Select all

i2c-controller = <&i2c>;
to:

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 <florian.meier@koalo.de>
 *              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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * 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 =
                snd_pcm_format_physical_width(params_format(params));

        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 |
                                SND_SOC_DAIFMT_CBS_CFS,
        .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;

        snd_rpi_test_dac.dev = &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_platform_driver(snd_rpi_test_dac_driver);

MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC");
MODULE_LICENSE("GPL v2");
It's ugly, but it works!

(Thank you invisible internet rubber ducks ;)

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 1730
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Getting the maxim98089 to work with Raspberry Pi

Wed Mar 28, 2018 4:15 pm

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:
audu7002-simple
applepi-dac
mbed-dac
pibell
superaudioboard

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

gadgetoid
Posts: 151
Joined: Wed Mar 07, 2012 9:58 pm

Re: Getting the maxim98089 to work with Raspberry Pi

Tue Apr 03, 2018 8:48 am

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.

Return to “Device Tree”

Who is online

Users browsing this forum: No registered users and 1 guest