TLV320ADC5140: 2x tlv320adc140 + mcasp + audio-graph

Part Number: TLV320ADC5140

Tool/software:

Dear Devs

i got a board on a am437x with 2 tlv320adcx140-codec which we need to align in tdm i2s ... please see my dtb snippets below and tell me if that is supposed to work

this is basicly on a scarthgap yocto chain with 6.6 kernel

My problem is that the setup is not correctly registering.

I hacked the tlv320adcx140.c to register 2 different codecs too like this


static struct snd_soc_dai_driver adcx140_dai_driver[] = {
    {
        .name = "tlv320adcx140-codec0",
        .capture = {
            .stream_name     = "Capture",
            .channels_min     = 2,
            .channels_max     = ADCX140_MAX_CHANNELS,
            .rates         = ADCX140_RATES,
            .formats     = ADCX140_FORMATS,
        },
        .ops = &adcx140_dai_ops,
        .symmetric_rate = 1,
    },{
        .name = "tlv320adcx140-codec1",
        .capture = {
            .stream_name     = "Capture",
            .channels_min     = 2,
            .channels_max     = ADCX140_MAX_CHANNELS,
            .rates         = ADCX140_RATES,
            .formats     = ADCX140_FORMATS,
        },
        .ops = &adcx140_dai_ops,
        .symmetric_rate = 1,
    }
};


    if (i2c->addr == 0x4c) {
        dev_info(&i2c->dev, "probed c %d\n", i2c->addr);
        return devm_snd_soc_register_component(&i2c->dev,
                           &soc_codec_driver_adcx140,
                           &adcx140_dai_driver[0], 1);
    } else {
        dev_info(&i2c->dev, "probed d %d\n", i2c->addr);
        return devm_snd_soc_register_component(&i2c->dev,
                           &soc_codec_driver_adcx140,
                           &adcx140_dai_driver[1], 1);
    }

9.630738] tlv320adcx140-codec 1-004c: probed c 76
[ 9.645979] tlv320adcx140-codec 1-004d: probed d 77
[ 10.858609] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
[ 10.858761] asoc-audio-graph-card sound: Count As Normal (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint) (/ocp@44000000/interconnect@48000000/segme)
[ 10.858873] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint)
[ 10.858980] asoc-audio-graph-card sound: Count As Normal (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint) (/ocp@44000000/interconnect@48000000/segme)
[ 10.859069] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
[ 10.950494] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint)
[ 10.950714] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
[ 10.950818] asoc-audio-graph-card sound: link_of cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
[ 10.950860] asoc-audio-graph-card sound: link_of codec_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@2a000/i2c@0/tlv320adc5140@4c/port/endpoint)
[ 10.950910] asoc-audio-graph-card sound: is cpu
[ 10.951065] asoc-audio-graph-card sound: is codec
[ 11.019418] asoc-audio-graph-card sound: name is 4803c000.mcasp-tlv320adcx140-codec0
[ 11.019497] asoc-audio-graph-card sound: loop on (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint)
[ 11.019626] asoc-audio-graph-card sound: link_of cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint)
[ 11.019670] asoc-audio-graph-card sound: link_of codec_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@2a000/i2c@0/tlv320adc5140@4d/port/endpoint)
[ 11.019720] asoc-audio-graph-card sound: is cpu
[ 11.019810] asoc-audio-graph-card sound: error on graph_parse dai
[ 11.019819] asoc-audio-graph-card sound: error on cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@2/endpoint)
[ 11.019860] asoc-audio-graph-card sound: ret is neg
[ 11.019868] asoc-audio-graph-card sound: graph_for_each_link err
[ 11.019878] asoc-audio-graph-card sound: error -EINVAL: parse error
[ 11.019893] asoc-audio-graph-card: probe of sound failed with error -22

sound {
        compatible = "audio-graph-card";
        model = "Audio System";
        label = "D880TSM093";
        dais = <&mcasp1_port0>, <&mcasp1_port1>, <&codec_0_ep>, <&codec_1_ep>;
};


&i2c1 {
    tlv320adc5140_4c: tlv320adc5140@4c {
        #sound-dai-cells = <0>;
        compatible = "ti,tlv320adc5140";
        reg = <0x4c>;
        pinctrl-names = "default";
        pinctrl-0 = <&tlv320adc_pins>;
        ti,mic-bias-source = <1>;                 /* VREF x 1.096 */
        ti,vref-source = <0>;                      /* 2.75V */
        ti,pdm-edge-select = <0 1 0 1>;
        ti,gpi-config = <0 0 0 0>;
        ti,gpio-config = <0 0>;
        ti,gpo-config-1 = <0 0>;
        ti,gpo-config-2 = <0 0>;
        reset-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
        port {
            codec_0_ep: endpoint {
                remote-endpoint = <&mcasp1_ep0>;
                dai-tdm-slot-num = <8>;
                dai-tdm-slot-width = <32>;
                dai-tdm-slot-tx-mask = <1 1 1 1 0 0 0 0>;
                dai-tdm-slot-rx-mask = <1 1 1 1 0 0 0 0>;
            };
        };
    };

    tlv320adc5140_4d: tlv320adc5140@4d {
        #sound-dai-cells = <0>;
        compatible = "ti,tlv320adc5140";
        reg = <0x4d>;
        ti,mic-bias-source = <1>;                 /* VREF x 1.096 */
        ti,vref-source = <0>;                      /* 2.75V */
        ti,pdm-edge-select = <0 1 0 1>;
        ti,gpi-config = <0 0 0 0>;
        ti,gpio-config = <0 0>;
        ti,gpo-config-1 = <0 0>;
        ti,gpo-config-2 = <0 0>;
        port {
            codec_1_ep: endpoint {
                remote-endpoint = <&mcasp1_ep1>;
                dai-tdm-slot-num = <8>;
                dai-tdm-slot-width = <32>;
                dai-tdm-slot-tx-mask = <0 0 0 0 1 1 1 1>;
                dai-tdm-slot-rx-mask = <0 0 0 0 1 1 1 1>;
            };
        };
    };


&mcasp1 {
    #sound-dai-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&mcasp1_pins>;

    status = "okay";
    op-mode = <0>; /* MCASP_IIS_MODE */
    tdm-slots = <8>;
    /* 4 serializers */
    /* 0: INACTIVE, 1: TX, 2: RX */
    serial-dir = < 0 0 2 0 >;
    tx-num-evt = <1>;
    rx-num-evt = <1>;

    mcasp1_port0: port@1 {
        mcasp1_ep0: endpoint {
            remote-endpoint = <&codec_0_ep>;
            dai-tdm-slot-num = <8>;
            dai-tdm-slot-width = <32>;
            dai-tdm-slot-tx-mask = <1 1 1 1 0 0 0 0>;
            dai-tdm-slot-rx-mask = <1 1 1 1 0 0 0 0>;
            dai-format = "dsp_b";
            frame-master;
            bitclock-master;
            bitclock-inversion; // Optional flag, preserved
        };
    };

    mcasp1_port1: port@2 {
        mcasp1_ep1: endpoint {
            remote-endpoint = <&codec_1_ep>;
            dai-tdm-slot-num = <8>;
            dai-tdm-slot-width = <32>;
            dai-tdm-slot-tx-mask = <0 0 0 0 1 1 1 1>;
            dai-tdm-slot-rx-mask = <0 0 0 0 1 1 1 1>;
            dai-format = "dsp_b";
            frame-master;
            bitclock-master;
            bitclock-inversion; // Optional flag, preserved
        };
    };
};

  • Hi,

    Can you attach your error message? What do you mean by it is not correctly registering?

    Best,
    Mir

  • Sorry if i was to vague and sorry for the messages above are mostly my printk bombs i added.

    The above messages show that the first connection between the mcasp and the first codec seems to be valid.

    10.976785] asoc-audio-graph-card sound: link_of cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@0/endpoint)
    [ 10.976829] asoc-audio-graph-card sound: link_of codec_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@2a000/i2c@0/tlv320adc5140@4c/port/endpoint)
    [ 10.976878] asoc-audio-graph-card sound: is cpu
    [ 10.977031] asoc-audio-graph-card sound: is codec

    [ 10.977131] asoc-audio-graph-card sound: name is 4803c000.mcasp-tlv320adcx140-codec0

    but when parsing the 2nd part it bails out which i traced so far into

       10.977286] asoc-audio-graph-card sound: link_of cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
    [   10.977326] asoc-audio-graph-card sound: link_of codec_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@2a000/i2c@0/tlv320adc5140@4d/port/endpoint)
    [   10.977373] asoc-audio-graph-card sound: is cpu
    [   10.977453] asoc-audio-graph-card sound: error on graph_parse dai
    [   10.977461] asoc-audio-graph-card sound: error on cpu_ep (/ocp@44000000/interconnect@48000000/segment@0/target-module@3c000/mcasp@0/port@1/endpoint)
    [   11.046538] asoc-audio-graph-card sound: ret is neg
    [   11.046561] asoc-audio-graph-card sound: graph_for_each_link err
    [   11.046572] asoc-audio-graph-card sound: error -EINVAL: parse error

    sound/soc/generic/simple-card-utils.c - asoc_graph_parse_dai() where the call to ret = snd_soc_get_dlc(&args, dlc); errors out.

    I will dig into that today and report on that. Either my dtb routes are still not valid or it does fail to duplicate the alsa utils for the 2 codes ( hence missing some iteration on the codec names or such).

    Regards Rob

  • ok so i got the following setup which is only calling 1 codec referenced and it works,

    as soon as i change it to dais = <&mcasp1_port0 &mcasp1_port1>; it breaks the and cant iterate through the 2nd codec.

    so something must be wrong with iterating the endpoints or adding a 2nd cpu endpoint to mcasp

    sound {
            compatible = "audio-graph-card";
            model = "Audio System";
            label = "MYCARD";
            dais = <&mcasp1_port0>;
        };


    &i2c1 {
        tlv320adc5140_4c: tlv320adc5140@4c {
            #sound-dai-cells = <0>;
            compatible = "ti,tlv320adc5140";
            reg = <0x4c>;
            pinctrl-names = "default";
            pinctrl-0 = <&tlv320adc_pins>;
            ti,mic-bias-source = <1>;                 /* VREF x 1.096 */
            ti,vref-source = <0>;                      /* 2.75V */
            ti,pdm-edge-select = <0 1 0 1>;
            ti,gpi-config = <0 0 0 0>;
            ti,gpio-config = <0 0>;
            ti,gpo-config-1 = <0 0>;
            ti,gpo-config-2 = <0 0>;
            reset-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>;
            port {
                codec_0_ep: endpoint@0 {
                    remote-endpoint = <&mcasp1_ep0>;
                    dai-tdm-slot-num = <8>;
                    dai-tdm-slot-width = <32>;
                    dai-tdm-slot-tx-mask = <1 1 1 1 0 0 0 0>;
                    dai-tdm-slot-rx-mask = <1 1 1 1 0 0 0 0>;
                };
            };
        };

        tlv320adc5140_4d: tlv320adc5140@4d {
            #sound-dai-cells = <0>;
            compatible = "ti,tlv320adc5140";
            reg = <0x4d>;
            ti,mic-bias-source = <1>;                 /* VREF x 1.096 */
            ti,vref-source = <0>;                      /* 2.75V */
            ti,pdm-edge-select = <0 1 0 1>;
            ti,gpi-config = <0 0 0 0>;
            ti,gpio-config = <0 0>;
            ti,gpo-config-1 = <0 0>;
            ti,gpo-config-2 = <0 0>;
            port {
                codec_1_ep: endpoint@0 {
                    remote-endpoint = <&mcasp1_ep1>;
                    dai-tdm-slot-num = <8>;
                    dai-tdm-slot-width = <32>;
                    dai-tdm-slot-tx-mask = <0 0 0 0 1 1 1 1>;
                    dai-tdm-slot-rx-mask = <0 0 0 0 1 1 1 1>;
                };
            };
        };

    };


    &mcasp1 {
        #sound-dai-cells = <1>;
        pinctrl-names = "default";
        pinctrl-0 = <&mcasp1_pins>;

        status = "okay";
        op-mode = <0>; /* MCASP_IIS_MODE */
        tdm-slots = <8>;
        /* 4 serializers */
        /* 0: INACTIVE, 1: TX, 2: RX */
        serial-dir = < 0 0 2 0 >;
        tx-num-evt = <1>;
        rx-num-evt = <1>;

        ports {
            #address-cells = <1>;
            #size-cells = <0>;

            mcasp1_port0: port@1 {
                mcasp1_ep0: endpoint {
                    remote-endpoint = <&codec_0_ep>;
                    dai-tdm-slot-num = <8>;
                    dai-tdm-slot-width = <32>;
                    dai-format = "dsp_b";
                    frame-master;
                    bitclock-master;
                    bitclock-inversion; // Optional flag, preserved
                };
            };

            mcasp1_port1: port@2 {
                mcasp1_ep1: endpoint {
                    remote-endpoint = <&codec_1_ep>;
                    dai-tdm-slot-num = <8>;
                    dai-tdm-slot-width = <32>;
                    dai-format = "dsp_b";
                    frame-master;
                    bitclock-master;
                    bitclock-inversion; // Optional flag, preserved
                };
            };
        };
    };

  • Hi Robert,

    Thanks for the info. Unfortunately, we do not have someone knowledgeable about multiple mcasp ports here on the team. What I do know is that this device, the ADC5140, does support multiple devices being used by the same host, where the I2C address of the device is hardware programmable to 4 options. You can also share the TDM audio bus, this ADC supports up to 64 slots of TDM. This app note: https://www.ti.com/lit/an/sbaa383c/sbaa383c.pdf explains how to configure the device to be in multi-device modes via I2C and hardware pin pullup/downs. I'm not exactly sure how to change your DTS or driver files to make this configuration work with two devices but most likely you do not need two mcasp ports. Instead, you would want to change the definition of the device in the driver to support more than one I2C register address. In the yaml file accessible here: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml it defines maxItems for the register, maybe you can increase that to 2. Again I'm not sure what else exactly would need to change. But, two of these ADCs connected on the same I2C line on your Linux processor can be set to two different register addresses and then be controlled from the same I2C host. I can help more if you have a specific I2C command script that you need to run, but as for the Linux driver and dts file, you will likely need to edit the driver/dts files to support more than one ADC at a time, but likely not by changing the mcasp settings. 

    Best,
    Mir