This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/TLV320AIC3106-Q1: How To Configure the 2nd I2S/PCM?

Part Number: TLV320AIC3106-Q1
Other Parts Discussed in Thread: TLV320AIC3106, TLV320AIC3268, TLV320AIC3262, TLV320AIC3212

Tool/software: Linux

Hi All,

I was configuring the 2nd I2S/PCM of TLV320AIC3106-Q1 like below diagram for WL2833Q Bluetooth.

It seemd that I can just add a :ai3x-gpio-func" like

&i2c2 {

        clock-frequency = <400000>;

        pinctrl-names = "default";

        pinctrl-0 = <&pinctrl_i2c2>;

        status = "okay";

 

        codec: tlv320aic3106@18 { ////Audio Codec

                compatible = "ti,tlv320aic3x";

                reg = <0x18>;

                clocks = <&codec_osc>;

                clock-names = "clko_clk";

                AVDD-supply = <&reg_audio>;

                IOVDD-supply = <&reg_audio>;

                DRVDD-supply = <&reg_audio>;

                DVDD-supply = <&reg_audio>;

        gpio-reset = <&gpio4 26 1>;

        ai3x-gpio-func = <11 8>; //<AIC3X_GPIO1_FUNC_AUDIO_WORDCLK, AIC3X_GPIO2_FUNC_AUDIO_BITCLK>

    };

};

But actually, it will crash my 1st I2S (WCLK, BCLK, DIN, DOUT) while playback an audio. So I tried to send the configuration commands through 

I2C like :

i2cset -f -y 1 0x18 98 0xB0

i2cset -f -y 1 0x18 99 0x80

i2cset -f -y 0x18 8 0xD0

I did see the GPIO1 and GPIO2 signals from my scope.

And if I tried to playback an audio from iMX6Q, it will then diable the GPIO1 and GPIO2.

i2cget -f -y 1 0x18 98 showed 0x00

i2cget -f -y 1 0x18 99 showed 0x00

i2cegt -f -y 1 0x18 98 8 showed 0x00

So if there was a good way to configure and enable my Bluetooth?  Thanks for your help.

-Justin

 

  • Hi, Justin,

    My colleague in charge of this device has been notified about your question. As he is out of the office on Holiday, the response could be delayed, so we appreciate your comprehension.

    Best Regards,

      -Diego Meléndez López
       Audio Applications Engineer

  • Hi Diego,

    It's all right since it's holiday season. please get back to me once he is back.
    Thank you very much.

    -Justin
  • Hi Justin,

    Thank you for your patience during the holiday!  

    please see the diagram below.  The MFP3 and GPIOs are muxed, so cannot be concurrently used with signals from your iMX60.  

    This would allow you to continue using a bluetooth device, when the processor is in sleep/low power mode.

    I hope that answers your question,  but if I misunderstood, please let me know.  I'm happy to help!

    best regards, 

    -Steve Wilson

  • Hi Steve,

    So you are saying that (WCLK, BCLK, DIN, DOUT) and (GPIO1, GPIO2, MFP3, DOUT) two channels can only one be activated?

    Then where should I put the this activation code? Does it mean I enable the channel when I want to use it, and disable the channel when I don't want to use it?

    How do I configure/enable/switch to (GPIO1, GPIO2, MFP3, DOUT) this channel, since I can not write the ai3x-gpio-func in device tree?

    -Justin
  • Hi Justin,

    Correct, only one Audio bus can be active at a time. So if the WL81330 is active, the iMX60 should not be active.

    The GPIO pins become active when you program the registers to be used as I2S audio ports.

    before you switch to the WL81330, you should discontinue the audio from the iMX60, then change audio bus, then start the WL81330 audio.
    it may makes sense to briefly mute the dac too. but see how that goes.

    best regards,
    -Steve Wilson
  • Justin,

    if you want to have two simultaneous Audio buses the TLV320AIC3262, TLV320AIC3212 and TLV320AIC3268 do have this functionality.

    best regards,
    -Steve
  • Hi Steve,

    Can you provide me some code snippet or sample code of configuration of GPIO1 and GPIO2 to I2S/PCM. I had tried to set up the Register 98 to 0xB0 (as WCLK) and Register 99 to 0x80 (as BCLK), but not worked.

    -Justin
  • Hi Steve,

    My development environment is Android N7.1.1 (Linux 4.1.15).
    And my current situation is Bluetooth headset can connect
    to my development board, but I can not hear any sound. The Audio codec is capable
    of playback and recording from Android app like Music/SoundRecorder, and from Linux binary
    like tinyplay/tinycap.

    The codes related follows:
    [DeviceTree: imx6q-asurada-pins.dtsi]
    / {
    sound-tlv320aic3106 {
    compatible = "fsl,imx6-asurada-tlv320aic3106",
    "fsl,imx-audio-tlv320aic3x";
    model = "tlv320aic3x-audio";
    audio-codec = <&codec>;
    cpu-dai = <&ssi2>;
    mux-int-port = <2>;
    mux-ext-port = <4>;
    audio-routing =
    "Line Out Jack", "LLOUT",
    "Ext Spk", "MONO_LOUT",
    "Line Out Jack", "RLOUT",
    "LINE1L", "AV Line In Jack",
    "LINE1R", "AV Line In Jack",
    "LINE2L", "Turner Line In",
    "LINE2R", "1388 Line Out",
    "MIC3L", "Aux Line In Jack",
    "MIC3R", "Aux Line In Jack",
    "Playback", "CPU-Playback",
    "CPU-Capture", "Capture";
    };
    };

    &i2c2 {
    clock-frequency = <400000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c2>;
    status = "okay";

    codec: tlv320aic3106@18 { ////Audio Codec
    compatible = "ti,tlv320aic3x";
    reg = <0x18>;
    clocks = <&codec_osc>; //original
    //clocks = <&clks IMX6QDL_CLK_CKO>;
    clock-names = "clko_clk";
    AVDD-supply = <&reg_audio>;
    IOVDD-supply = <&reg_audio>;
    DRVDD-supply = <&reg_audio>;
    DVDD-supply = <&reg_audio>;
    gpio-reset = <&gpio4 26 1>;
    #if 0 //justin@20171228
    ai3x-gpio-func = <
    11 //justin@20171219: AIC3X_GPIO1_FUNC_AUDIO_WORDCLK
    8 //justin@20171219: AIC3X_GPIO2_FUNC_AUDIO_BITCLK
    >;
    #endif
    };
    };

    [Codec Driver: kewrnel_imx/sound/soc/codecs/tlv320aic3x.c]
    static const struct snd_kcontrol_new aic3x_mono_controls[] = {

    /* justin@20180103 */
    SOC_SINGLE("GPIO1 Control Switch", AIC3X_GPIO1_REG, 4, 0x0F, 0),
    SOC_SINGLE("GPIO2 Control Switch", AIC3X_GPIO2_REG, 4, 0x0F, 0),
    SOC_SINGLE("Audio Serial Data Interface Mode", AIC3X_ASD_INTF_CTRLB, 6, 0x03, 0),
    };

    [config_tlv320aic3x.h of tinyalsa_hal.c ]
    static struct route_setting mm_bt_mic_input_TLV320AIC3X[] = {
    //R98(AIC3X_GPIO1_REG): WCLK
    {
    .ctl_name = "GPIO1 Control Switch",
    .intval = 11,
    },
    //R99(AIC3X_GPIO2_REG): BCLK
    {
    .ctl_name = "GPIO2 Control Switch",
    .intval = 8,
    },
    //R9(AIC3X_ASD_INTF_CTRLB): DSP mode
    {
    .ctl_name = "Audio Serial Data Interface Transfer Mode",
    .intval = 1,
    },
    //R81(PGAL_2_LLOPM_VOL)
    {
    .ctl_name = "Left Line Mixer PGAL Bypass Switch",
    .intval = 1,
    },
    //R84(PGAR_2_LLOPM_VOL)
    {
    .ctl_name = "Left Line Mixer PGAR Bypass Switch",
    .intval = 1,
    },
    {
    .ctl_name = NULL,
    },
    };

    static struct audio_card tlv320aic3x_card = {
    .name = "tlv320aic3x-audio",
    .driver_name = "tlv320aic3x-aud",
    .supported_out_devices = (
    AUDIO_DEVICE_OUT_WIRED_HEADSET |
    AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
    AUDIO_DEVICE_OUT_SPEAKER |
    AUDIO_DEVICE_OUT_ALL_SCO |
    AUDIO_DEVICE_OUT_DEFAULT ),
    .supported_in_devices = (
    AUDIO_DEVICE_IN_WIRED_HEADSET |
    AUDIO_DEVICE_IN_BUILTIN_MIC |
    AUDIO_DEVICE_IN_ALL_SCO |
    AUDIO_DEVICE_IN_DEFAULT),
    .defaults = defaults_TLV320AIC3X,
    .bt_output = NULL, //bt_output_TLV320AIC3X,
    .speaker_output = NULL, //speaker_output_TLV320AIC3X,
    .hs_output = NULL, //hs_output_TLV320AIC3X,
    .earpiece_output = NULL, //earpiece_output_TLV320AIC3X,
    .vx_hs_mic_input = NULL, //vx_hs_mic_input_TLV320AIC3X,
    .mm_main_mic_input = NULL, //mm_main_mic_input_TLV320AIC3X,
    .vx_main_mic_input = NULL, //vx_main_mic_input_TLV320AIC3X,
    .mm_hs_mic_input = NULL, //mm_hs_mic_input_TLV320AIC3X,
    .vx_bt_mic_input = mm_bt_mic_input_TLV320AIC3X, //vx_bt_mic_input_TLV320AIC3X,
    .mm_bt_mic_input = mm_bt_mic_input_TLV320AIC3X,
    .card = 0,
    .out_rate = 0,
    .out_channels = 0,
    .out_format = 0,
    .in_rate = 0,
    .in_channels = 0,
    .in_format = 0,
    };

    [Board Config: device/fsl/asurada/audio_policy.conf]
    audio_hw_modules {
    primary {
    outputs {
    primary {
    sampling_rates 48000
    channel_masks AUDIO_CHANNEL_OUT_STEREO
    formats AUDIO_FORMAT_PCM_16_BIT
    # justin: devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_AUX_DIGITAL
    devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_ALL_SCO
    flags AUDIO_OUTPUT_FLAG_PRIMARY
    }
    hdmi {
    sampling_rates dynamic
    channel_masks dynamic
    formats AUDIO_FORMAT_PCM_16_BIT
    devices AUDIO_DEVICE_OUT_AUX_DIGITAL
    flags AUDIO_OUTPUT_FLAG_DIRECT
    }
    esai {
    sampling_rates 48000
    channel_masks AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1
    formats AUDIO_FORMAT_PCM_16_BIT
    devices AUDIO_DEVICE_OUT_SPEAKER
    flags AUDIO_OUTPUT_FLAG_DIRECT
    }
    }
    inputs {
    primary {
    sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
    channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
    formats AUDIO_FORMAT_PCM_16_BIT
    #justin: devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_AUX_DIGITAL
    #justin: |AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET (maybe)
    devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_AUX_DIGITAL|AUDIO_DEVICE_IN_ALL_SCO
    }
    }
    }
    #justin: =====>
    a2dp {
    outputs {
    a2dp {
    sampling_rates 44100
    channel_masks AUDIO_CHANNEL_OUT_STEREO
    formats AUDIO_FORMAT_PCM_16_BIT
    devices AUDIO_DEVICE_OUT_ALL_A2DP
    }
    }
    inputs {
    a2dp {
    sampling_rates 44100|48000
    channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
    formats AUDIO_FORMAT_PCM_16_BIT
    devices AUDIO_DEVICE_IN_BLUETOOTH_A2DP
    }
    }
    }
    #justin: <=====

    }


    The current problem,my routing path (mm_bt_mic_input_TLV320AIC3X) is not establish from what I have code tracing.
    And I doubt tinyalsa_hal.c has no idea that Bluetooth turns on, and not goes (mm_bt_mic_input_TLV320AIC3X).
    [tinyalsa_hal.c]
    static void select_input_device(struct imx_audio_device *adev)
    {
    int i;
    int headset_on = 0;
    int main_mic_on = 0;
    int sub_mic_on = 0;
    int bt_on = adev->in_device & AUDIO_DEVICE_IN_ALL_SCO;

    if (!bt_on) {
    if ((adev->mode != AUDIO_MODE_IN_CALL) && (adev->active_input != 0)) {
    /* sub mic is used for camcorder or VoIP on speaker phone */
    sub_mic_on = (adev->active_input->source == AUDIO_SOURCE_CAMCORDER) ||
    ((adev->out_device & AUDIO_DEVICE_OUT_SPEAKER) &&
    (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION));
    }

    headset_on = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET;
    main_mic_on = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC;
    }

    ALOGI("justin: %s: bt_on = %d, headset_on = %d, main_mic_on = %d, sub_mic_on = %d\n",
    __func__, bt_on, headset_on, main_mic_on, sub_mic_on);
    /* TODO: check how capture is possible during voice calls or if
    * both use cases are mutually exclusive.
    */
    if (bt_on)
    {
    ALOGI("justin: %s: bt_on\n", __func__);
    for(i = 0; i < MAX_AUDIO_CARD_NUM; i++)
    set_route_by_array(adev->mixer[i], adev->card_list[i]->mm_bt_mic_input, 1);
    }
    else {
    /* Select front end */
    if (headset_on)
    {
    ALOGI("justin: %s: headset_on\n", __func__);
    for(i = 0; i < MAX_AUDIO_CARD_NUM; i++)
    set_route_by_array(adev->mixer[i], adev->card_list[i]->mm_hs_mic_input, 1);
    }
    else if (main_mic_on || sub_mic_on)
    {
    ALOGI("justin: %s: main_mic_on || sub_mic_on\n", __func__);
    for(i = 0; i < MAX_AUDIO_CARD_NUM; i++)
    set_route_by_array(adev->mixer[i], adev->card_list[i]->mm_main_mic_input, 1);
    }
    else
    {
    ALOGI("justin: %s: ELSE\n", __func__);
    for(i = 0; i < MAX_AUDIO_CARD_NUM; i++)
    set_route_by_array(adev->mixer[i], adev->card_list[i]->mm_main_mic_input, 0);
    }
    }
    }

    Please help. Thank you very much.

    -Justin
  • Justin,

    I haven't forgotten about you. I will try to set up the secondary I2S this afternoon and get back to you with the results.

    best regards
    -STeve Wilson
  • Hi Steve,

    Thank you for your help. I am expecting your result.

    -Justin
  • Justin,

    I was able to test this in the lab today.

    If you have the iMX60 functioning with the Codec, and you want to switch i2S buses, the ADC and DACs must be powered down, then register 98 and 99 and 101 should be written to. Then power the ADC and DACs back up.

    98: 0xC0
    99: 0x80
    101:0x10

    best regards,
    -Steve Wilson
  • Hi Steve,

    As you mentioned in the email reply. The correct way to switch I2S bus is:
    [1] ADCs and DACs powered down. But which resgisters?
    [2] Register 98 set to 0xC0. But why not 0xB0?
    [3] Register 99 set to 0x80.
    [4] Register 101 set to 0x10. But why MFP3 pin usage as audio serial data input pin is enabled (MOSI), not SDIN?
    [5] ADCs and DACs powered back up? But which resgisters?

    Could you please sent me your code snippets?
    How do you know your switching I2S bus is successfully?

    Thank you for your help.

    -Justin
  • Justin,

    1: This info is in the datasheet. ADC: R19 and R22. DAC: R37.
    2: Yes, my mistake, 0xB0 is the correct value.
    3: yes
    4: The Datasheet is unfortunately not very clear on this. when you look at the mux diagram in the datasheet, something has to control the mux telling it where the digital audio data is coming from. it is either the MFP3 pin or the DIN pin. default is DIN, so it simply makes sense that changing this value would switch the mux to the MOSI/GPIO pin (MFP3) I have confirmed in my tests, that if you write 0x00 to register 101 the Din pin is still active. while if you write 0x10, the MFP3 pin is active.
    5: same as #1


    I performed the tests on the EVM, so I don't have any code snippets, just register configurations. here they are.

    i i2cfast
    w 30 01 80
    w 30 07 8A
    w 30 62 B0
    w 30 63 80
    w 30 65 10
    w 30 08 C0
    w 30 29 02
    w 30 2B 00
    w 30 25 D0
    w 30 26 20
    w 30 40 80
    w 30 2F 80
    w 30 33 0D
    w 30 41 0D


    I know my I2S bus is switching correctly because I am providing a test tone from an AP, and I can monitor that same test tone with the AP. It looks good.

    best Regards,
    -Steve Wilson

  • HELLO STEVE

    I Want To Make Sure As I Asked In The Other Post.

    Can We Control AIC3106-Q1 To Route Audio From Host Processor Then PCM Out To WL1833Q Bluetooth WiFi Chipset? And Also Can We Route WL1833Q PCM To Host Processor For Making Voice Recorder Feature? That's What We Want The Codec For.

  • Bright Wang,

    There is only one serial bus, not two. You cannot use a DIN for the BT module without disabling the Din you want for the processor. There is only one Din.
    So there is no way to do what you want with this device. unless you only want one DIN active at a time. 

    Best Regards,
    -Steve Wilson