Electronic – Multiple audio codecs on an i.MX6Q

audioembeddedfreescale

We are currently trying to bring up a custom i.MX6Q based board with Linux 3.10.17, two TI TLV320AIC3106 codecs and an S/PDIF interface.

The two codecs are I2S slaves and are connected to the i.MX6 via

codec1 <-> AUDMUX3 <-> SSI1

and

codec2 <-> AUDMUX4 <-> SSI2

I have written an ASoC machine driver for the codecs and so far everything looks fine from an ALSA point of view:

aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: imxspdif [imx-spdif], device 0: S/PDIF PCM Playback dit-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: CODEC1 [CODEC1], device 0: HiFi tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: CODEC2 [CODEC2], device 0: HiFi tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: imxspdif [imx-spdif], device 1: S/PDIF PCM Capture dir-hifi-1 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: CODEC1 [CODEC1], device 0: HiFi tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: CODEC2 [CODEC2], device 0: HiFi tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

My problem now is, that I can only interact with of the codec audio devices (card 2 in the example above). Trying to playback to/capture from card 1 will result in:

aplay -D "plughw:1,0" /home/1000_loud.wav
ALSA sound/core/pcm_lib.c:1944 playback write error (DMA or IRQ trouble?)
aplay: pcm_write:1603: write error: Input/output error

I took notice that I don't have any activity on the I2S lines for card 1 (no clock or data).
However both of the devices do work if I disable the other device in the DT. So I think I must be blocking something somewhere, but I have no idea where/why/how.

I can talk to the codecs via I2C so at least the I2C bus doesn't seem to be the problem.

Here is (the relevant part of) my DT:

/ {

    clocks {
        osc {
            compatible = "fsl,imx-osc", "fixed-clock";
            clock-frequency = <25000000>;
        };
    };

    regulators {
        compatible = "simple-bus";

        reg_audio: tlv320aic3x_supply {
            compatible = "regulator-fixed";
            regulator-name = "tlv320aic3x-supply";
            regulator-boot-on;
            regulator-always-on;
        };
    };

    sound1 {
        compatible = "fsl,imx-audio-tlv320aic3x";
        model = "CODEC1";
        ssi-controller = <&ssi1>;
        audio-codec = <&codec1>;
        audio-routing =
            "Microphone 1",      "LINE1L",
            "Microphone 1",      "LINE1R",
            "Microphone 2",      "LINE2L",
            "Microphone 2",      "LINE2R",
            "Piezo Loudspeaker", "LLOUT";
        mux-int-port = <1>;
        mux-ext-port = <3>;
    };

    sound2 {
        compatible = "fsl,imx-audio-tlv320aic3x";
        model = "CODEC2";
        ssi-controller = <&ssi2>;
        audio-codec = <&codec2>;
        audio-routing =
            "Microphone 1", "LINE1L",
            "Microphone 1", "LINE1R",
            "Microphone 2", "LINE2L",
            "Microphone 2", "LINE2R",
            "Loudspeaker",  "LLOUT",
            "Loudspeaker",  "RLOUT";
        mux-int-port = <2>;
        mux-ext-port = <4>;
    };

    sound-spdif {
        compatible = "fsl,imx-audio-spdif";
        model = "imx-spdif";
        spdif-controller = <&spdif>;
        spdif-in;
        spdif-out;
    };
};

&audmux {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_audmux_4>;
    status = "okay";
};

&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1_2>;
    status = "okay";

    codec1: tlv320aic3x@01b {
        compatible = "ti,tlv320aic3x";
        reg = <0x01b>;
        gpio-reset = <&gpio5 18 GPIO_ACTIVE_LOW>;
        status = "okay";

        clocks = <&clks 201>;
        clock-names = "cko";
        clock-frequency = <25000000>;

        AVDD-supply = <&reg_audio>;
        IOVDD-supply = <&reg_audio>;
        DRVDD-supply = <&reg_audio>;
        DVDD-supply = <&reg_audio>;
        HPVDD-supply = <&reg_audio>;
        SPRVDD-supply = <&reg_audio>;
        SPLVDD-supply = <&reg_audio>;
    };

    codec2: tlv320aic3x@018 {
        compatible = "ti,tlv320aic3x";
        reg = <0x018>;
        gpio-reset = <&gpio5 18 GPIO_ACTIVE_LOW>;
        status = "okay";

        clocks = <&clks 201>;
        clock-names = "cko";
        clock-frequency = <25000000>;

        AVDD-supply = <&reg_audio>;
        IOVDD-supply = <&reg_audio>;
        DRVDD-supply = <&reg_audio>;
        DVDD-supply = <&reg_audio>;
        HPVDD-supply = <&reg_audio>;
        SPRVDD-supply = <&reg_audio>;
        SPLVDD-supply = <&reg_audio>;
    };
};

&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_audmux_4>;

    audmux {
        pinctrl_audmux_4: audmux-4 {
            fsl,pins = <
                MX6QDL_PAD_SD2_DAT0__AUD4_RXD  0x130b0
                MX6QDL_PAD_SD2_DAT3__AUD4_TXC  0x130b0
                MX6QDL_PAD_SD2_DAT2__AUD4_TXD  0x110b0
                MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0
                MX6QDL_PAD_CSI0_DAT7__AUD3_RXD  0x130b0
                MX6QDL_PAD_CSI0_DAT4__AUD3_TXC  0x130b0
                MX6QDL_PAD_CSI0_DAT5__AUD3_TXD  0x110b0
                MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
            >;
        };
    };

    spdif {
        pinctrl_spdif_3: spdifgrp-3 {
            fsl,pins = <
                MX6QDL_PAD_EIM_D21__SPDIF_IN  0x1b0b0
                MX6QDL_PAD_EIM_D22__SPDIF_OUT 0x1b0b0
            >;
        };
    };
};

&ssi1 {
    fsl,mode = "i2s-master";
    status = "okay";
};

&ssi2 {
    fsl,mode = "i2s-master";
    status = "okay";
};

&spdif {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_spdif_3>;
    status = "okay";
};

Does anyone have an idea what I might be missing or doing wrong?

Thanks a lot for any help in advance!

Best Answer

I was able to solve it.

It was a two part problem:

a) The machine driver I used as template for my own didn't handle being loaded multiple times very well. I rewrote it, which resolved the blocking issue.

However after that, I still couldn't play back audio from both codecs. As soon as I started interacting with the second codec, playback from the first one would stop. This was caused by

b) By hardware design both codecs on our board share the same reset GPIO. The codec driver performed a hardware reset on every playback/capture start event resetting the other codec