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.

AM335x interface audio codec TLV320AIC3100 supplies error messages

Other Parts Discussed in Thread: TLV320AIC3100, TLV320AIC3111

Hello,

We use the beaglebone black as development board for a project, in this project we need an audio codec, this would be the TLV320AIC3100. As operation system we use the Ti Linux SDK 07.00.00.00 version.

We have connected the audio codec on the mcasp0 interface(pinning: lcd_data8, 9, 11, 15 & clkout2) and i2c1 port.

I have changed the device tree and disabled the lcd data and put in the next information:

In am335x-boneblack.dts

&am33xx_pinmux {
    i2c1_pins: pinmux_i2c1_pins {
            pinctrl-single,pins = <
                0x158 0x32    /* spi0_d1.i2c1_sda,  PIN_INPUT_PULLUP | MODE 3 -> connected to sda1 */
                0x15c 0x32    /* spi0_cs0.i2c1_scl, PIN_INPUT_PULLUP | MODE 3 -> connected to scl1 */
            >;
    };

    am335x_evm_audio_pins: pinmux_am335x_evm_audio_pins {
            pinctrl-single,pins = <
                0xc0 0x23    /* lcd_data8.mcasp0_aclkx, PIN_INPUT_PULLDOWN  | MODE3 -> connected to bclk */
                0xc4 0x23    /* lcd_data9.mcasp0_fsxm,  PIN_INPUT_PULLDOWN  | MODE3 -> connected to wclk */
                0xcc 0x04    /* lcd_data11.mcasp0_axr2, PIN_OUTPUT_PULLDOWN | MODE4 -> connected to DIN  */
                0xdc 0x24    /* lcd_data15.mcasp0_axr3, PIN_INPUT_PULLDOWN  | MODE4 -> connected to dout */
            >;
    };                        


};

&i2c1 {
    #address-cells = <1>;
    #size-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2c1_pins>;
    clock-frequency = <100000>;
    status = "okay";

    tlv320aic3x: tlv320aic3x@18 {
        compatible = "ti,tlv320aic3x";
        reg = <0x18>;
        status = "okay";
    };
};

&mcasp0 {
    pinctrl-names = "default";
    pinctrl-0 = <&am335x_evm_audio_pins>;

    status = "okay";

    op-mode = <0>;        /* MCASP_IIS_MODE */
    tdm-slots = <2>;
    serial-dir = <        /* 0: INACTIVE, 1: TX, 2: RX */
        0 0 1 2        /* AXR0 AXR1 AXR2 AXR3 */
    >;
    
    tx-num-evt = <1>;
    rx-num-evt = <1>;
};

and in am335x-bone-common.dtsi I added the follwing unter the OCP

sound {
            compatible = "ti,da830-evm-audio";
            ti,model = "DA830 EVM";
            ti,audio-codec = <&tlv320aic3x>;
            ti,mcasp-controller = <&mcasp0>;
            ti,codec-clock-rate = <12000000>;
            ti,audio-routing =
                "Headphone Jack",    "HPLOUT",
                "Headphone Jack",    "HPROUT",
                "LINE1L",        "Line In",
                "LINE1R",        "Line In";
        };

when I know start up the image i get the following errors:

davinci_evm sound.5: Asoc: CPU DAI (null) not registered

davinci_evm sound.5: snd_soc_register_card failed (-517)

platform sound.5: Driver davinci_evm request probe deferral

tlv320aic3x-codec 1-0018: Failed to get supply 'IOVDD': -19

tlv320aic3x-codec 1-0018: Failed to request supplies: -19

tlv320aic3x-codec 1-0018: ASoC: falied to instantiate card -19

Why  do we get the errors? I have measure the voltage and this is 3.3Voltage

Thanks in advance

  • Hello,

    Edit information about the first problem I write above, the following errors are gone:

    tlv320aic3x-codec 1-0018: Failed to get supply 'IOVDD': -19

    tlv320aic3x-codec 1-0018: Failed to request supplies: -19

    tlv320aic3x-codec 1-0018: ASoC: falied to instantiate card -19

    It seems like you must give in the regulator information in the dts file, so after that this doesn't come again, but the following does:

    [ 6.691234] davinci_evm sound.5: ASoC: CPU DAI (null) not registered
    [ 6.795236] davinci_evm sound.5: snd_soc_register_card failed (-517)
    [ 6.848397] platform sound.5: Driver davinci_evm requests probe deferral
    [ 6.913853] davinci_evm sound.5: ASoC: CPU DAI (null) not registered
    [ 6.967747] davinci_evm sound.5: snd_soc_register_card failed (-517)
    [ 7.016922] platform sound.5: Driver davinci_evm requests probe deferral
    [ 7.107289] davinci_evm sound.5: tlv320aic3x-hifi <-> 48038000.mcasp mapping ok

    ALSA: Restoring mixer settings...
    No state is present for card EVM
    Found hardware: "DA830_EVM" "" "" "" ""
    Hardware is initialized using a generic method
    No state is present for card EVM

    What does the errors mean and how can it be solved?

    Thanks in advanced

  • Hi Patrick,

    It looks like you haven't configure the machine layer in ASoC properly.  Please go over the content in the wiki that Biser posted above.

    So you know, you need to edit sound/soc/davinci/davinci-evm.c.  There is also this guide that gives an example of editing this file: http://processors.wiki.ti.com/index.php/Sitara_Linux_SDK_Audio_DAC_Example

    Josh

  • Hello Biser,

    Thanks for the link.

    I had now changed the pin settings just like the audio cape(mcasp0), but the same error message I get.

    Also when I use the speaker-test or the aplay nothing happen. What also strange is that there no MCLK clock and this is connected to the mcasp0_ahclkx pin, just like in the audio cape.

    thanks in advance

  • Hi Patrick,

    With your current changes, MCLK would not be an output of the McASP, so this behavior is expected.  For an example of how to set MCLK as McASP output, look over the the Interfacing a DAC wiki I sent you.

    Regards,

    Josh

  • Hello Jash,

    Thanks for direction, but when I look in the file davinci-evm.c and use the guide you pionted me to. I see that there is already an struct called:

    static struct snd_soc_dai_link evm_dai-tlv320aic3x

    In this struct i see that dai_fmt = snd_soc_daifmt_cbm_cfm and thas means:  /* codec is clock and frame master */, does it mean that the codec must generate the clock?

    thanks in advance

  • Hi Patrick,

    In our EVMs, the AIC3x devices are always clock masters, so they provided BCLK and FSYNC to the McASP.  The MCLK that the AIC3x uses comes from an external oscillator.

    The guide I sent you shows an example of the McASP generating the clocks, though; in this case, it uses the 24MHz aux clock as MCLK, and from that clock signal BCLK and FSYNC are created.

    Regards,

    Josh

  • Hello Josh,

    Thanks for the reply.

    I had folllowed the main schematic guide from the starter kit, in my design. With the output i/o from the beaglebone black so I could test everything.

    In the starterkit(TMDSSK3358) the MCLK is connected to the clkout2 pin, when I measure I see here an frequency of about 31.25KHz, what is very strange.

    When I use the pin  MCASP0_AHCLKX like in the beaglebone I do not get any output.

    So the clock generate from the beaglebone is not correct. Can this be a wrong setting in the device tree?

    Regards

    Patrick

  • Hello,

    I have news. It seems that the errors on start-up are gone:

    6.809324] davinci_evm sound.6: tlv320aic3x-hifi <-> 48038000.mcasp mapping ok 

    ALSA: Restoring mixer settings...
    No state is present for card EVM
    Found hardware: "DA830_EVM" "" "" "" ""
    Hardware is initialized using a generic method
    No state is present for card EVM

    that are now the message's at start-up.

    Now I did connect the same pinnig as the audio cape for Beaglebone black, but just as said in the previous post I did not saw a clock puls for the MCLK, but when I did the next thing:

    root@am335x-evm:~# aplay -L
    null
    Discard all samples (playback) or generate zero samples (capture)
    default:CARD=EVM
    DA830 EVM,
    Default Audio Device
    sysdefault:CARD=EVM
    DA830 EVM,
    Default Audio Device
    root@am335x-evm:~# aplay -l
    **** List of PLAYBACK Hardware Devices ****
    card 0: EVM [DA830 EVM], device 0: AIC3X tlv320aic3x-hifi-0 []
    Subdevices: 1/1
    Subdevice #0: subdevice #0
    root@am335x-evm:~# aplay beepbeep.wav
    Playing WAVE 'beepbeep.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
    root@am335x-evm:~#

    I get an 12Mhz clock from the MCASP0_AHCLKX(MCLK), but there is no sound. When enter: dmesg -c i get the following error:

    ALSA sound/core/pcm_native.c:1544 playback drain error (DMA or IRQ trouble?)

    Regards

    Patrick

  • Hi Patrick,

    If the McASP is supplying the clocks, it will only produce them when audio is being recorded or played; this is why you only see the 12 MHz clock when you use aplay.  Have you check the other signals with a scope to make sure they are correct?  The error you see sounds like the clocks are not set up (so data is not being pulled from buffers).

    Regards,

    Josh

  • Hello,

    Some errors still are present I saw and also measure the signals:

    [ 1.342910] davinci_evm sound.6: ASoC: CODEC (null) not registered

    [ 1.349429] davinci_evm sound.6: snd_soc_register_card failed (-517)
    [ 1.358249] platform sound.6: Driver davinci_evm requests probe deferral

    Later in the debug I saw this:

    [ 1.615533] ALSA device list:
    [ 1.618684] #0: DA830 EVM

    And about the end:

    LSA: Restoring mixer settings...
    No state is present for card EVM
    Found hardware: "DA830_EVM" "" "" "" ""
    Hardware is initialized using a generic method
    No state is present for card EVM

    The settings are now the same as the audio cape for the beaglebone black, the i2c2 is used and mcasp0 is with the same pinning as the beaglebone.

    When measure the MCLK the is no clockpulse, just after the command: aplay beepbeep.wav you see and 12Mhz clock on that pin. When booting there is no clock pulse present.

    I have measured the signals with the scope:

    After booting:

    MCLK, DOUT, DIN, BCLK, WCLK all low, the I2C signal are high.

    After / while aplay:

    MCLK has clockpule, WCLK, DOUT,DIN are LOW and on BCLK  clock signal of about 200mV of about 12Mhz.

    thanks in advance

    Patrick

  • Hello,

    Still have no luck with the audio codec and I was wondering if the correct driver will be loaded. In the dts I use "ti,da830-evm-audio" and that is a link to the tlv320aic3x chip.

    Now I see that there is also and tlv320aic3111 driver, which in the same serie as the tlv320aic3100. So I was wondering if this driver not must being used?

    Kind regards

    Patrick

  • Hello,

    After the last post I tried the driver for the TLV320AIC3111, but I still get the same problem and error messages.

    Then I tried an external 12Mhz clock on the MCLK, but the same problem stay's.

    So I'm little bit confused and out of options, I do not see any clock pulse from blck or wclk, the mclk is present at 12Mhz and all voltage supply's are correct. Also to I2c interface works fine

    Maybe somebody has an idea what it can be.

    Thanks in advance

    Patrick

  • Hi Patrick,

    It sounds like you definitely have clock set up issues.  Can you give me a description of exactly how you intend your clocks to be configured?  For example:

    1. Is McASP or codec clock master?
    2. Does McASP generate MCLK or does a crystal?

    Also, please look at the clock set up portion of the Audio DAC Porting Example for some clues as to how clocks can be set up.

    Regards,

    Josh

  • Hello Josh,

    The codec is the master and the MCLK is external 12Mhz generated from the Beaglebone Black board.

    I have now used mcasp1 interface, but the result stays exactly the same:

    ALSA sound/core/pcm_native.c:1544 playback drain error (DMA or IRQ trouble?)

    If I look with the scope I see the MCLK present, but when using aplay nothing happens on the signal: bclk, wclk, audout, audin. I2c is resposing corretly to the codec.

    Would it be wiser to use the MCASP interface as master?

    Regards,

    Patrick

  • Hi Patrick,

    Thanks for the clarification.  I think that you're fine with keeping the codec as clock master--that's how we do it on our EVMs.

    It sounds like the issue now is that the codec driver is not properly configuring the bclk and frame sync.  I'm not an expert on the codec, so you may want to ask the codec specific questions at the the Audio Converters forum.  Although I do have some tips for you:

    In the AIC3x driver, I see the following note:

     * Notes:
     *  The AIC3X is a driver for a low power stereo audio	
     *  codecs aic31, aic32, aic33, aic3007.

    So I don't believe this is the right driver to use.  As you mention, though, there is an aic3111 driver in the 3.12 kernel in our SDK 7.0.  If you look at davinci-evm.c, you can see that the am43xx epos platform entries show how to set up this driver.  I would recommend taking a look at those entries and adding them to your set up.

    Regards,

    Josh 

  • Hello Josh,

    Thanks for the advice! I have setup the use of the aic3111 driver with the mcasp1 interface and i2c1 one interface here a part of my dts code:

    &am33xx_pinmux {
    i2c1_pins: pinmux_i2c1_pins {
    pinctrl-single,pins = <
    0x158 0x32 /* spi0_d1.i2c1_sda, PIN_INPUT_PULLUP | MODE 3 -> connected to sda1 */
    0x15c 0x32 /* spi0_cs0.i2c1_scl, PIN_INPUT_PULLUP | MODE 3 -> connected to scl1 */
    >;
    };
    am43xx_evm_audio_pins: pinmux_am43xx_evm_audio_pins {
    pinctrl-single,pins = <
    0x1ac 0x23 /* mcasp0_ahclkx.mcasp1_axr1 MODE3 -> connected to dout*/
    0x1a0 0x23 /* mcasp0_aclkr.mcasp1_aclkx MODE3 -> connected to bclk*/
    0x1a4 0x23 /* mcasp0_fsr.mcasp1_fsx MODE3 -> connected to wck*/
    0x1a8 0x03 /* mcasp0_axr1.mcasp_axr0 MODE3 -> connected to din*/
    >;
    };
    };

    &i2c1 {
    #address-cells = <1>;
    #size-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2c1_pins>;
    clock-frequency = <100000>;
    status = "okay";

    tlv320aic3111: tlv320aic3111@18 {
    compatible = "ti,tlv320aic311x";
    reg = <0x18>; status = "okay";

    /* Regulators */
    AVDD-supply = <&ldo4_reg>;
    IOVDD-supply = <&ldo4_reg>;
    DRVDD-supply = <&ldo4_reg>;
    DVDD-supply = <&ldo1_reg>;
    HPVDD-supply = <&ldo4_reg>;
    SPRVDD-supply = <&ldo4_reg>;
    SPLVDD-supply = <&ldo4_reg>;
    };
    };

    &mcasp1 {
    pinctrl-names = "default";
    pinctrl-0 = <&am43xx_evm_audio_pins>;
    status = "okay";
    op-mode = <0>; /* MCASP_IIS_MODE */
    tdm-slots = <2>;
    serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
    1 2 0 0 /* AXR0 AXR1 AXR2 AXR3 */
    >;

    tx-num-evt = <1>;
    rx-num-evt = <1>;
    };

    / {
    sound {
    compatible = "ti,am43xx-epos-evm-audio";
    ti,model = "AM43x-EPOS-EVM";
    ti,audio-codec = <&tlv320aic3111>;
    ti,mcasp-controller = <&mcasp1>;
    ti,codec-clock-rate = <12000000>;
    ti,audio-routing =
    "Speaker", "SPL",
    "Speaker", "SPR",
    "Headphone Jack", "HPL",
    "Headphone Jack", "HPR",
    "MIC1LP", "Mic Jack",
    "MIC1RP", "Mic Jack";
    };
    };


    When booting the following message's also displayed:
    [ 1.386726] davinci_evm sound.6: ASoC: CODEC (null) not registered
    [ 1.393315] davinci_evm sound.6: snd_soc_register_card failed (-517)
    [ 1.400040] platform sound.6: Driver davinci_evm requests probe deferral
    ..... [ 1.598278] davinci_evm sound.6: tlv320aic31xx-hifi <-> 4803c000.mcasp mapping ok
    [ 1.619063] tlv320aic31xx-codec 1-0018: ASoC: mux CM M-Terminal has no paths
    .....
    [ 1.765424] ALSA device list:
    [ 1.768554] #0: AM43x-EPOS-EVM
    ....
    ALSA: Restoring mixer settings...
    No state is present for card AM43xEPOSEVM
    Found hardware: "AM43x-EPOS-EVM" "" "" "" ""
    Hardware is initialized using a generic method
    No state is present for card AM43xEPOSEVM

    Then I log in and give a few commands to check:

    root@am335x-evm:~# aplay -l
    **** List of PLAYBACK Hardware Devices ****
    card 0: AM43xEPOSEVM [AM43x-EPOS-EVM], device 0: AIC3111 tlv320aic31xx-hifi-0 []
    Subdevices: 1/1
    Subdevice #0: subdevice #0
    root@am335x-evm:~# aplay -L
    null
    Discard all samples (playback) or generate zero samples (capture)
    default:CARD=AM43xEPOSEVM
    AM43x-EPOS-EVM,
    Default Audio Device
    sysdefault:CARD=AM43xEPOSEVM
    AM43x-EPOS-EVM,
    Default Audio Device

    And then I will play and .wav sound:

    root@am335x-evm:~# aplay beepbeep.wav                                                        
    Playing WAVE 'beepbeep.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono                             
    root@am335x-evm:~# dmesg -c                                                                  
    [  391.629658] ALSA sound/core/pcm_native.c:1544 playback drain error (DMA or IRQ trouble?)
    But nothing happend, no sound and again the same error, also no bclk, wclk is present when play the sound.
    Nothing on the lines happend, while a mclk is present.

    Thanks in advance.
    Patrick

  • Hello,

    I have stil go problems with the audio codec, like the post before this one.(using driver TLV320AIC3111 from the AM43xx)

    Now I did connect an logic analyzer to the I2C data lines to look what happend. After some study it looks like the most things are correctly configured, like the WCLK and BCLK are configured as output. The MCLK is input for the PLL_CLKIN and the CODEC_CLKIN = PLL_CLK, etc.

    Then I looked at the I2C bus when aplay is started, you see the configuration for the registers, but when looking at the PLL register Page 0 / Register 5: PLL P and R-VAL the configuration is 0x11, and stays 0x11.

    This is strange because then bit 7 is 0 and that means that PLL is powered down. This is not good, because now the clocks will not internally starts, so the interface mcasp will never work.


    How can this being solved?

    Thanks in advance.

    Patrick

  • Hello,

    It looks like we got a clock signal.

    Whit my logic analyzer and some configuration settings, when using command: speaker-test -c2.

    I see clock on the BCLK and WCLK. The frequency are: MCLK: 12Mhz, BCLK: 1.6Mhz and WCLK: 48Khz, also data on the DIN port is present.

    But the speaker-test -c2 gives an error message's:

    Write error: -5, Input/output error

    xrun_recovery failed: -5, Input/output error

    Transfer failed: Operation not permitted.

    What does this mean?

    Thank in advance

    Patrick

  • Hi Patrick,

    It could mean that the clocks from the codec are not actually finding their way to the McASP; this could be caused by improper pinmuxing.  I would recommend double checking your pinmuxing and connections to be absolutely sure everything is correct.

    Regards,

    Josh

  • Hi Josh,

    Thanks for you advice. I did have a good look and I saw that I yesterday changed my MCASP interface from 1 to 0, I used the correct pinmux settings.

    But forget to change in the sound{} that interface mcasp0 must be used instead of mcasp1. Now I changed it and speaker-test works fine, I hear an good pink noise.

    So I tried an wav example of 8bit mono but this would not play, it say only 16bit Litte Endian. So I used a wav with 16bit and it plays.

    I use the command: aplay -Dhw:0,0 sample1.wav, but a strange message appears after the play. The wav is done playing and aplay just hangs a little and git this messages:

    aplay: pcm_write:1737: write error: Input/output error
    [  956.001364] tlv320aic31xx-codec 1-0018: aic31xx_wait_bits: Failed! 0xa5 was 0x88 expected 0x0 (0, 0x80, )
    [  956.012280] tlv320aic31xx-codec 1-0018: ASoC: POST_PMD: DAC Left event failed: -1
    [  957.122289] tlv320aic31xx-codec 1-0018: aic31xx_wait_bits: Failed! 0xa5 was 0x88 expected 0x0 (0, 0x8, 500000 us)
    [  957.133087] tlv320aic31xx-codec 1-0018: ASoC: POST_PMD: DAC Right event failed: -1

    Was does that mean?

    Kind regards and again thanks for the help.

    Patrick

  • Hi Patrick,

    I'm not sure what those errors mean--it looks to be something with the aic31xx driver rather than the McASP.

    One thing I would suggest is using plugw:0,0 instead of hw:0,0, as plughw:0,0 will do the proper format conversions on the audio file to match the parameters of the audio hardware.

    Regards,

    Josh

  • Hello Josh,


    Thanks for the advice and your help. The most of the time everything works fine. I'm now busy to get mplayer to works, so i could play mp3 files

    Regards

    Patrick

  • Hi Patrick,

    I am facing same problem.

    [    9.586716] tlv320aic3x-codec 2-0018: Failed to get supply 'IOVDD': -517
    [    9.598903] tlv320aic3x-codec 2-0018: Failed to request supplies: -517
    [    9.613160] tlv320aic3x-codec 2-0018: asoc: failed to probe CODEC tlv320aic3x-codec.2-0018: -517

    i am using same codec TLV320AIC3100.


    Can you say what regulator information added in dts file.

    But i am for allwinner board, it may hep me.

    Regards

    Punith

  • Hello Punith

    I have used the Beaglebone Black as development board, and have the following in my dts file:

    &I2C1 {

       ...............Here information about the pinctrl, status etc etc

    tlv320aic3111: tlv320aic3111@18{

    compatible ="ti, tlv320aic311x";

    reg =<0x18>;

    status = "okay";

    /*regulators*/

    AVDD-supply = < &ldo4_reg>;

    IOVDD-supply = < &ldo4_reg>;

    DRVDD-supply = < &ldo4_reg>;

    DVDD-supply = < &ldo1_reg>;

    HPVDD-supply = < &ldo4_reg>;

    SPRVDD-supply = < &ldo4_reg>;

    SPLVDD-supply = < &ldo4_reg>;

    }

    Remeber that this supply reference to my pmic which is used in the beaglebone black, the last two I must changed because it needs the vbat as power.

    regards

    Patrick

  • Hi Patrick,


    I just commented all regultor function in codec driver , then i am able to create sound card, but once i play audio

    it is playing fine without any error but i am not getting any audio on HPLOUT and HPROUT line.

    Here will be my link for my issue.

    http://e2e.ti.com/support/data_converters/audio_converters/f/64/p/349115/1225305.aspx#1225305

    if you want i will post machine driver code and schematics also.

    Kindly tell me what will be the issue.


    Your help will be greatly appreciable.

    Regards

    Punith

  • Hello Puntih,

    Please follow this wiki:

    http://processors.wiki.ti.com/index.php/Linux_Core_Audio_User's_Guide

    at the paragraph: AM43x-EPOS-EVM

    There you see how you must settup the amixer to get the headphone running.

    Kind regards

    Patrick

  • Hi Patrick,

    Thanks for your replay.

    but getting error like:

    root@localhost:/# amixer -c 2 sset 'HP Right' on
    amixer: Unable to find simple control 'HP Right',0

    But here will be my output of amixer -c 2 (because in my case sound card number is 2).

    root@localhost:/# amixer -c 2
    Simple mixer control 'PCM',0
      Capabilities: pvolume penum
      Playback channels: Front Left - Front Right
      Limits: Playback 0 - 127
      Mono:
      Front Left: Playback 87 [69%] [-20.00dB]
      Front Right: Playback 87 [69%] [-20.00dB]
    Simple mixer control 'Line',0
      Capabilities: pswitch penum
      Playback channels: Front Left - Front Right
      Mono:
      Front Left: Playback [on]
      Front Right: Playback [on]
    Simple mixer control 'Line DAC',0
      Capabilities: pvolume penum
      Playback channels: Front Left - Front Right
      Limits: Playback 0 - 118
      Mono:
      Front Left: Playback 71 [60%] [-23.50dB]
      Front Right: Playback 71 [60%] [-23.50dB]
    Simple mixer control 'Line Line2 Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'Line PGA Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'Mono',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Mono DAC',0
      Capabilities: pvolume penum
      Playback channels: Front Left - Front Right
      Limits: Playback 0 - 118
      Mono:
      Front Left: Playback 71 [60%] [-23.50dB]
      Front Right: Playback 71 [60%] [-23.50dB]
    Simple mixer control 'Mono Line2 Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'Mono Mixer DACL1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Mono Mixer DACR1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Mono Mixer Line2L Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Mono Mixer Line2R Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Mono Mixer PGAL Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Mono Mixer PGAR Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Mono PGA Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'ADC HPF Cut-off',0
      Capabilities: enum
      Items: 'Disabled' '0.0045xFs' '0.0125xFs' '0.025xFs'
      Item0: 'Disabled'
      Item1: 'Disabled'
    Simple mixer control 'AGC',0
      Capabilities: pswitch penum
      Playback channels: Front Left - Front Right
      Mono:
      Front Left: Playback [off]
      Front Right: Playback [off]
    Simple mixer control 'HP',0
      Capabilities: pswitch penum
      Playback channels: Front Left - Front Right
      Mono:
      Front Left: Playback [on]
      Front Right: Playback [on]
    Simple mixer control 'HP DAC',0
      Capabilities: pvolume penum
      Playback channels: Front Left - Front Right
      Limits: Playback 0 - 118
      Mono:
      Front Left: Playback 71 [60%] [-23.50dB]
      Front Right: Playback 71 [60%] [-23.50dB]
    Simple mixer control 'HP Line2 Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'HP PGA Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'HPCOM',0
      Capabilities: pswitch penum
      Playback channels: Front Left - Front Right
      Mono:
      Front Left: Playback [on]
      Front Right: Playback [on]
    Simple mixer control 'HPCOM DAC',0
      Capabilities: pvolume penum
      Playback channels: Front Left - Front Right
      Limits: Playback 0 - 118
      Mono:
      Front Left: Playback 71 [60%] [-23.50dB]
      Front Right: Playback 71 [60%] [-23.50dB]
    Simple mixer control 'HPCOM Line2 Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'HPCOM PGA Bypass',0
      Capabilities: volume penum
      Playback channels: Front Left - Front Right
      Capture channels: Front Left - Front Right
      Limits: 0 - 118
      Front Left: 71 [60%] [-23.50dB]
      Front Right: 71 [60%] [-23.50dB]
    Simple mixer control 'Left DAC Mux',0
      Capabilities: enum
      Items: 'DAC_L1' 'DAC_L3' 'DAC_L2'
      Item0: 'DAC_L1'
    Simple mixer control 'Left HP Mixer DACL1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Left HP Mixer DACR1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Left HP Mixer Line2L Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left HP Mixer Line2R Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left HP Mixer PGAL Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left HP Mixer PGAR Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left HPCOM Mixer DACL1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Left HPCOM Mixer DACR1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Left HPCOM Mixer Line2L Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left HPCOM Mixer Line2R Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left HPCOM Mixer PGAL Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left HPCOM Mixer PGAR Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left HPCOM Mux',0
      Capabilities: enum
      Items: 'differential of HPLOUT' 'constant VCM' 'single-ended'
      Item0: 'differential of HPLOUT'
    Simple mixer control 'Left Line Mixer DACL1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Left Line Mixer DACR1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Left Line Mixer Line2L Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left Line Mixer Line2R Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left Line Mixer PGAL Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left Line Mixer PGAR Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Left Line1L Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Left Line1R Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Left Line2L Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Left PGA Mixer Line1L',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Left PGA Mixer Line1R',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left PGA Mixer Line2L',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left PGA Mixer Mic3L',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Left PGA Mixer Mic3R',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'PGA',0
      Capabilities: cvolume cswitch penum
      Capture channels: Front Left - Front Right
      Limits: Capture 0 - 119
      Front Left: Capture 32 [27%] [16.00dB] [on]
      Front Right: Capture 32 [27%] [16.00dB] [on]
    Simple mixer control 'Right DAC Mux',0
      Capabilities: enum
      Items: 'DAC_R1' 'DAC_R3' 'DAC_R2'
      Item0: 'DAC_R1'
    Simple mixer control 'Right HP Mixer DACL1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Right HP Mixer DACR1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Right HP Mixer Line2L Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Right HP Mixer Line2R Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right HP Mixer PGAL Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Right HP Mixer PGAR Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right HPCOM Mixer DACL1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Right HPCOM Mixer DACR1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Right HPCOM Mixer Line2L Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Right HPCOM Mixer Line2R Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right HPCOM Mixer PGAL Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Right HPCOM Mixer PGAR Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right HPCOM Mux',0
      Capabilities: enum
      Items: 'differential of HPROUT' 'constant VCM' 'single-ended' 'differential of HPLCOM' 'external feedback'
      Item0: 'differential of HPROUT'
    Simple mixer control 'Right Line Mixer DACL1',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback 0 - 118
      Mono: Playback 118 [100%] [0.00dB] [off]
    Simple mixer control 'Right Line Mixer DACR1',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Right Line Mixer Line2L Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [off]
    Simple mixer control 'Right Line Mixer Line2R Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right Line Mixer PGAL Bypass',0
      Capabilities: volume volume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Capture channels: Mono
      Limits: 0 - 118
      Mono: 118 [100%] [0.00dB] Playback [on]
    Simple mixer control 'Right Line Mixer PGAR Bypass',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right Line1L Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Right Line1R Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Right Line2R Mux',0
      Capabilities: enum
      Items: 'single-ended' 'differential'
      Item0: 'single-ended'
    Simple mixer control 'Right PGA Mixer Line1L',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right PGA Mixer Line1R',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [on]
    Simple mixer control 'Right PGA Mixer Line2R',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right PGA Mixer Mic3L',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    Simple mixer control 'Right PGA Mixer Mic3R',0
      Capabilities: pswitch pswitch-joined penum
      Playback channels: Mono
      Mono: Playback [off]
    root@localhost:/#
     

    Can you say commenting the regulator functions in codec driver is ok?.

    Regards

    Punith

  • Hi Patrick .

    Here will be my output for amixer

    root@localhost:/# amixer -c 2 sset 'HP Right' on
    amixer: Unable to find simple control 'HP Right',0

    i am getting same thing for all

    Is i need to do any modification in machine driver?.

     Can you commenting regulator function in codec driver is ok?

    Regards

    Punith

  • Hi Patrick,

    For TLV320AIC3100 chip set which codec driver we need to use either tlv320aic3x.c or tlv320aic31xx.c?.

    Regards

    Punith

  • Hello Punith,

    I have used the tvl320aic3111 driver available in the AM43x-EPOS-EVM. The tlv320aic3x didn't work for me.

    In the dts file I have the following additional:

    / { 

      sound {

            compatible = "ti,am43xx-epos-evm-audio";

            ti,model = "AM43x-EPOS-EVM";

            ti,audio-codec = <&tlv320aic3111>;

            ti,mcasp-controller = <&mcasp0>;

            ti,codec-clock-rate = <12000000>;

           ti,audio-routing =

            "Speaker",  "SPL",

            "Speaker",  "SPR",

           "Headphone Jack",  "HPL",

           "Headphone Jack",  "HPR",

           "MIC1LP",  "Mic Jack",

           "MIC1RP",  "Mic Jack";

          };

    }

    When i type: amixer sset 'HP Right' on my reaction is correct:

    Simple mixer control 'HP Right',0
    Capabilities: pswitch pswitch-joined
    Playback channels: Mono
    Mono: Playback [on]

    Kind regards

    Patrick

  • Hi Patrick,

    amixer -c 2 sset 'Left HP Mixer DACL1' on               # HP Left route enable
    amixer -c 2 sset 'Right HP Mixer DACR1' on              # HP Right route enable
    amixer -c 2 sset 'Left Line Mixer DACL1' off            # Line out Left disable
    amixer -c 2 sset 'Right Line Mixer DACR1' off           # Line out Right disable
    amixer -c 2 sset 'HP DAC' 90                             # Adjust HP volume

    This section works for me. It means there is no problem in audio routing but i am not getting any
    audio from HPL and HPR line , i checked by probing the lines.
    Regards
    Punith

  • Hello Punith

    Could you try: 

    amixer sset 'DAC' 127
    amixer sset 'HP Analog' 66
    amixer sset 'HP Driver' 0 on
    amixer sset 'HP Left' on
    amixer sset 'HP Right' on
    amixer sset 'Output Left From Left DAC' on
    amixer sset 'Output Right From Right DAC' on

    Here you see that the HP Driver / Analog must be put on

    regards
    Patrick
  • Hi Patrick,

    All statements are saying  amixer: Unable to find simple control ...

    I am using Alllwinner A20 custom board.

    Is the instructions are same for all boards?.

    One more question.

    i am commented all regulator function in tlv320aic3x driver because i am getting all voltages in hardware?

    is it a Problem to not get audio?.


    Regards

    Punith

  • Hello Punith,

    The instruction I have used are with TI Linux SDK, but I would advise not to use the tlv320aic3x driver, but the tlv320aic31x driver. 

    I had also problems with tlv320aic3x driver and the tlv320aic31x driver worked for me.

    For the voltages I believe(i'm not sure, maybe somebody from TI could confirm this) you shouldn't do that.

    But you getting audio from the speakers, but  not from the headphone? How is the voltage supplied to the headpohone drivers?

    Regards

    Patrick

  • Hi Patrick,

    I dont have any speaker in my board, we are just taking HPL and HPR line from codec and passing to single to line through some registers and capacitors.

    I probed both lines but not getting any signals on the lines.

    From console audio is playing fine but not getting any analog signal from board.

    i dont have any driver like tlv320aic31x , can you share the driver?.

    i think commenting regulators is not an issue since i have all voltages in hardware.

    i also checked in codec part , it is able to write and read the registers.

    if you want , i will share machine driver code.

    Kindly let me know what will be an issue.

    Regards

    Punith

  • Hello Punith

    The driver (source code) is from Ti self, see attachment.

    /*
     * ALSA SoC TLV320AIC31XX codec driver
     *
     * Copyright (C) 2013 Texas Instruments, Inc.
     *
     * Author: Jyri Sarha <jsarha@ti.com>
     *
     * Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
     *
     * This package 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 PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
     * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     *
     * The TLV320AIC31xx series of audio codec is a low-power, highly integrated
     * high performance codec which provides a stereo DAC, a mono ADC,
     * and mono/stereo Class-D speaker driver.
     */
    
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/pm.h>
    #include <linux/i2c.h>
    #include <linux/gpio.h>
    #include <linux/regulator/consumer.h>
    #include <linux/of_gpio.h>
    #include <linux/slab.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/pcm_params.h>
    #include <sound/soc.h>
    #include <sound/initval.h>
    #include <sound/tlv.h>
    
    #include "tlv320aic31xx.h"
    
    static const struct regmap_range_cfg aic31xx_ranges[] = {
    	{
    		.name = "codec-regmap",
    		.range_min = 128,
    		.range_max = 13 * 128,
    		.selector_reg = 0,
    		.selector_mask = 0xff,
    		.selector_shift = 0,
    		.window_start = 0,
    		.window_len = 128,
    	},
    };
    
    struct regmap_config aicxxx_i2c_regmap = {
    	.reg_bits = 8,
    	.val_bits = 8,
    	.cache_type = REGCACHE_NONE,
    	.ranges = aic31xx_ranges,
    	.num_ranges = ARRAY_SIZE(aic31xx_ranges),
    	.max_register =	 13 * 128,
    };
    
    #define AIC31XX_NUM_SUPPLIES	6
    static const char * const aic31xx_supply_names[] = {
    	"HPVDD",
    	"SPRVDD",
    	"SPLVDD",
    	"AVDD",
    	"IOVDD",
    	"DVDD",
    };
    
    struct aic31xx_disable_nb {
    	struct notifier_block nb;
    	struct aic31xx_priv *aic31xx;
    };
    
    struct aic31xx_priv {
    	struct snd_soc_codec *codec;
    	u8 i2c_regs_status;
    	struct device *dev;
    	struct regmap *regmap;
    	struct aic31xx_pdata pdata;
    	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
    	struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
    	int power;
    	unsigned int sysclk;
    };
    
    struct aic31xx_rate_divs {
    	u32 mclk;
    	u32 rate;
    	u8 p_val;
    	u8 pll_j;
    	u16 pll_d;
    	u16 dosr;
    	u8 ndac;
    	u8 mdac;
    	u8 aosr;
    	u8 nadc;
    	u8 madc;
    	u8 bclk_n;
    };
    
    static const struct aic31xx_rate_divs aic31xx_divs[] = {
    	/* mclk	   rate	  p  j	   d dosr  nd md aors  na  ma blck_n */
    	/* 8k rate */
    	{12000000, 8000,  1, 7, 6800, 768,  5, 3, 128,	5, 18, 24},
    	{24000000, 8000,  2, 7, 6800, 768, 15, 1,  64, 45,  4, 24},
    	{25000000, 8000,  2, 7, 3728, 768, 15, 1,  64, 45,  4, 24},
    	/* 11.025k rate */
    	{12000000, 11025, 1, 7, 5264, 512,  8, 2, 128,	8,  8, 16},
    	{24000000, 11025, 2, 7, 5264, 512, 16, 1,  64, 32,  4, 16},
    	/* 16k rate */
    	{12000000, 16000, 1, 7, 6800, 384,  5, 3, 128,	5,  9, 12},
    	{24000000, 16000, 2, 7, 6800, 384, 15, 1,  64, 18,  5, 12},
    	{25000000, 16000, 2, 7, 3728, 384, 15, 1,  64, 18,  5, 12},
    	/* 22.05k rate */
    	{12000000, 22050, 1, 7, 5264, 256,  4, 4, 128,	4,  8,	8},
    	{24000000, 22050, 2, 7, 5264, 256, 16, 1,  64, 16,  4,	8},
    	{25000000, 22050, 2, 7, 2253, 256, 16, 1,  64, 16,  4,	8},
    	/* 32k rate */
    	{12000000, 32000, 1, 7, 1680, 192,  2, 7,  64,	2, 21,	6},
    	{24000000, 32000, 2, 7, 1680, 192,  7, 2,  64,	7,  6,	6},
    	/* 44.1k rate */
    	{12000000, 44100, 1, 7, 5264, 128,  2, 8, 128,	2,  8,	4},
    	{24000000, 44100, 2, 7, 5264, 128,  8, 2,  64,	8,  4,	4},
    	{25000000, 44100, 2, 7, 2253, 128,  8, 2,  64,	8,  4,	4},
    	/* 48k rate */
    	{12000000, 48000, 1, 8, 1920, 128,  2, 8, 128,	2,  8,	4},
    	{24000000, 48000, 2, 8, 1920, 128,  8, 2,  64,	8,  4,	4},
    	{25000000, 48000, 2, 7, 8643, 128,  8, 2,  64,	8,  4,	4},
    };
    
    static const char * const ldac_in_text[] = {
    	"off", "Left Data", "Right Data", "Mono"
    };
    
    static const char * const rdac_in_text[] = {
    	"off", "Right Data", "Left Data", "Mono"
    };
    
    static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text);
    
    static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text);
    
    static const char * const mic_select_text[] = {
    	"off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm"
    };
    
    static const
    SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6, mic_select_text);
    static const
    SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, mic_select_text);
    static const
    SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text);
    
    static const
    SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
    static const
    SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text);
    
    static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
    static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
    static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
    static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0);
    static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0);
    static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0);
    static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0);
    static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
    
    /*
     * controls to be exported to the user space
     */
    static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
    	/* DAC Volume Control*/
    	SOC_DOUBLE_R_SX_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
    			    AIC31XX_RDACVOL, 0, 0x81, 0xaf, dac_vol_tlv),
    	/* HP driver mute control */
    	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
    		     AIC31XX_HPRGAIN, 2, 1, 0),
    
    	/* ADC FINE GAIN */
    	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
    		       adc_fgain_tlv),
    
    	/* ADC mute control */
    	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
    
    	/* ADC COARSE GAIN */
    	SOC_DOUBLE_R_SX_TLV("ADC Capture Volume", AIC31XX_ADCVOL,
    			    AIC31XX_ADCVOL,	0, 0x28, 0x40,
    			    adc_cgain_tlv),
    	/* ADC MIC PGA GAIN */
    	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
    		       119, 0, mic_pga_tlv),
    
    	/* HP driver Volume Control */
    	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
    			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
    	/* Left DAC input selection control */
    
    	/* Throughput of 7-bit vol ADC for pin control */
    	/* HP Analog Gain Volume Control */
    	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
    			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
    };
    
    static const struct snd_kcontrol_new aic311x_snd_controls[] = {
    	/* SP Class-D driver output stage gain Control */
    	SOC_DOUBLE_R_TLV("SP Driver Playback Volume", AIC31XX_SPLGAIN,
    			 AIC31XX_SPRGAIN, 3, 0x04, 0, class_D_drv_tlv),
    	/* SP Analog Gain Volume Control */
    	SOC_DOUBLE_R_TLV("SP Analog Playback Volume", AIC31XX_LANALOGSPL,
    			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
    	/* SP driver mute control */
    	SOC_DOUBLE_R("SP Driver Playback Switch", AIC31XX_SPLGAIN,
    		     AIC31XX_SPRGAIN, 2, 1, 0),
    };
    
    static const struct snd_kcontrol_new aic310x_snd_controls[] = {
    	/* SP Class-D driver output stage gain Control */
    	SOC_SINGLE_TLV("SP Driver Playback Volume", AIC31XX_SPLGAIN,
    		       3, 0x04, 0, class_D_drv_tlv),
    	/* SP Analog Gain Volume Control */
    	SOC_SINGLE_TLV("SP Analog Playback Volume", AIC31XX_LANALOGSPL,
    		       0, 0x7F, 1, sp_vol_tlv),
    	SOC_SINGLE("SP Driver Playback Switch", AIC31XX_SPLGAIN,
    		   2, 1, 0),
    };
    
    static const struct snd_kcontrol_new ldac_in_control =
    	SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum);
    
    static const struct snd_kcontrol_new rdac_in_control =
    	SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
    
    int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
    		      unsigned int mask, unsigned int wbits, int sleep,
    		      int count)
    {
    	unsigned int bits;
    	int counter = count;
    	int ret = regmap_read(aic31xx->regmap, reg, &bits);
    	while ((bits & mask) != wbits && counter && !ret) {
    		usleep_range(sleep, sleep * 2);
    		ret = regmap_read(aic31xx->regmap, reg, &bits);
    		counter--;
    	}
    	if ((bits & mask) != wbits) {
    		dev_err(aic31xx->dev,
    			"%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n",
    			__func__, reg, bits, wbits, ret, mask,
    			(count - counter) * sleep);
    		ret = -1;
    	}
    	return ret;
    }
    
    static int aic31xx_power_up_event(struct snd_soc_dapm_widget *w,
    				  struct snd_kcontrol *kcontrol, int event)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
    	unsigned int reg = AIC31XX_DACFLAG1;
    	unsigned int mask;
    
    	if (!strcmp(w->name, "DAC Left")) {
    		mask = AIC31XX_LDACPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "DAC Right")) {
    		mask = AIC31XX_RDACPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "HPL Driver")) {
    		mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "HPR Driver")) {
    		mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "SPL ClassD") ||
    		   !strcmp(w->name, "SPK ClassD")) {
    		mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "SPR ClassD")) {
    		mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
    	} else if (!strcmp(w->name, "ADC")) {
    		mask = AIC31XX_ADCPWRSTATUS_MASK;
    		reg = AIC31XX_ADCFLAG;
    	} else {
    		dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
    			w->name, __func__);
    		return -1;
    	}
    
    	if (event == SND_SOC_DAPM_POST_PMU)
    		return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
    	else if (event == SND_SOC_DAPM_POST_PMD)
    		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
    
    	dev_dbg(w->codec->dev, "Unhandled dapm widget event %d from %s\n",
    		event, w->name);
    	return 0;
    }
    
    static const struct snd_kcontrol_new left_output_switches[] = {
    	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
    	SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
    	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
    };
    
    static const struct snd_kcontrol_new right_output_switches[] = {
    	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
    	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
    };
    
    static const struct snd_kcontrol_new p_term_mic1lp =
    	SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
    
    static const struct snd_kcontrol_new p_term_mic1rp =
    	SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum);
    
    static const struct snd_kcontrol_new p_term_mic1lm =
    	SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum);
    
    static const struct snd_kcontrol_new m_term_cm =
    	SOC_DAPM_ENUM("CM M-Terminal", cm_m_enum);
    
    static const struct snd_kcontrol_new m_term_mic1lm =
    	SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum);
    
    static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch =
    	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0);
    
    static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch =
    	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0);
    
    static const struct snd_kcontrol_new aic31xx_dapm_spl_switch =
    	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0);
    
    static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
    	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0);
    
    static int pll_power_on_event(struct snd_soc_dapm_widget *w,
    			      struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_codec *codec = w->codec;
    
    	if (SND_SOC_DAPM_EVENT_ON(event))
    		dev_dbg(codec->dev, "pll->on pre_pmu");
    	else if (SND_SOC_DAPM_EVENT_OFF(event))
    		dev_dbg(codec->dev, "pll->off\n");
    
    	mdelay(10);
    	return 0;
    }
    
    static int mic_bias_event(struct snd_soc_dapm_widget *w,
    			  struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_codec *codec = w->codec;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMU:
    		/* change mic bias voltage to user defined */
    		if (aic31xx->pdata.micbias_vg != AIC31XX_MICBIAS_OFF) {
    			snd_soc_update_bits(codec, AIC31XX_MICBIAS,
    					    AIC31XX_MICBIAS_MASK,
    					    aic31xx->pdata.micbias_vg <<
    					    AIC31XX_MICBIAS_SHIFT);
    			dev_dbg(codec->dev, "%s: turned on\n", __func__);
    		}
    		break;
    	case SND_SOC_DAPM_PRE_PMD:
    		if (aic31xx->pdata.micbias_vg != AIC31XX_MICBIAS_OFF) {
    			snd_soc_update_bits(codec, AIC31XX_MICBIAS,
    					    AIC31XX_MICBIAS_MASK, 0);
    			dev_dbg(codec->dev, "%s: turned off\n", __func__);
    		}
    		break;
    	}
    	return 0;
    }
    
    static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
    	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
    
    	SND_SOC_DAPM_MUX("DAC Left Input",
    			 SND_SOC_NOPM, 0, 0, &ldac_in_control),
    	SND_SOC_DAPM_MUX("DAC Right Input",
    			 SND_SOC_NOPM, 0, 0, &rdac_in_control),
    	/* DACs */
    	SND_SOC_DAPM_DAC_E("DAC Left", "DAC Left Input",
    			   AIC31XX_DACSETUP, 7, 0, aic31xx_power_up_event,
    			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
    
    	SND_SOC_DAPM_DAC_E("DAC Right", "DAC Right Input",
    			   AIC31XX_DACSETUP, 6, 0, aic31xx_power_up_event,
    			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
    
    	/* Output Mixers */
    	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
    			   left_output_switches,
    			   ARRAY_SIZE(left_output_switches)),
    	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
    			   right_output_switches,
    			   ARRAY_SIZE(right_output_switches)),
    
    	SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_hpl_switch),
    	SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_hpr_switch),
    
    	/* Output drivers */
    	SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0,
    			       NULL, 0, aic31xx_power_up_event,
    			       SND_SOC_DAPM_POST_PMU),
    	SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
    			       NULL, 0, aic31xx_power_up_event,
    			       SND_SOC_DAPM_POST_PMU),
    
    	/* ADC */
    	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
    			   aic31xx_power_up_event, SND_SOC_DAPM_POST_PMU |
    			   SND_SOC_DAPM_POST_PMD),
    
    	/* Input Selection to MIC_PGA */
    	SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
    			 &p_term_mic1lp),
    	SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0,
    			 &p_term_mic1rp),
    	SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
    			 &p_term_mic1lm),
    
    	SND_SOC_DAPM_MUX("CM M-Terminal", SND_SOC_NOPM, 0, 0, &m_term_cm),
    	SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
    			 &m_term_mic1lm),
    	/* Enabling & Disabling MIC Gain Ctl */
    	SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
    			 7, 1, NULL, 0),
    
    	SND_SOC_DAPM_SUPPLY("PLLCLK", AIC31XX_PLLPR, 7, 0, pll_power_on_event,
    			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_SUPPLY("BCLKN_DIV", AIC31XX_BCLKN, 7, 0, NULL, 0),
    	SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
    	SND_SOC_DAPM_SUPPLY("NDAC_DIV", AIC31XX_NDAC, 7, 0, NULL, 0),
    	SND_SOC_DAPM_SUPPLY("MDAC_DIV", AIC31XX_MDAC, 7, 0, NULL, 0),
    	SND_SOC_DAPM_SUPPLY("NADC_DIV", AIC31XX_NADC, 7, 0, NULL, 0),
    	SND_SOC_DAPM_SUPPLY("MADC_DIV", AIC31XX_MADC, 7, 0, NULL, 0),
    
    	/* Mic Bias */
    	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
    			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    
    	/* Outputs */
    	SND_SOC_DAPM_OUTPUT("HPL"),
    	SND_SOC_DAPM_OUTPUT("HPR"),
    
    	/* Inputs */
    	SND_SOC_DAPM_INPUT("MIC1LP"),
    	SND_SOC_DAPM_INPUT("MIC1RP"),
    	SND_SOC_DAPM_INPUT("MIC1LM"),
    };
    
    static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
    	/* For AIC31XX and AIC3110 as it is stereo both left and right channel
    	 * class-D can be powered up/down
    	 */
    	SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
    			       aic31xx_power_up_event, SND_SOC_DAPM_POST_PMU |
    			       SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
    			       aic31xx_power_up_event, SND_SOC_DAPM_POST_PMU |
    			       SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_SWITCH("SP Left", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_spl_switch),
    	SND_SOC_DAPM_SWITCH("SP Right", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_spr_switch),
    	SND_SOC_DAPM_OUTPUT("SPL"),
    	SND_SOC_DAPM_OUTPUT("SPR"),
    };
    
    static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
    	SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
    			       aic31xx_power_up_event, SND_SOC_DAPM_POST_PMU |
    			       SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_spl_switch),
    	SND_SOC_DAPM_OUTPUT("SPK"),
    };
    
    static const struct snd_soc_dapm_route
    aic31xx_audio_map[] = {
    	{"CODEC_CLK_IN", NULL, "PLLCLK"},
    	{"CODEC_CLK_IN", NULL, "BCLKN_DIV"},
    	{"CODEC_CLK_IN", NULL, "NDAC_DIV"},
    	{"CODEC_CLK_IN", NULL, "NADC_DIV"},
    	{"CODEC_CLK_IN", NULL, "MDAC_DIV"},
    	{"CODEC_CLK_IN", NULL, "MADC_DIV"},
    
    	/* Clocks for ADC */
    	{"ADC", NULL, "CODEC_CLK_IN"},
    
    	/* DAC Input Routing */
    	{"DAC Left Input", "Left Data", "DAC IN"},
    	{"DAC Left Input", "Right Data", "DAC IN"},
    	{"DAC Left Input", "Mono", "DAC IN"},
    	{"DAC Right Input", "Left Data", "DAC IN"},
    	{"DAC Right Input", "Right Data", "DAC IN"},
    	{"DAC Right Input", "Mono", "DAC IN"},
    	{"DAC Left", NULL, "DAC Left Input"},
    	{"DAC Right", NULL, "DAC Right Input"},
    
    	/* Mic input */
    	{"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
    	{"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
    	{"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"},
    	{"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"},
    	{"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"},
    	{"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"},
    	{"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"},
    	{"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"},
    	{"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"},
    
    	{"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"},
    	{"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"},
    	{"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"},
    
    	{"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"},
    	{"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"},
    	{"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"},
    	{"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"},
    
    	{"ADC", NULL, "MIC_GAIN_CTL"},
    	{"MIC_GAIN_CTL", NULL, "Mic Bias"},
    
    	/* Clocks for DAC */
    	{"DAC Left", NULL, "CODEC_CLK_IN" },
    	{"DAC Right", NULL, "CODEC_CLK_IN"},
    
    	/* Left Output */
    	{"Output Left", "From Left DAC", "DAC Left"},
    	{"Output Left", "From MIC1LP", "MIC1LP"},
    	{"Output Left", "From MIC1RP", "MIC1RP"},
    
    	/* Right Output */
    	{"Output Right", "From Right DAC", "DAC Right"},
    	{"Output Right", "From MIC1RP", "MIC1RP"},
    
    	/* HPL path */
    	{"HP Left", "Switch", "Output Left"},
    	{"HPL Driver", NULL, "HP Left"},
    	{"HPL", NULL, "HPL Driver"},
    
    	/* HPR path */
    	{"HP Right", "Switch", "Output Right"},
    	{"HPR Driver", NULL, "HP Right"},
    	{"HPR", NULL, "HPR Driver"},
    };
    
    static const struct snd_soc_dapm_route
    aic311x_audio_map[] = {
    	/* SP L path */
    	{"SP Left", "Switch", "Output Left"},
    	{"SPL ClassD", NULL, "SP Left"},
    	{"SPL", NULL, "SPL ClassD"},
    
    	/* SP R path */
    	{"SP Right", "Switch", "Output Right"},
    	{"SPR ClassD", NULL, "SP Right"},
    	{"SPR", NULL, "SPR ClassD"},
    };
    
    static const struct snd_soc_dapm_route
    aic310x_audio_map[] = {
    	/* SP L path */
    	{"Speaker", "Switch", "Output Left"},
    	{"SPK ClassD", NULL, "Speaker"},
    	{"SPK", NULL, "SPK ClassD"},
    };
    
    static int aic31xx_add_controls(struct snd_soc_codec *codec)
    {
    	int err = 0;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    
    	if (aic31xx->pdata.codec_type == AIC311X) {
    		err = snd_soc_add_codec_controls(
    			codec, aic311x_snd_controls,
    			ARRAY_SIZE(aic311x_snd_controls));
    		if (err < 0)
    			dev_dbg(codec->dev, "Invalid control\n");
    
    	} else if (aic31xx->pdata.codec_type == AIC310X) {
    		err = snd_soc_add_codec_controls(
    			codec, aic310x_snd_controls,
    			ARRAY_SIZE(aic310x_snd_controls));
    		if (err < 0)
    			dev_dbg(codec->dev, "Invalid Control\n");
    	}
    	return 0;
    }
    
    static int aic31xx_add_widgets(struct snd_soc_codec *codec)
    {
    	struct snd_soc_dapm_context *dapm = &codec->dapm;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int ret = 0;
    
    	if (aic31xx->pdata.codec_type == AIC311X) {
    		ret = snd_soc_dapm_new_controls(
    			dapm, aic311x_dapm_widgets,
    			ARRAY_SIZE(aic311x_dapm_widgets));
    		if (ret)
    			dev_err(codec->dev,
    				"Adding %d dapm widgets failed: %d\n",
    				ARRAY_SIZE(aic311x_dapm_widgets), ret);
    		ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
    					      ARRAY_SIZE(aic311x_audio_map));
    		if (ret)
    			dev_err(codec->dev,
    				"Adding %d DAPM routes failed: %d\n",
    				ARRAY_SIZE(aic311x_audio_map), ret);
    	} else if (aic31xx->pdata.codec_type == AIC310X) {
    		ret = snd_soc_dapm_new_controls(
    			dapm, aic310x_dapm_widgets,
    			ARRAY_SIZE(aic310x_dapm_widgets));
    		if (ret)
    			dev_err(codec->dev,
    				"Adding %d dapm widgets failed: %d\n",
    				ARRAY_SIZE(aic310x_dapm_widgets), ret);
    		ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
    					      ARRAY_SIZE(aic310x_audio_map));
    		if (ret)
    			dev_err(codec->dev,
    				"Adding %d DAPM routes failed: %d\n",
    				ARRAY_SIZE(aic310x_audio_map), ret);
    	}
    
    	return 0;
    }
    
    static int aic31xx_hw_params(struct snd_pcm_substream *substream,
    			     struct snd_pcm_hw_params *params,
    			     struct snd_soc_dai *tmp)
    {
    	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    	struct snd_soc_codec *codec = rtd->codec;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	u8 data = 0;
    	int i;
    
    	dev_dbg(codec->dev, "## %s: format %d rate %d\n",
    		__func__, params_format(params), params_rate(params));
    
    	switch (params_format(params)) {
    	case SNDRV_PCM_FORMAT_S16_LE:
    		break;
    	case SNDRV_PCM_FORMAT_S20_3LE:
    		data = (AIC31XX_WORD_LEN_20BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    		break;
    	case SNDRV_PCM_FORMAT_S24_3LE:
    		data = (AIC31XX_WORD_LEN_24BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    		break;
    	case SNDRV_PCM_FORMAT_S32_LE:
    		data = (AIC31XX_WORD_LEN_32BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    	break;
    	}
    
    	snd_soc_update_bits(codec, AIC31XX_IFACE1,
    			    AIC31XX_IFACE1_DATALEN_MASK,
    			    data);
    
    	/* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
    	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
    			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
    	snd_soc_update_bits(codec, AIC31XX_IFACE2, AIC31XX_BDIVCLK_MASK,
    			    AIC31XX_DACMOD2BCLK);
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
    		if ((aic31xx_divs[i].rate == params_rate(params))
    		    && (aic31xx_divs[i].mclk == aic31xx->sysclk)) {
    			break;
    		}
    	}
    
    	if (i == ARRAY_SIZE(aic31xx_divs)) {
    		dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
    			__func__, params_rate(params));
    		return -EINVAL;
    	}
    
    	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
    			    (aic31xx_divs[i].p_val << 4) | 0x01);
    	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
    
    	snd_soc_write(codec, AIC31XX_PLLDMSB, (aic31xx_divs[i].pll_d >> 8));
    	snd_soc_write(codec, AIC31XX_PLLDLSB,
    		      (aic31xx_divs[i].pll_d & 0xff));
    
    	/* NDAC divider value */
    	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].ndac);
    
    	/* MDAC divider value */
    	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].mdac);
    
    	/* DOSR MSB & LSB values */
    	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
    	snd_soc_write(codec, AIC31XX_DOSRLSB,
    		      (aic31xx_divs[i].dosr & 0xff));
    	/* NADC divider value */
    	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].nadc);
    	/* MADC divider value */
    	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].madc);
    	/* AOSR value */
    	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
    	/* BCLK N divider */
    	snd_soc_update_bits(codec, AIC31XX_BCLKN, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].bclk_n);
    
    	return 0;
    }
    
    static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
    {
    	struct snd_soc_codec *codec = codec_dai->codec;
    
    	if (mute) {
    		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
    				    AIC31XX_DACMUTE_MASK,
    				    AIC31XX_DACMUTE_MASK);
    	} else {
    		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
    				    AIC31XX_DACMUTE_MASK, 0x0);
    	}
    
    	return 0;
    }
    
    static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
    			       unsigned int fmt)
    {
    	struct snd_soc_codec *codec = codec_dai->codec;
    	u8 iface_reg1 = 0;
    	u8 iface_reg3 = 0;
    	u8 dsp_a_val = 0;
    
    	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
    
    	/* set master/slave audio interface */
    	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    	case SND_SOC_DAIFMT_CBM_CFM:
    		iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
    		break;
    	case SND_SOC_DAIFMT_CBS_CFS:
    		iface_reg1 &= ~(AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER);
    		break;
    	case SND_SOC_DAIFMT_CBS_CFM:
    		iface_reg1 |= AIC31XX_BCLK_MASTER;
    		iface_reg1 &= ~(AIC31XX_WCLK_MASTER);
    		break;
    	default:
    		dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
    		return -EINVAL;
    	}
    	/* interface format */
    	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    	case SND_SOC_DAIFMT_I2S:
    		break;
    	case SND_SOC_DAIFMT_DSP_A:
    		dsp_a_val = 0x1;
    	case SND_SOC_DAIFMT_DSP_B:
    		/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
    		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    		case SND_SOC_DAIFMT_NB_NF:
    			iface_reg3 |= AIC31XX_BCLKINV_MASK;
    			break;
    		case SND_SOC_DAIFMT_IB_NF:
    			break;
    		default:
    			return -EINVAL;
    		}
    		iface_reg1 |= (AIC31XX_DSP_MODE <<
    			       AIC31XX_IFACE1_DATATYPE_SHIFT);
    		break;
    	case SND_SOC_DAIFMT_RIGHT_J:
    		iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
    			       AIC31XX_IFACE1_DATATYPE_SHIFT);
    		break;
    	case SND_SOC_DAIFMT_LEFT_J:
    		iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
    			       AIC31XX_IFACE1_DATATYPE_SHIFT);
    		break;
    	default:
    		dev_err(codec->dev, "Invalid DAI interface format\n");
    		return -EINVAL;
    	}
    
    	snd_soc_update_bits(codec, AIC31XX_IFACE1,
    			    AIC31XX_IFACE1_DATATYPE_MASK |
    			    AIC31XX_IFACE1_MASTER_MASK,
    			    iface_reg1);
    	snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
    			    AIC31XX_DATA_OFFSET_MASK,
    			    dsp_a_val);
    	snd_soc_update_bits(codec, AIC31XX_IFACE2,
    			    AIC31XX_BCLKINV_MASK,
    			    iface_reg3);
    
    	return 0;
    }
    
    static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    				  int clk_id, unsigned int freq, int dir)
    {
    	struct snd_soc_codec *codec = codec_dai->codec;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int i;
    
    	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
    		__func__, clk_id, freq, dir);
    
    	for (i = 0; aic31xx_divs[i].mclk != freq; i++)
    		if (i == ARRAY_SIZE(aic31xx_divs)) {
    			dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
    				__func__, freq);
    			return -EINVAL;
    		}
    
    	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
    	snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
    			    clk_id << AIC31XX_PLL_CLKIN_SHIFT);
    
    	aic31xx->sysclk = freq;
    	return 0;
    }
    
    static int aic31xx_regulator_event(struct notifier_block *nb,
    				   unsigned long event, void *data)
    {
    	struct aic31xx_disable_nb *disable_nb =
    		container_of(nb, struct aic31xx_disable_nb, nb);
    	struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
    
    	if (event & REGULATOR_EVENT_DISABLE) {
    		/*
    		 * Put codec to reset and as at least one
    		 * of the supplies was disabled
    		 */
    		dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
    		if (gpio_is_valid(aic31xx->pdata.gpio_reset))
    			gpio_set_value(aic31xx->pdata.gpio_reset, 0);
    	}
    
    	return 0;
    }
    
    static int aic31xx_set_power(struct snd_soc_codec *codec, int power)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int ret;
    
    	dev_dbg(codec->dev, "## %s: %d\n", __func__, power);
    	if (power) {
    		ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
    					    aic31xx->supplies);
    		if (ret)
    			return ret;
    		aic31xx->power = 1;
    
    		if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
    			gpio_set_value(aic31xx->pdata.gpio_reset, 1);
    			mdelay(10);
    		}
    	} else {
    		/*
    		 * Do soft reset to this codec instance in order to clear
    		 * possible VDD leakage currents in case the supply regulators
    		 * remain on
    		 */
    		snd_soc_write(codec, AIC31XX_RESET, 0x01);
    		if (gpio_is_valid(aic31xx->pdata.gpio_reset))
    			gpio_set_value(aic31xx->pdata.gpio_reset, 0);
    		aic31xx->power = 0;
    		ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
    					     aic31xx->supplies);
    	}
    
    	return ret;
    }
    
    static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
    				  enum snd_soc_bias_level level)
    {
    	dev_dbg(codec->dev, "## %s: %d (current = %d)\n", __func__,
    		level, codec->dapm.bias_level);
    	if (level == codec->dapm.bias_level)
    		return 0;
    
    	switch (level) {
    	/* full On */
    	case SND_SOC_BIAS_ON:
    		/* All power is driven by DAPM system*/
    		break;
    	/* partial On */
    	case SND_SOC_BIAS_PREPARE:
    		break;
    	/* Off, with power */
    	case SND_SOC_BIAS_STANDBY:
    		aic31xx_set_power(codec, 1);
    		break;
    	/* Off, without power */
    	case SND_SOC_BIAS_OFF:
    		aic31xx_set_power(codec, 0);
    		break;
    	}
    	codec->dapm.bias_level = level;
    
    	return 0;
    }
    
    
    static int aic31xx_suspend(struct snd_soc_codec *codec)
    {
    	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
    	return 0;
    }
    
    static int aic31xx_resume(struct snd_soc_codec *codec)
    {
    	aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
    	return 0;
    }
    
    void aic31xx_device_exit(struct aic31xx_priv *aic31xx)
    {
    	if (aic31xx->pdata.gpio_reset)
    		gpio_free(aic31xx->pdata.gpio_reset);
    	regulator_bulk_free(ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies);
    }
    
    static int aic31xx_codec_probe(struct snd_soc_codec *codec)
    {
    	int ret = 0;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int i;
    
    	dev_dbg(aic31xx->dev, "## %s\n", __func__);
    
    	aic31xx = snd_soc_codec_get_drvdata(codec);
    	codec->control_data = aic31xx->regmap;
    
    	aic31xx->codec = codec;
    
    	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
    
    	if (ret != 0) {
    		dev_err(codec->dev, "snd_soc_codec_set_cache_io failed %d\n",
    			ret);
    		return ret;
    	}
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
    		aic31xx->disable_nb[i].nb.notifier_call =
    			aic31xx_regulator_event;
    		aic31xx->disable_nb[i].aic31xx = aic31xx;
    		ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
    						  &aic31xx->disable_nb[i].nb);
    		if (ret) {
    			dev_err(codec->dev,
    				"Failed to request regulator notifier: %d\n",
    				ret);
    			return ret;
    		}
    	}
    
    	/* off, with power on */
    	aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
    	aic31xx_add_controls(codec);
    	aic31xx_add_widgets(codec);
    
    	return ret;
    }
    
    static int aic31xx_codec_remove(struct snd_soc_codec *codec)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int i;
    	/* power down chip */
    	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
    		regulator_unregister_notifier(aic31xx->supplies[i].consumer,
    					      &aic31xx->disable_nb[i].nb);
    
    	return 0;
    }
    
    static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
    	.probe			= aic31xx_codec_probe,
    	.remove			= aic31xx_codec_remove,
    	.suspend		= aic31xx_suspend,
    	.resume			= aic31xx_resume,
    	.set_bias_level		= aic31xx_set_bias_level,
    	.controls		= aic31xx_snd_controls,
    	.num_controls		= ARRAY_SIZE(aic31xx_snd_controls),
    	.dapm_widgets		= aic31xx_dapm_widgets,
    	.num_dapm_widgets	= ARRAY_SIZE(aic31xx_dapm_widgets),
    	.dapm_routes		= aic31xx_audio_map,
    	.num_dapm_routes	= ARRAY_SIZE(aic31xx_audio_map),
    };
    
    static struct snd_soc_dai_ops aic31xx_dai_ops = {
    	.hw_params	= aic31xx_hw_params,
    	.set_sysclk	= aic31xx_set_dai_sysclk,
    	.set_fmt	= aic31xx_set_dai_fmt,
    	.digital_mute	= aic31xx_dac_mute,
    };
    
    static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
    	{
    		.name = "tlv320aic31xx-hifi",
    		.playback = {
    			.stream_name	 = "Playback",
    			.channels_min	 = 1,
    			.channels_max	 = 2,
    			.rates		 = AIC31XX_RATES,
    			.formats	 = AIC31XX_FORMATS,
    		},
    		.capture = {
    			.stream_name	 = "Capture",
    			.channels_min	 = 1,
    			.channels_max	 = 2,
    			.rates		 = AIC31XX_RATES,
    			.formats	 = AIC31XX_FORMATS,
    		},
    		.ops = &aic31xx_dai_ops,
    	}
    };
    
    #if defined(CONFIG_OF)
    static const struct of_device_id tlv320aic31xx_of_match[] = {
    	{ .compatible = "ti,tlv320aic310x" },
    	{ .compatible = "ti,tlv320aic311x" },
    	{},
    };
    MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
    
    static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
    {
    	struct device_node *np = aic31xx->dev->of_node;
    	unsigned int value;
    	int ret;
    
    	if (!of_property_read_u32(np, "ai31xx-micbias-vg", &value)) {
    		switch (value) {
    		case 1:
    			aic31xx->pdata.micbias_vg = AIC31XX_MICBIAS_2_0V;
    			break;
    		case 2:
    			aic31xx->pdata.micbias_vg = AIC31XX_MICBIAS_2_5V;
    			break;
    		case 3:
    			aic31xx->pdata.micbias_vg = AIC31XX_MICBIAS_AVDDV;
    			break;
    		default:
    			dev_err(aic31xx->dev,
    				"Bad ai31xx-micbias-vg value %d DT\n",
    				value);
    		case 0:
    			aic31xx->pdata.micbias_vg = AIC31XX_MICBIAS_OFF;
    		}
    	}
    
    	ret = of_get_named_gpio(np, "gpio-reset", 0);
    	if (ret > 0)
    		aic31xx->pdata.gpio_reset = ret;
    }
    #else /* CONFIG_OF */
    static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
    {
    }
    #endif /* CONFIG_OF */
    
    void aic31xx_device_init(struct aic31xx_priv *aic31xx)
    {
    	int ret, i;
    
    	dev_set_drvdata(aic31xx->dev, aic31xx);
    
    	if (dev_get_platdata(aic31xx->dev))
    		memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
    		       sizeof(aic31xx->pdata));
    	else if (aic31xx->dev->of_node)
    		aic31xx_pdata_from_of(aic31xx);
    
    	if (aic31xx->pdata.gpio_reset) {
    		ret = gpio_request_one(aic31xx->pdata.gpio_reset,
    				       GPIOF_OUT_INIT_HIGH,
    				       "aic31xx-reset-pin");
    		if (ret < 0) {
    			dev_err(aic31xx->dev, "not able to acquire gpio\n");
    			return;
    		}
    	}
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
    		aic31xx->supplies[i].supply = aic31xx_supply_names[i];
    
    	ret = devm_regulator_bulk_get(aic31xx->dev,
    				      ARRAY_SIZE(aic31xx->supplies),
    				      aic31xx->supplies);
    	if (ret != 0) {
    		dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
    		goto gpio_free;
    	}
    
    gpio_free:
    	if (aic31xx->pdata.gpio_reset)
    		gpio_free(aic31xx->pdata.gpio_reset);
    
    }
    
    static int aic31xx_i2c_probe(struct i2c_client *i2c,
    			     const struct i2c_device_id *id)
    {
    	struct aic31xx_priv *aic31xx;
    	int ret;
    	const struct regmap_config *regmap_config;
    
    	dev_dbg(&i2c->dev, "## %s: codec_type = %d\n", __func__,
    		(int) id->driver_data);
    
    	regmap_config = &aicxxx_i2c_regmap;
    
    	aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
    	if (aic31xx == NULL)
    		return -ENOMEM;
    
    	aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
    
    	if (IS_ERR(aic31xx->regmap)) {
    		ret = PTR_ERR(aic31xx->regmap);
    		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
    			ret);
    		return ret;
    	}
    	aic31xx->dev = &i2c->dev;
    
    	aic31xx->pdata.codec_type = id->driver_data;
    
    	aic31xx_device_init(aic31xx);
    
    	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
    				     aic31xx_dai_driver,
    				     ARRAY_SIZE(aic31xx_dai_driver));
    
    	return ret;
    }
    
    static int aic31xx_i2c_remove(struct i2c_client *i2c)
    {
    	struct aic31xx_priv *aic31xx = dev_get_drvdata(&i2c->dev);
    
    	aic31xx_device_exit(aic31xx);
    	kfree(aic31xx);
    	return 0;
    }
    
    static const struct i2c_device_id aic31xx_i2c_id[] = {
    	{ "tlv320aic311x", AIC311X },
    	{ "tlv320aic310x", AIC310X },
    	{ }
    };
    MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
    
    static struct i2c_driver aic31xx_i2c_driver = {
    	.driver = {
    		.name	= "tlv320aic31xx-codec",
    		.owner	= THIS_MODULE,
    		.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
    	},
    	.probe		= aic31xx_i2c_probe,
    	.remove		= (aic31xx_i2c_remove),
    	.id_table	= aic31xx_i2c_id,
    };
    
    module_i2c_driver(aic31xx_i2c_driver);
    
    MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver");
    MODULE_AUTHOR("Jyri Sarha");
    MODULE_LICENSE("GPL");
    

    3125.tlv320aic31xx.h

    This is the source code I use and is working fine. Please look if you can find difference in your source code.

    Regards

    Patric

  • Hi Patrick,

    This driver not worked for my kernel 3.4.39 . which kernel you have tested?.


    Regards

    Punith

  • Hi Patrick,

    Once i comment

    /*static const struct regmap_range_cfg aic31xx_ranges[] = {
            {
                    .name = "codec-regmap",
                    .range_min = 128,
                    .range_max = 13 * 128,
                    .selector_reg = 0,
                    .selector_mask = 0xff,
                    .selector_shift = 0,
                    .window_start = 0,
                    .window_len = 128,
            },
    };
    */

    and all regulator function , then able to create soundcard.

    once i play audio ,  i am getting same result like previous driver.

    But

    amixer sset 'DAC' 127
    amixer sset 'HP Analog' 66
    amixer sset 'HP Driver' 0 on
    amixer sset 'HP Left' on
    amixer sset 'HP Right' on
    amixer sset 'Output Left From Left DAC' on
    amixer sset 'Output Right From Right DAC' on

    These commands worked for me

    root@localhost:/# amixer -c 2 sset 'HP Analog' 66
    Simple mixer control 'HP Analog',0
    Capabilities: pvolume penum
    Playback channels: Front Left - Front Right
    Limits: Playback 0 - 127
    Mono:
    Front Left: Playback 66 [52%] [-30.50dB]
    Front Right: Playback 66 [52%] [-30.50dB]

    And also mclk=11MHZ, bclk=2.8MHZ and wclk is not coming(is this problem).

    getting DIN signal also while playing audio.

    Regards

    Punith

  • Hello Punith,

    Remember that the codec is configured as master in my systems, this means that I put an external 12Mhz clock onto the MCLK, the codec then generates the BCLK and WCLK.

    I think also that this is the setup for you, try to connect and 12Mhz clock signal to the MCLK pin of the audio codec and check good if the pinmux table is correct.

    Kind regards,

    Patrick

  • Hi Patrick,

    With fallowing configuration i am getting wclk as 44KHZ.

     /* set codec DAI configuration */
            ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);

    where

    #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_A | \
                    SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF)

    It means i configure codec as slave .

    So i think there no issue with wclk?.

    What clock you set for codec sysclk?.

    but not getting any audio in hp lines.


    Regards

    Punith

  • Hello Punith,

    And what for BCLK output do you get?

    I used the master mode, 12MHz input on the MCLK from the beaglebone black.

    But what is you play command to play sound?

    regards

    Patrick

  • Hi Patrick,

    my BCLK=2.8MHZ MCLK=11MHZ WCLK=48.8KHZ

    and used fallowing command to play audio

    aplay -D hw:2,0 2L38_01_96kHz\(short\).wav

    mplayer -ao alsa:device=hw=1.0 /Waka.mp4

    Kindly my audio route mapping code IN MACHINE DRIVER also:

    static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {

            SND_SOC_DAPM_HP("Headphone Jack", NULL),
    };

    static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
            SND_SOC_DAPM_SPK("Earphone", NULL),
    };

    static const struct snd_soc_dapm_route audio_map[] = {
            /* Headphone connected to HPLOUT, HPROUT */
            {"Headphone Jack", NULL, "HPLCOM"},
            {"Headphone Jack", NULL, "HPRCOM"},
    };
    static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
    {
            struct snd_soc_codec *codec = rtd->codec;
            struct snd_soc_dapm_context *dapm = &codec->dapm;
            int err;

            printk("puneet %s\n", __func__);
            

            /* Add RX-51 specific widgets */
            snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
                                      ARRAY_SIZE(aic34_dapm_widgets));

            /* Set up RX-51 specific audio path audio_map */
            snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));

         snd_soc_dapm_nc_pin(dapm, "MIC3L");
            snd_soc_dapm_nc_pin(dapm, "MIC3R");
            snd_soc_dapm_nc_pin(dapm, "LINE1R");
            snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
            snd_soc_dapm_enable_pin(dapm, "HPLOUT");
            snd_soc_dapm_enable_pin(dapm, "HPROUT");
            snd_soc_dapm_enable_pin(dapm, "HPLCOM");
            snd_soc_dapm_enable_pin(dapm, "HPRCOM");

            /* always connected */
            snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
            snd_soc_dapm_nc_pin(dapm, "Line Out");
            snd_soc_dapm_nc_pin(dapm, "Mic Jack");
            snd_soc_dapm_nc_pin(dapm, "Line In");


            return 0;
    }

    Regards

    Punith

  • Hi Patrick,

    Still i am not able to solve the issue,

    Kindly update me , if you have anything to suggest.


    Regards

    Punith

  • Hello Punith,

    The maping looks good, but my code is from TI itself and I only have to changed the device tree with the correct pinmux and sound paths.

    But could you run: speakertest -c2?

    regards

    Patrick

  • Hi Patrick,

    Once thing i observed is:

    with tlv320aic31xx.c driver i2c  write is not happening.

    with tlv320aic3x.c driver both i2c write and read happening fine.


    Is it because i commented the regmap_range_cfg aic31xx_ranges[].

    Kindly let me know.

    Regards

    Punith

  • Hello Punith,

    This is strange, because with me the I2C write/read works perfectly. I did measure it with a logic analyzer.

    Maybe you could look at github(TI Linux) and look how the TLV320 will be configured:

    https://git.ti.com/wilink8-wlan/wilink8-wlan-ti-linux-kernel/blobs/ti-linux-3.12.y-wlcore_eco/sound/soc/davinci/davinci-evm.c

    https://git.ti.com/wilink8-wlan/wilink8-wlan-ti-linux-kernel/blobs/ti-linux-3.12.y-wlcore_eco/sound/soc/codecs/tlv320aic31xx.c

    Look at the am43xx-epos-evm. That is the one I'm using know.

    Regards

    Patrick

  • Hi Patrick,

    In order to get audio in HPL and HPR line.

    Can you tell what value should be programmed in fallowing registers.

    page reg      my_current_value

    1     35          0x44   
    1     36         0xBD  
    1     37         0xBd
    1     40         0x06
    1     41         0x06

    0     37       0x88    

    Regards

    Punith

  • Hi Patrick,

    Once i able to write chip by i2c and did fallowing commands

    amixer -c 2 sset 'DAC' 127
    amixer -c 2 sset 'HP Analog' 66
    amixer -c 2 sset 'HP Driver' 0 on            
    amixer -c 2 sset 'HP Left' on
    amixer -c 2 sset 'HP Right' on
    amixer -c 2 sset 'Output Left From Left DAC' on
    amixer -c 2 sset 'Output Right From Right DAC' on

    And once i play audio i got fallowing error

    tlv320aic31xx-codec 2-0018: aic31xx_wait_bits: Failed! 0x25 was 0x88 expected 0x20 (0, 0x20, 500000 us)
    POST_PMU: HPL Driver event failed: -1
    tlv320aic31xx-codec 2-0018: aic31xx_wait_bits: Failed! 0x25 was 0x88 expected 0x2 (0, 0x2, 500000 us)
    POST_PMU: HPR Driver event failed: -1
    AO: [alsa] 44100Hz 2ch s16le (2 bytes per sample)
    Video: no video
    Starting playback...
    A: 131.0 (02:11.0) of 210.6 (03:30.5)  2.7% $<3>
    [1]+  Stopped                 mplayer -ao alsa:device=hw=2.0 /Waka.mp4

    The register 0x25 (37 register) is read only register , but indicating HPL and HPR driver power down.

    Can you say how can i solve this?.

    In your case can you print the value of registers which i posted  in previous reply.

    Regards

    Punith

  • Hello Punith,

    Could you run: speaker-test -c2

    Then you must hear pink noise in the headphone. And also check if you clocks are good.

    kind regards

    Patrick