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.

TLV320AIC3100: Playback speed issue in TLV320AIC3100 Audio codec

Part Number: TLV320AIC3100

Currently we are facing other issues with respect to playback speed.

 

Problem statement : The playback speed in TLV320AIC31xx  is at half the speed of what is expected. We expect it to happen in 1x speed but the playback speed happening in 0.5x.

i have changed the frequencies up to clock-frequency = <19200000> in the DTS file, but the problem is not  yet solved. Only we are facing the issues in TLV320AIC31xx audio codec, also i have tried with wm9860, everything working good.

So, i need your support to resolve this playback setting issues in the TLV320AIC31xx at driver level.
Regards
Ravi V
  • Hi Ravi,

    I apologize for the delayed response. 

    Can you describe to me your setup ? Also, can you please let me know the details of about the  input audio signal ? 

  • Setup & Problem statement:

    We are using TLV320AIC3100IRHBR as audio codec interface for our Embedded Linux Platform (imx8MQ) developed using Yocto Project (Kernel Version used is 4.14.98). With the help of TI Support team, we have successfully configured the Audo codec in the linux driver. 

    Problem statement : The playback speed is at half the speed of what is expected. We expect it to happen in 1x speed but the playback speed happening in 0.5x by default.

    Payer used for playing :  gst-play_1.0 and aplay 

     Input audio signal: sound.wav file

     Please let me know for further information..

  • I am not very aware of your hardware setup. I assume you have somewhere a USB connection to your pc and the wav file is played over usb.

    do you know the sampling rate of the wav file you make.?

  • Audiocodec_HWDetails.pptx

    I have attched the HW details for your reference. 

    No we are not using PC. The Alaram.wav file is avail in the embeeded linux directory in the imx8m board, from there  i am execution/playing the audio file using "gst-play_1.0 Alaram.wav" command.

    I hope am clarified the connection details & playing execution details.

  • Alaram.wav -> 

    Bitrate is 176kbps

  • WOULD IT BE POSSIBLE TO MEASURE THE FREQUENCIES OF WCLK,BCLK AND MCLK?

  • Hi Sanjay, 

    WCLK = 20.83khz

    BCLK = 666.7khz

    MCLK = No Clock freq

  • The BCLK corresponds to the Bit rate of the signal. This would be 666.7Khz.

    BCLK/WCLK  666/20.83=32

    This Looks like 16 Bit Stereo Input with a sampling rate of  20.83Khx. and a bit rate of 666.7 Khz.

    This seems to be different from the source file  which has a Bit clock of 176kbps.

    Do you still get these waveforms if you dont run the wav file?

    https://www.kozco.com/tech/soundtests.html

    I picked up the Link for some 44.1Khz ,16 bit wave files from the Internet. Would it be possible to try some of these  out? Also  could you

    check the waveforms for these files

  • With a WCLK of 20kHz, it is less than half of the 44.1kHz and the thread doesnot indicate what sample rate is being used in the playback command. For instance, we should see:

    aplay -f S16_LE -c 2 -r 48000 --device="hw:0,1”

    Where

    -r indicates the sample rate.

    -f indicates the word size format (signed extended 16-bit little endian in the above command)

    -c is the number of channels

    Given that BCLK / WCLK = 32, you seem to be using 2 channels with 16-bit data.

     

    Linux usually has a test command where you do not have to worry about sample rates:

    speaker-test -c 2 -t wav -D"hw:0,1”

    speaker-test -c 2 -t sine -D"hw:0,1”

     

    The first command plays “left” and “right” for each channel. The sine one just outputs a sine tone.

  • Yes sanjay, linux command wise we are able to set speed manually and playing the .wav file without any issue.

    But, due to this problem, we are unable to play with normal speed of .wav or any other file from QT application.

    From  "wm8960" we are not facing any issue "this codec avail ic eval kit", in our HW we are using TLV, we are facing the issue here.

    So, any registry level speed stetting is good for solving this problem. Request you provide the solution, it will be very helpful.

  • Hi Sanjay,

    Do you still get these waveforms if you dont run the wav file?

    There is no clock pulses, its pulled high.

  • root@b2qt-nitrogen8m:~/Test# speaker-test -c 2 -t wav -D"hw:0,0"

    speaker-test 1.1.9

    Playback device is hw:0,0
    Stream parameters are 48000Hz, S16_LE, 2 channels
    WAV file(s)
    Rate set to 48000Hz (requested 48000Hz)
    Buffer size range from 64 to 16384
    Period size range from 32 to 8192
    Using max buffer size 16384
    Periods = 4
    was set period_size = 4096
    was set buffer_size = 16384
    0 - Front Left
    1 - Front Right
    Time per period = 6.175488
    0 - Front Left
    ^CTransfer failed: Bad address
    root@b2qt-nitrogen8m:~/Test#
    root@b2qt-nitrogen8m:~/Test# speaker-test -c 2 -t sine -D"hw:0,0"

    speaker-test 1.1.9

    Playback device is hw:0,0
    Stream parameters are 48000Hz, S16_LE, 2 channels
    Sine wave rate is 440.0000Hz
    Rate set to 48000Hz (requested 48000Hz)
    Buffer size range from 64 to 16384
    Period size range from 32 to 8192
    Using max buffer size 16384
    Periods = 4
    was set period_size = 4096
    was set buffer_size = 16384
    0 - Front Left
    1 - Front Right
    ^CTime per period = 6.745331
    root@b2qt-nitrogen8m:~/Test#

  • Hi Sanjay,

     I have played LRMonoPhase4.wav (Left, Right, In-Phase, Out-Of-Phase Test, 48k/16, WAV 7.3MB, 39 seconds) and LRMonoPhase4.mp3 (Same test but in MP3). using gst-play_1.0 & aplay player. Still same speed issue.

    Console Log:

    root@b2qt-nitrogen8m:~/Test# ls
    Alarm.wav LRMonoPhase4_MP3.mp3 test_splash.gif
    GraphingLogic RM_INIT tone.mp3
    LRMonoPhase4.wav RM_SOM_INTEGRATION_WRAPPER
    root@b2qt-nitrogen8m:~/Test#

  • It just sounds like your issue is not programming the part correctly. Apparently, you read a file with their QT application, extract sample rates from the headers of the wav file and then configure the AIC to play it through. you do not seem to be using a linux command, 

     Probably best way to debug this, is to  compare register dumps between playing the wav file with a linux command and playing it through QT application. 

  • Even, i am playing with linux command as well as QT wise, the out put is same. I will record and i will attach. 

    Register dumps like i2c dump?

  • You were mentioning that with linux command it was working. Is that correct?

    We can take a look at I2C Dump.

    One thing i like to mention, our device is set up as a slave so it receives BCLK and WCLK from the Processor. 

    if we play an audio file of 44.1khz ,16 bit stereo from the source, the WCLK should be at 44.1khz and the BCLK should be at 44.1khz*32 or 1.411 Mhz.   If The Chip has Clock I2C registers set up such that it samples at 44.1Khx, then the DAC shall play sound correct. This register setup can be confirmed from I2C dump.

    So if you are playing a 48khz file from any source the WCLK must become 48khz .. With the Linux command try to play a 48Khz file and check WCLK and Bclk

  • Yes sanjay, by using the following command i have tried 

    "gst-launch-1.0 filesrc location= IEC_Tone_4.wav ! decodebin ! audioconvert ! speed speed=2.0 ! audioresample ! alsasink device=hw:0"

    So, this is playing with 2x speed setting and audio coded is playing at normal speed, which is not acceptable.

    The sound test you provided, it also played at half the speed, irrespective of what player we use: gst-play_1.0, aplay, youtube and QT Application. 

    Please give me the solution to fix the issue.

  • I would suggst the following:

    1. Play a  48khz file with aplay.

    2. measure BCLK, WCLK

    3. Send me the I2C registers written into the device

  • So, this is playing with 2x speed setting and audio coded is playing at normal speed, which is not acceptable.

    Can you also let me know the BCLK AND LRCLK WITH THIS SETTING?

  • BCLK is ok, which line is LRCLK?

    Shall i play the following .wav file as you suggested for 48khz "LRMonoPhase4.wav (Left, Right, In-Phase, Out-Of-Phase Test, 48k/16, WAV 7.3MB, 39 seconds)" and capture the signals?

  • Console log:

    root@b2qt-nitrogen8m:~/Test# aplay -v LRMonoPhase4.wav
    [ 846.822536] alloc_contig_range: [44d30, 44d40) PFNs busy
    [ 846.829024] alloc_contig_range: [44d70, 44d80) PFNs busy
    Playing WAVE 'LRMonoPhase4.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
    Plug PCM: Rate conversion PCM (44100, sformat=S16_LE)
    Converter: linear-interpolation
    Protocol version: 10002
    Its setup is:
    stream : PLAYBACK
    access : RW_INTERLEAVED
    format : S16_LE
    subformat : STD
    channels : 2
    rate : 48000
    exact rate : 48000 (48000/1)
    msbits : 16
    buffer_size : 5760
    period_size : 1920
    period_time : 40000
    tstamp_mode : NONE
    tstamp_type : MONOTONIC
    period_step : 1
    avail_min : 1920
    period_event : 0
    start_threshold : 5760
    stop_threshold : 5760
    silence_threshold: 0
    silence_size : 0
    boundary : 6485183463413514240
    Slave: Direct Stream Mixing PCM
    Its setup is:
    stream : PLAYBACK
    access : MMAP_INTERLEAVED
    format : S16_LE
    subformat : STD
    channels : 2
    rate : 44100
    exact rate : 44100 (44100/1)
    msbits : 16
    buffer_size : 5292
    period_size : 1764
    period_time : 40000
    tstamp_mode : NONE
    tstamp_type : MONOTONIC
    period_step : 1
    avail_min : 1764
    period_event : 0
    start_threshold : 5292
    stop_threshold : 5292
    silence_threshold: 0
    silence_size : 0
    boundary : 5958262307011166208
    Hardware PCM card 0 'TI-TLV320AIC31xx-Card' device 0 subdevice 0

  • BCLK @ 680.2khz 

    WCLK @21.19khz

    i have played in both aplay, gst player. Also, i have increased speed upto 2.50 via keypad (entering '+) in gst-play_1.0 and i have observed  that both BCLK & WCLK as same as above image. . 

  • Played via QT APP:


    AUD-20210813-WA0003.m4a

    Played Via linux command

  • you need to capture WCK

    It looks to me that the source timing is always at Half the rate the device is setup for.

    Generally I2C settings in the device is  setup to receive 44,1Khz.The source is generating timing at 1/2 the rate.OR AT 22KZ. We have to change the timing of the source such that it generates WCLK NOT AT 21.9kHZ BUT AT 44kHZ

    When you change aplay -f S16_LE -c 2 -r 48000 --device="hw:0,1”         with 96000 Do you see WCLK becoming 44k or 48k?

  • ALso , if possible can you send us a i2c dump of settings written into the codec?

  • Hi Sanjay,

    root@b2qt-nitrogen8m:~# i2cdetect -y 3
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- 56 -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --
    root@b2qt-nitrogen8m:~# i2cdump 3 0x18
    No size specified (using byte-data access)
    Error: Could not set address to 0x18: Device or resource busy
    root@b2qt-nitrogen8m:~#

    Can you please tell me how to stop using i2cset command. because am unable to dump any values in 0x18 address, it shows Resource busy, 

  • Hi Rävi,

    did you try to run the file with Linux command at sample rate of 96k? Did w close increase to 48k?

  • Hi Sanjay,

    I have downloaded, .wav file with different freq rate and tested with gplay and aplay with 96hz to 48khz. But the audio speed is same.

    "https://www.mitsue.co.jp/english/service/audio_and_video/audio_production/high_resolution_narration.html"

    root@b2qt-nitrogen8m:~/Test# ls
    GraphingLogic RM_SOM_INTEGRATION_WRAPPER sample06.wav sample09.wav
    LRMonoPhase4.wav sample02.wav sample07.wav test_splash.gif
    RM_INIT sample04.wav sample08.wav tone.mp3
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample09.wav
    [ 2495.037371] alloc_contig_range: [44d30, 44d40) PFNs busy
    Playing WAVE 'sample09.wav' : Signed 16 bit Little Endian, Rate 22050 Hz, Mono
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample02.wav
    [ 2504.273858] alloc_contig_range: [44d30, 44d40) PFNs busy
    Warning: format is changed to S24_3LE
    Playing WAVE 'sample02.wav' : Signed 24 bit Little Endian in 3bytes, Rate 192000 Hz, Mono
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample07.wav
    [ 2512.253583] alloc_contig_range: [44d30, 44d40) PFNs busy
    Warning: format is changed to S24_3LE
    Playing WAVE 'sample07.wav' : Signed 24 bit Little Endian in 3bytes, Rate 44100 Hz, Mono
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample04.wav
    [ 2521.805694] alloc_contig_range: [44d30, 44d40) PFNs busy
    Warning: format is changed to S24_3LE
    Playing WAVE 'sample04.wav' : Signed 24 bit Little Endian in 3bytes, Rate 96000 Hz, Mono
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample08.wav
    [ 2539.187419] alloc_contig_range: [44d30, 44d40) PFNs busy
    Playing WAVE 'sample08.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 tone.mp3
    [ 2548.428796] alloc_contig_range: [44d30, 44d40) PFNs busy
    Playing raw data 'tone.mp3' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
    root@b2qt-nitrogen8m:~/Test# aplay -f S16_LE -c 2 -r 48000 sample4.mp3
    [ 3001.562027] alloc_contig_range: [44d30, 44d40) PFNs busy
    Playing raw data 'sample4.mp3' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
    ^CAborted by signal Interrupt...
    aplay: pcm_write:2057: write error: Interrupted system call
    root@b2qt-nitrogen8m:~/Test#

  • Also, i have tried to set the PLL clock by using the following link - blindly 

    https://e2e.ti.com/support/audio-group/audio/f/audio-forum/650362/linux-tlv320aic3204evm-k-i2c-tlv320aic3204-evaluation-module-problem

    ###############################################
    # Clock Settings
    # ---------------------------------------------
    # The codec receives: MCLK = 24 MHz,
    # BLCK = 1,4112 MHz, WCLK = 44,1 kHz
    ###############################################
    #
    # Select Page 0
    i2cset -y -f 2 0x18 0x00 0x00
    #
    # MCLK as PLL_input; PLL_CLK as CODEC_CLKIN
    i2cset -y -f 2 0x18 0x04 0x03
    #
    # P = 2; R = 1; J = 7; D = 560; PLL enabled
    i2cset -y -f 2 0x18 0x05 0xa1
    i2cset -y -f 2 0x18 0x06 0x07
    i2cset -y -f 2 0x18 0x07 0x02
    i2cset -y -f 2 0x18 0x08 0x30
    #
    # NDAC = 3, MDAC = 3; dividers powered on
    i2cset -y -f 2 0x18 0x0b 0x83
    i2cset -y -f 2 0x18 0x0c 0x83

    # Program the OSR of DAC to 128
    i2cset -y -f 2 0x18 0x0d 0x00
    i2cset -y -f 2 0x18 0x0e 0x80

    The playback speed went to 4.0x, this i have verified by using gst-play-1.0 with entering + key in keyboard.

    So, am suspecting something we need to set with register level. can you please help me to set. I guess, this will solve our pbm.

    Regrads

    Ravi V

  • Hi Ravi,

    When you changed  aplay settings to 96khz did the input signals change from the settings that were there below. If so what were BCLK,WCLKP at 96K ?

    IWCLK =20.83 kh

    BCLK = 666.7khz

    MCLK = No Clock freq

    These settings are an input to the codec and the codec register settings have nothing to do with these settings.These settings should change when the input changes .

    If you like i can try to give you register settings for the codec that should enable operation at whatever is coming into the codec.

    Can you send me the current WCLK,BCLK,MCLK?

  • Hi Sanjay, 

    There is no change aplay setting with diffrent frequencies.

    I got good results in  the I2CSet commands:

    # Select Page 0
    i2cset -y -f 2 0x18 0x00 0x00
    # NDAC = 3, MDAC = 3; dividers powered on
    i2cset -y -f 2 0x18 0x0b 0x82
    i2cset -y -f 2 0x18 0x0c 0x84

    The above setting will configured for normal playbackspeed, and also it is working. 

    But the problem is it is not stable, after power OFF and Power ON. This setting not avil, so each power on time i have to do this setting.

    So, please verify the above command and provide me how permanently store this values in the TLV chip.

    With this setting, i following frequenncies are captured: 56.82kHz & 1.814MHz

    Now we got some clue, please provide stable/permanent solution. It will be veryhelpful.

    Regards

    Ravi V

  • Hi Sanjay

    Can you please provide the soultion.

    Regards

    ravi V

    • i2cdump-y -f 2 0x4c => show all registers at I2C bus 2 device 0x4c  
    • Can you try the above to see if you can get an I2C Dump.
  • Actually I2C bus is 3 and address is 0x18: Please find below i2c dump

    root@b2qt-nitrogen8m:~# i2cdump -f -y 3 0x18
    No size specified (using byte-data access)
    0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
    00: 00 00 01 66 00 91 04 00 00 00 00 81 81 00 80 80 ..?f.??....??.??
    10: 08 00 81 81 80 80 04 00 00 00 01 0c 00 00 81 00 ?.?????...??..?.
    20: 00 00 00 00 80 10 00 00 00 00 00 00 00 00 00 00 ....??..........
    30: 00 00 00 02 32 12 03 02 02 11 10 00 01 04 00 14 ...?2??????.??.?
    40: 0c 00 00 00 6f 38 00 00 00 00 00 ee 10 d8 7e e3 ?...o8.....???~?
    50: 00 00 80 00 00 00 00 00 7f 00 00 00 00 00 00 00 ..?.....?.......
    60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    70: 00 00 00 00 00 5c 00 00 00 00 00 00 00 00 00 00 .....\..........
    80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

    But, i am unable to get any data @0x4C

    root@b2qt-nitrogen8m:~# i2cdump -y -f 3 0x4c
    No size specified (using byte-data access)
    0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
    00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    10: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    20: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    30: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    40: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    50: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    90: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    a0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    b0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    c0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    d0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    e0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
    f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX

  • sorry 0x4c  was just an example to explain the format

  • got it, Thanks

    root@b2qt-nitrogen8m:~# i2cdump -f -y 3 0x18
    No size specified (using byte-data access)
    0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
    00: 00 00 01 66 00 91 04 00 00 00 00 81 81 00 80 80 ..?f.??....??.??
    10: 08 00 81 81 80 80 04 00 00 00 01 0c 00 00 81 00 ?.?????...??..?.
    20: 00 00 00 00 80 10 00 00 00 00 00 00 00 00 00 00 ....??..........
    30: 00 00 00 02 32 12 03 02 02 11 10 00 01 04 00 14 ...?2??????.??.?
    40: 0c 00 00 00 6f 38 00 00 00 00 00 ee 10 d8 7e e3 ?...o8.....???~?
    50: 00 00 80 00 00 00 00 00 7f 00 00 00 00 00 00 00 ..?.....?.......
    60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    70: 00 00 00 00 00 5c 00 00 00 00 00 00 00 00 00 00 .....\..........
    80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

     

    Iam planning to update the seetings in tlv320aic31xx device tree or tlv320aic31xx.c kernel level. So, please help me to do this way.

  • Hi Sanjay,

    Please provide me teh solution.

    Regards

    Ravi V

  • I looked at the register dump.

    One thing I noticed is Register 27.

    It has 0X0C written . This means WCLK and BCLK are outputs and the TLV320AIC3100 is acting like a master and is in fact

    Generating the timing.  We need to come to a situation where the processor is generating the BCLK and WCLK so that the commands can generate the correct timings.

    A lot of the clocking and who is driving is generated automatically depending on DTS settings. The driver will only drive the clocks, if set to Master at the DTS level.

    After this the i2c settings of the Codec shall have to be setup as a slave.

    Please refer to the text file .

    A lot of the clocking and wh is driving is generated automatically depending on DTS settings. The driver will only drive the clocks, if set to Master at the DTS level. The following shows the driver code routine that reads this from the ALSA driver:
    static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
    			       unsigned int fmt)
    {
    	struct snd_soc_component *component = codec_dai->component;
    	u8 iface_reg1 = 0;
    	u8 iface_reg2 = 0;
    	u8 dsp_a_val = 0;
    
    	dev_dbg(component->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_CFM:
    		iface_reg1 |= AIC31XX_WCLK_MASTER;
    		break;
    	case SND_SOC_DAIFMT_CBM_CFS:
    		iface_reg1 |= AIC31XX_BCLK_MASTER;
    		break;
    	case SND_SOC_DAIFMT_CBS_CFS:
    		break;
    	default:
    		dev_err(component->dev, "Invalid DAI master/slave interface\n");
    		return -EINVAL;
    	}
    
    The SND_SOC_DAIFMT_MASTER_MASK is set by the ALSA driver, it offers:
     /*
       62  * DAI hardware clock masters.
       63  *
       64  * This is wrt the codec, the inverse is true for the interface
       65  * i.e. if the codec is clk and FRM master then the interface is
       66  * clk and frame slave.
       67  */
       68 #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */
       69 #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */
       70 #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */
       71 #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */
       72 
       73 #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
       74 #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
       75 #define SND_SOC_DAIFMT_INV_MASK 0x0f00
       76 #define SND_SOC_DAIFMT_MASTER_MASK 0xf000
    
    In Summary, this is obtained from system configuration including DTS that indicates which clocks are master. In the following DTS example, the CPU is master and codec is slave:
     simple-audio-card,dai-link@1 {
            format = "dsp_a";
            bitclock-master = <&sound0_1_master>;
            frame-master = <&sound0_1_master>;
            sound0_1_master: cpu {
                sound-dai = <&mcasp0>;
                clocks = <&clk_mcasp0>;
                dai-tdm-slot-num = <8>;
                dai-tdm-slot-width = <32>;
                dai-tdm-slot-tx-mask = <1 1 1 1 1 1 1 1>;
                dai-tdm-slot-rx-mask = <1 1 1 1 1 1 1 1>;
            };
     
            codec {
                sound-dai = <&tlv320adc5140>;
                dai-tdm-slot-num = <8>;
                dai-tdm-slot-width = <32>;
                dai-tdm-slot-tx-mask = <1 1 1 1 1 1 1 1>;
                dai-tdm-slot-rx-mask = <1 1 1 1 1 1 1 1>;
            };
        };
    
    If 
    If wanting the codec as master, then it would be like:
    	sound0_1_master: codec {
                sound-dai = <&tlv320adc5140>;
                dai-tdm-slot-num = <8>;
                dai-tdm-slot-width = <32>;
                dai-tdm-slot-tx-mask = <1 1 1 1 1 1 1 1>;
                dai-tdm-slot-rx-mask = <1 1 1 1 1 1 1 1>;
            };
    

  • Hi Sanjay,

    One smalll correction, 0x0c written in Register 17 not in 27. 

    I am confused, what cahnge i have to do and where. Here with i have attched my .dts file. We have added the TLC Audio codec drived recommended by TI. Also i have attached the tlv320aic31xx.c file.

    I would request you to please suggest me what the cjanges i have to do and where.

    Regards

    Ravi 

    	sound-wm8960 {
    		compatible = "simple-audio-card";
    		simple-audio-card,name = "TI-TLV320AIC31xx-Card";
    		simple-audio-card,format = "i2s";
    		simple-audio-card,bitclock-master = <&codec_dai>;
    		simple-audio-card,frame-master = <&codec_dai>;
    		simple-audio-card,widgets =
    		"Speaker", "Speaker";
    		simple-audio-card,routing =
    		"Speaker", "SPK";
    
    		simple-audio-card,cpu {
    			sound-dai = <&sai1>;
    		};
    
    		codec_dai: simple-audio-card,codec {
    			sound-dai = <&tlv320aic31xx>;
    			system-clock-frequency = <12000000>; /* this matches sai1 */
    		};
    	};
    	
    	&i2c4 {
    	clock-frequency = <100000>;
    	pinctrl-names = "default";
    	pinctrl-0 = <&pinctrl_i2c4>;
    	status = "okay";
    
    	tlv320aic31xx: tlv320aic31xx@18 {
                    #sound-dai-cells = <0>;
    		compatible = "ti,tlv320aic310x";
    		reg = <0x18>;
                    ai31xx-micbias-vg = <MICBIAS_2_0V>;
                    reset-gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>;
    		HPVDD-supply = <&reg_vref_3v3>;
    		SPRVDD-supply = <&reg_vref_3v3>;
    		SPLVDD-supply = <&reg_vref_3v3>;
    		SKPVDD-supply = <&reg_vref_5v>;
    		SPKVDD-supply = <&reg_vref_5v>;
    		AVDD-supply = <&reg_vref_3v3>;
    		IOVDD-supply = <&reg_vref_3v3>;
    		DVDD-supply = <&reg_vref_1v8>;
    	};
    };
    
    
    	
    	
    	

  • I have attached the tlv320aic31xx.c file.

    /*
     * ALSA SoC TLV320AIC31XX codec driver
     *
     * Copyright (C) 2014 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/acpi.h>
    #include <linux/of.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 <dt-bindings/sound/tlv320aic31xx-micbias.h>
    
    #include "tlv320aic31xx.h"
    
    static const struct reg_default aic31xx_reg_defaults[] = {
    	{ AIC31XX_CLKMUX, 0x00 },
    	{ AIC31XX_PLLPR, 0x11 },
    	{ AIC31XX_PLLJ, 0x04 },
    	{ AIC31XX_PLLDMSB, 0x00 },
    	{ AIC31XX_PLLDLSB, 0x00 },
    	{ AIC31XX_NDAC, 0x01 },
    	{ AIC31XX_MDAC, 0x01 },
    	{ AIC31XX_DOSRMSB, 0x00 },
    	{ AIC31XX_DOSRLSB, 0x80 },
    	{ AIC31XX_NADC, 0x01 },
    	{ AIC31XX_MADC, 0x01 },
    	{ AIC31XX_AOSR, 0x80 },
    	{ AIC31XX_IFACE1, 0x00 },
    	{ AIC31XX_DATA_OFFSET, 0x00 },
    	{ AIC31XX_IFACE2, 0x00 },
    	{ AIC31XX_BCLKN, 0x01 },
    	{ AIC31XX_DACSETUP, 0x14 },
    	{ AIC31XX_DACMUTE, 0x0c },
    	{ AIC31XX_LDACVOL, 0x00 },
    	{ AIC31XX_RDACVOL, 0x00 },
    	{ AIC31XX_ADCSETUP, 0x00 },
    	{ AIC31XX_ADCFGA, 0x80 },
    	{ AIC31XX_ADCVOL, 0x00 },
    	{ AIC31XX_HPDRIVER, 0x04 },
    	{ AIC31XX_SPKAMP, 0x06 },
    	{ AIC31XX_DACMIXERROUTE, 0x00 },
    	{ AIC31XX_LANALOGHPL, 0x7f },
    	{ AIC31XX_RANALOGHPR, 0x7f },
    	{ AIC31XX_LANALOGSPL, 0x7f },
    	{ AIC31XX_RANALOGSPR, 0x7f },
    	{ AIC31XX_HPLGAIN, 0x02 },
    	{ AIC31XX_HPRGAIN, 0x02 },
    	{ AIC31XX_SPLGAIN, 0x00 },
    	{ AIC31XX_SPRGAIN, 0x00 },
    	{ AIC31XX_MICBIAS, 0x00 },
    	{ AIC31XX_MICPGA, 0x80 },
    	{ AIC31XX_MICPGAPI, 0x00 },
    	{ AIC31XX_MICPGAMI, 0x00 },
    };
    
    static bool aic31xx_volatile(struct device *dev, unsigned int reg)
    {
    	switch (reg) {
    	case AIC31XX_PAGECTL: /* regmap implementation requires this */
    	case AIC31XX_RESET: /* always clears after write */
    	case AIC31XX_OT_FLAG:
    	case AIC31XX_ADCFLAG:
    	case AIC31XX_DACFLAG1:
    	case AIC31XX_DACFLAG2:
    	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRDACFLAG2:
    	case AIC31XX_INTRADCFLAG2:
    		return true;
    	}
    	return false;
    }
    
    static bool aic31xx_writeable(struct device *dev, unsigned int reg)
    {
    	switch (reg) {
    	case AIC31XX_OT_FLAG:
    	case AIC31XX_ADCFLAG:
    	case AIC31XX_DACFLAG1:
    	case AIC31XX_DACFLAG2:
    	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
    	case AIC31XX_INTRDACFLAG2:
    	case AIC31XX_INTRADCFLAG2:
    		return false;
    	}
    	return true;
    }
    
    static const struct regmap_range_cfg aic31xx_ranges[] = {
    	{
    		.range_min = 0,
    		.range_max = 12 * 128,
    		.selector_reg = AIC31XX_PAGECTL,
    		.selector_mask = 0xff,
    		.selector_shift = 0,
    		.window_start = 0,
    		.window_len = 128,
    	},
    };
    
    static const struct regmap_config aic31xx_i2c_regmap = {
    	.reg_bits = 8,
    	.val_bits = 8,
    	.writeable_reg = aic31xx_writeable,
    	.volatile_reg = aic31xx_volatile,
    	.reg_defaults = aic31xx_reg_defaults,
    	.num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults),
    	.cache_type = REGCACHE_RBTREE,
    	.ranges = aic31xx_ranges,
    	.num_ranges = ARRAY_SIZE(aic31xx_ranges),
    	.max_register = 12 * 128,
    };
    
    #define AIC31XX_NUM_SUPPLIES	6
    static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
    	"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];
    	unsigned int sysclk;
    	u8 p_div;
    	int rate_div_line;
    };
    
    struct aic31xx_rate_divs {
    	u32 mclk_p;
    	u32 rate;
    	u8 pll_j;
    	u16 pll_d;
    	u16 dosr;
    	u8 ndac;
    	u8 mdac;
    	u8 aosr;
    	u8 nadc;
    	u8 madc;
    };
    
    /* ADC dividers can be disabled by cofiguring them to 0 */
    static const struct aic31xx_rate_divs aic31xx_divs[] = {
    	/* mclk/p    rate  pll: j     d        dosr ndac mdac  aors nadc madc */
    	/* 8k rate */
    	{12000000,   8000,	8, 1920,	128,  48,  2,	128,  48,  2},
    	{12000000,   8000,	8, 1920,	128,  32,  3,	128,  32,  3},
    	{12500000,   8000,	7, 8643,	128,  48,  2,	128,  48,  2},
    	/* 11.025k rate */
    	{12000000,  11025,	7, 5264,	128,  32,  2,	128,  32,  2},
    	{12000000,  11025,	8, 4672,	128,  24,  3,	128,  24,  3},
    	{12500000,  11025,	7, 2253,	128,  32,  2,	128,  32,  2},
    	/* 16k rate */
    	{12000000,  16000,	8, 1920,	128,  24,  2,	128,  24,  2},
    	{12000000,  16000,	8, 1920,	128,  16,  3,	128,  16,  3},
    	{12500000,  16000,	7, 8643,	128,  24,  2,	128,  24,  2},
    	/* 22.05k rate */
    	{12000000,  22050,	7, 5264,	128,  16,  2,	128,  16,  2},
    	{12000000,  22050,	8, 4672,	128,  12,  3,	128,  12,  3},
    	{12500000,  22050,	7, 2253,	128,  16,  2,	128,  16,  2},
    	/* 32k rate */
    	{12000000,  32000,	8, 1920,	128,  12,  2,	128,  12,  2},
    	{12000000,  32000,	8, 1920,	128,   8,  3,	128,   8,  3},
    	{12500000,  32000,	7, 8643,	128,  12,  2,	128,  12,  2},
    	/* 44.1k rate */
    	{12000000,  44100,	7, 5264,	128,   8,  2,	128,   8,  2},
    	{12000000,  44100,	8, 4672,	128,   6,  3,	128,   6,  3},
    	{12500000,  44100,	7, 2253,	128,   8,  2,	128,   8,  2},
    	/* 48k rate */
    	{12000000,  48000,	8, 1920,	128,   8,  2,	128,   8,  2},
    	{12000000,  48000,	7, 6800,	 96,   5,  4,	 96,   5,  4},
    	{12500000,  48000,	7, 8643,	128,   8,  2,	128,   8,  2},
    	/* 88.2k rate */
    	{12000000,  88200,	7, 5264,	 64,   8,  2,	 64,   8,  2},
    	{12000000,  88200,	8, 4672,	 64,   6,  3,	 64,   6,  3},
    	{12500000,  88200,	7, 2253,	 64,   8,  2,	 64,   8,  2},
    	/* 96k rate */
    	{12000000,  96000,	8, 1920,	 64,   8,  2,	 64,   8,  2},
    	{12000000,  96000,	7, 6800,	 48,   5,  4,	 48,   5,  4},
    	{12500000,  96000,	7, 8643,	 64,   8,  2,	 64,   8,  2},
    	/* 176.4k rate */
    	{12000000, 176400,	7, 5264,	 32,   8,  2,	 32,   8,  2},
    	{12000000, 176400,	8, 4672,	 32,   6,  3,	 32,   6,  3},
    	{12500000, 176400,	7, 2253,	 32,   8,  2,	 32,   8,  2},
    	/* 192k rate */
    	{12000000, 192000,	8, 1920,	 32,   8,  2,	 32,   8,  2},
    	{12000000, 192000,	7, 6800,	 24,   5,  4,	 24,   5,  4},
    	{12500000, 192000,	7, 8643,	 32,   8,  2,	 32,   8,  2},
    };
    
    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 SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6,
    	mic_select_text);
    static SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4,
    	mic_select_text);
    static SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2,
    	mic_select_text);
    
    static SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
    static 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 common31xx_snd_controls[] = {
    	SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
    			   AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
    
    	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
    		     AIC31XX_HPRGAIN, 2, 1, 0),
    	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
    			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
    
    	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
    			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
    };
    
    static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
    	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
    		       adc_fgain_tlv),
    
    	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
    	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL,
    			   0, -24, 40, 6, 0, adc_cgain_tlv),
    
    	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
    		       119, 0, mic_pga_tlv),
    };
    
    static const struct snd_kcontrol_new aic311x_snd_controls[] = {
    	SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
    		     AIC31XX_SPRGAIN, 2, 1, 0),
    	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
    			 AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
    
    	SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
    			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
    };
    
    static const struct snd_kcontrol_new aic310x_snd_controls[] = {
    	SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
    		   2, 1, 0),
    	SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
    		       3, 3, 0, class_D_drv_tlv),
    
    	SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
    		       0, 0x7F, 1, sp_vol_tlv),
    };
    
    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);
    
    static 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;
    }
    
    #define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
    
    static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
    				    struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	unsigned int reg = AIC31XX_DACFLAG1;
    	unsigned int mask;
    
    	switch (WIDGET_BIT(w->reg, w->shift)) {
    	case WIDGET_BIT(AIC31XX_DACSETUP, 7):
    		mask = AIC31XX_LDACPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_DACSETUP, 6):
    		mask = AIC31XX_RDACPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
    		mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
    		mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_SPKAMP, 7):
    		mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_SPKAMP, 6):
    		mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
    		break;
    	case WIDGET_BIT(AIC31XX_ADCSETUP, 7):
    		mask = AIC31XX_ADCPWRSTATUS_MASK;
    		reg = AIC31XX_ADCFLAG;
    		break;
    	default:
    		dev_err(codec->dev, "Unknown widget '%s' calling %s\n",
    			w->name, __func__);
    		return -EINVAL;
    	}
    
    	switch (event) {
    	case SND_SOC_DAPM_POST_PMU:
    		return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
    	case SND_SOC_DAPM_POST_PMD:
    		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
    	default:
    		dev_dbg(codec->dev,
    			"Unhandled dapm widget event %d from %s\n",
    			event, w->name);
    	}
    	return 0;
    }
    
    static const struct snd_kcontrol_new aic31xx_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 aic31xx_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 dac31xx_left_output_switches[] = {
    	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
    	SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0),
    	SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0),
    };
    
    static const struct snd_kcontrol_new dac31xx_right_output_switches[] = {
    	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
    	SOC_DAPM_SINGLE("From AIN2", 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_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 mic_bias_event(struct snd_soc_dapm_widget *w,
    			  struct snd_kcontrol *kcontrol, int event)
    {
    	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
    	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 */
    		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:
    		/* turn mic bias 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 common31xx_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", "Left Playback",
    			   AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
    			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
    
    	SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
    			   AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
    			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
    
    	/* HP */
    	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_dapm_power_event,
    			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
    	SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
    			       NULL, 0, aic31xx_dapm_power_event,
    			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
    
    	/* Mic Bias */
    	SND_SOC_DAPM_SUPPLY("MICBIAS", 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"),
    };
    
    static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = {
    	/* Inputs */
    	SND_SOC_DAPM_INPUT("AIN1"),
    	SND_SOC_DAPM_INPUT("AIN2"),
    
    	/* Output Mixers */
    	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
    			   dac31xx_left_output_switches,
    			   ARRAY_SIZE(dac31xx_left_output_switches)),
    	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
    			   dac31xx_right_output_switches,
    			   ARRAY_SIZE(dac31xx_right_output_switches)),
    };
    
    static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
    	/* Inputs */
    	SND_SOC_DAPM_INPUT("MIC1LP"),
    	SND_SOC_DAPM_INPUT("MIC1RP"),
    	SND_SOC_DAPM_INPUT("MIC1LM"),
    
    	/* 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),
    
    	/* ADC */
    	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
    			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
    			   SND_SOC_DAPM_POST_PMD),
    
    	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),
    
    	/* Output Mixers */
    	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
    			   aic31xx_left_output_switches,
    			   ARRAY_SIZE(aic31xx_left_output_switches)),
    	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
    			   aic31xx_right_output_switches,
    			   ARRAY_SIZE(aic31xx_right_output_switches)),
    };
    
    static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
    	/* AIC3111 and AIC3110 have stereo class-D amplifier */
    	SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
    			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
    			       SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
    			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
    			       SND_SOC_DAPM_POST_PMD),
    	SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_spl_switch),
    	SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0,
    			    &aic31xx_dapm_spr_switch),
    	SND_SOC_DAPM_OUTPUT("SPL"),
    	SND_SOC_DAPM_OUTPUT("SPR"),
    };
    
    /* AIC3100 and AIC3120 have only mono class-D amplifier */
    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_dapm_power_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
    common31xx_audio_map[] = {
    	/* 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"},
    
    	/* 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
    dac31xx_audio_map[] = {
    	/* Left Output */
    	{"Output Left", "From Left DAC", "DAC Left"},
    	{"Output Left", "From AIN1", "AIN1"},
    	{"Output Left", "From AIN2", "AIN2"},
    
    	/* Right Output */
    	{"Output Right", "From Right DAC", "DAC Right"},
    	{"Output Right", "From AIN2", "AIN2"},
    };
    
    static const struct snd_soc_dapm_route
    aic31xx_audio_map[] = {
    	/* 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"},
    
    	/* 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"},
    };
    
    static const struct snd_soc_dapm_route
    aic311x_audio_map[] = {
    	/* SP L path */
    	{"Speaker Left", "Switch", "Output Left"},
    	{"SPL ClassD", NULL, "Speaker Left"},
    	{"SPL", NULL, "SPL ClassD"},
    
    	/* SP R path */
    	{"Speaker Right", "Switch", "Output Right"},
    	{"SPR ClassD", NULL, "Speaker 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 ret = 0;
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    
    	if (!(aic31xx->pdata.codec_type & DAC31XX_BIT))
    		ret = snd_soc_add_codec_controls(
    			codec, aic31xx_snd_controls,
    			ARRAY_SIZE(aic31xx_snd_controls));
    	if (ret)
    		return ret;
    
    	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
    		ret = snd_soc_add_codec_controls(
    			codec, aic311x_snd_controls,
    			ARRAY_SIZE(aic311x_snd_controls));
    	else
    		ret = snd_soc_add_codec_controls(
    			codec, aic310x_snd_controls,
    			ARRAY_SIZE(aic310x_snd_controls));
    
    	return ret;
    }
    
    static int aic31xx_add_widgets(struct snd_soc_codec *codec)
    {
    	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int ret = 0;
    
    	if (aic31xx->pdata.codec_type & DAC31XX_BIT) {
    		ret = snd_soc_dapm_new_controls(
    			dapm, dac31xx_dapm_widgets,
    			ARRAY_SIZE(dac31xx_dapm_widgets));
    		if (ret)
    			return ret;
    
    		ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map,
    					      ARRAY_SIZE(dac31xx_audio_map));
    		if (ret)
    			return ret;
    	} else {
    		ret = snd_soc_dapm_new_controls(
    			dapm, aic31xx_dapm_widgets,
    			ARRAY_SIZE(aic31xx_dapm_widgets));
    		if (ret)
    			return ret;
    
    		ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map,
    					      ARRAY_SIZE(aic31xx_audio_map));
    		if (ret)
    			return ret;
    	}
    
    	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
    		ret = snd_soc_dapm_new_controls(
    			dapm, aic311x_dapm_widgets,
    			ARRAY_SIZE(aic311x_dapm_widgets));
    		if (ret)
    			return ret;
    
    		ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
    					      ARRAY_SIZE(aic311x_audio_map));
    		if (ret)
    			return ret;
    	} else {
    		ret = snd_soc_dapm_new_controls(
    			dapm, aic310x_dapm_widgets,
    			ARRAY_SIZE(aic310x_dapm_widgets));
    		if (ret)
    			return ret;
    
    		ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
    					      ARRAY_SIZE(aic310x_audio_map));
    		if (ret)
    			return ret;
    	}
    
    	return 0;
    }
    
    static int aic31xx_setup_pll(struct snd_soc_codec *codec,
    			     struct snd_pcm_hw_params *params)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int bclk_score = snd_soc_params_to_frame_size(params);
    	int mclk_p = aic31xx->sysclk / aic31xx->p_div;
    	int bclk_n = 0;
    	int match = -1;
    	int i;
    
    	/* Use PLL as CODEC_CLKIN and DAC_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_DAC2BCLK);
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
    		if (aic31xx_divs[i].rate == params_rate(params) &&
    		    aic31xx_divs[i].mclk_p == mclk_p) {
    			int s =	(aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
    				snd_soc_params_to_frame_size(params);
    			int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
    				snd_soc_params_to_frame_size(params);
    			if (s < bclk_score && bn > 0) {
    				match = i;
    				bclk_n = bn;
    				bclk_score = s;
    			}
    		}
    	}
    
    	if (match == -1) {
    		dev_err(codec->dev,
    			"%s: Sample rate (%u) and format not supported\n",
    			__func__, params_rate(params));
    		/* See bellow for details how fix this. */
    		return -EINVAL;
    	}
    	if (bclk_score != 0) {
    		dev_warn(codec->dev, "Can not produce exact bitclock");
    		/* This is fine if using dsp format, but if using i2s
    		   there may be trouble. To fix the issue edit the
    		   aic31xx_divs table for your mclk and sample
    		   rate. Details can be found from:
    		   http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf
    		   Section: 5.6 CLOCK Generation and PLL
    		*/
    	}
    	i = match;
    
    	/* PLL configuration */
    	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
    			    (aic31xx->p_div << 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);
    
    	/* DAC dividers configuration */
    	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].ndac);
    	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].mdac);
    
    	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
    	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
    
    	/* ADC dividers configuration. Write reset value 1 if not used. */
    	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
    	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
    			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
    
    	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
    
    	/* Bit clock divider configuration. */
    	snd_soc_update_bits(codec, AIC31XX_BCLKN,
    			    AIC31XX_PLL_MASK, bclk_n);
    
    	aic31xx->rate_div_line = i;
    
    	dev_dbg(codec->dev,
    		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
    		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
    		aic31xx->p_div, aic31xx_divs[i].dosr,
    		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
    		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
    		aic31xx_divs[i].madc, bclk_n);
    
    	return 0;
    }
    
    static int aic31xx_hw_params(struct snd_pcm_substream *substream,
    			     struct snd_pcm_hw_params *params,
    			     struct snd_soc_dai *dai)
    {
    	struct snd_soc_codec *codec = dai->codec;
    	u8 data = 0;
    
    	dev_dbg(codec->dev, "## %s: width %d rate %d\n",
    		__func__, params_width(params),
    		params_rate(params));
    
    	switch (params_width(params)) {
    	case 16:
    		break;
    	case 20:
    		data = (AIC31XX_WORD_LEN_20BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    		break;
    	case 24:
    		data = (AIC31XX_WORD_LEN_24BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    		break;
    	case 32:
    		data = (AIC31XX_WORD_LEN_32BITS <<
    			AIC31XX_IFACE1_DATALEN_SHIFT);
    		break;
    	default:
    		dev_err(codec->dev, "%s: Unsupported width %d\n",
    			__func__, params_width(params));
    		return -EINVAL;
    	}
    
    	snd_soc_update_bits(codec, AIC31XX_IFACE1,
    			    AIC31XX_IFACE1_DATALEN_MASK,
    			    data);
    
    	return aic31xx_setup_pll(codec, params);
    }
    
    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_reg2 = 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;
    	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_reg2 |= 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_reg2);
    
    	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 = 1; freq/i > 20000000 && i < 8; i++)
    		;
    	if (freq/i > 20000000) {
    		dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
    			__func__, freq);
    			return -EINVAL;
    	}
    	aic31xx->p_div = i;
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx_divs) &&
    		     aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; 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.
    		 */
    		if (gpio_is_valid(aic31xx->pdata.gpio_reset))
    			gpio_set_value(aic31xx->pdata.gpio_reset, 0);
    
    		regcache_mark_dirty(aic31xx->regmap);
    		dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
    	}
    
    	return 0;
    }
    
    static void aic31xx_clk_on(struct snd_soc_codec *codec)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	u8 mask = AIC31XX_PM_MASK;
    	u8 on = AIC31XX_PM_MASK;
    
    	dev_dbg(codec->dev, "codec clock -> on (rate %d)\n",
    		aic31xx_divs[aic31xx->rate_div_line].rate);
    	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on);
    	mdelay(10);
    	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on);
    	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on);
    	if (aic31xx_divs[aic31xx->rate_div_line].nadc)
    		snd_soc_update_bits(codec, AIC31XX_NADC, mask, on);
    	if (aic31xx_divs[aic31xx->rate_div_line].madc)
    		snd_soc_update_bits(codec, AIC31XX_MADC, mask, on);
    	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on);
    }
    
    static void aic31xx_clk_off(struct snd_soc_codec *codec)
    {
    	u8 mask = AIC31XX_PM_MASK;
    	u8 off = 0;
    
    	dev_dbg(codec->dev, "codec clock -> off\n");
    	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off);
    	snd_soc_update_bits(codec, AIC31XX_MADC, mask, off);
    	snd_soc_update_bits(codec, AIC31XX_NADC, mask, off);
    	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off);
    	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off);
    	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off);
    }
    
    static int aic31xx_power_on(struct snd_soc_codec *codec)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int ret = 0;
    
    	ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
    				    aic31xx->supplies);
    	if (ret)
    		return ret;
    
    	if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
    		gpio_set_value(aic31xx->pdata.gpio_reset, 1);
    		udelay(100);
    	}
    	regcache_cache_only(aic31xx->regmap, false);
    	ret = regcache_sync(aic31xx->regmap);
    	if (ret != 0) {
    		dev_err(codec->dev,
    			"Failed to restore cache: %d\n", ret);
    		regcache_cache_only(aic31xx->regmap, true);
    		regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
    				       aic31xx->supplies);
    		return ret;
    	}
    	return 0;
    }
    
    static int aic31xx_power_off(struct snd_soc_codec *codec)
    {
    	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
    	int ret = 0;
    
    	regcache_cache_only(aic31xx->regmap, true);
    	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 -> %d\n", __func__,
    		snd_soc_codec_get_bias_level(codec), level);
    
    	switch (level) {
    	case SND_SOC_BIAS_ON:
    		break;
    	case SND_SOC_BIAS_PREPARE:
    		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
    			aic31xx_clk_on(codec);
    		break;
    	case SND_SOC_BIAS_STANDBY:
    		switch (snd_soc_codec_get_bias_level(codec)) {
    		case SND_SOC_BIAS_OFF:
    			aic31xx_power_on(codec);
    			break;
    		case SND_SOC_BIAS_PREPARE:
    			aic31xx_clk_off(codec);
    			break;
    		default:
    			BUG();
    		}
    		break;
    	case SND_SOC_BIAS_OFF:
    		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
    			aic31xx_power_off(codec);
    		break;
    	}
    
    	return 0;
    }
    
    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);
    
    	aic31xx->codec = codec;
    
    	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;
    		}
    	}
    
    	regcache_cache_only(aic31xx->regmap, true);
    	regcache_mark_dirty(aic31xx->regmap);
    
    	ret = aic31xx_add_controls(codec);
    	if (ret)
    		return ret;
    
    	ret = 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;
    
    	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
    		regulator_unregister_notifier(aic31xx->supplies[i].consumer,
    					      &aic31xx->disable_nb[i].nb);
    
    	return 0;
    }
    
    static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
    	.probe			= aic31xx_codec_probe,
    	.remove			= aic31xx_codec_remove,
    	.set_bias_level		= aic31xx_set_bias_level,
    	.suspend_bias_off	= true,
    
    	.component_driver = {
    		.controls		= common31xx_snd_controls,
    		.num_controls		= ARRAY_SIZE(common31xx_snd_controls),
    		.dapm_widgets		= common31xx_dapm_widgets,
    		.num_dapm_widgets	= ARRAY_SIZE(common31xx_dapm_widgets),
    		.dapm_routes		= common31xx_audio_map,
    		.num_dapm_routes	= ARRAY_SIZE(common31xx_audio_map),
    	},
    };
    
    static const 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 dac31xx_dai_driver[] = {
    	{
    		.name = "tlv320dac31xx-hifi",
    		.playback = {
    			.stream_name	 = "Playback",
    			.channels_min	 = 2,
    			.channels_max	 = 2,
    			.rates		 = AIC31XX_RATES,
    			.formats	 = AIC31XX_FORMATS,
    		},
    		.ops = &aic31xx_dai_ops,
    		.symmetric_rates = 1,
    	}
    };
    
    static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
    	{
    		.name = "tlv320aic31xx-hifi",
    		.playback = {
    			.stream_name	 = "Playback",
    			.channels_min	 = 2,
    			.channels_max	 = 2,
    			.rates		 = AIC31XX_RATES,
    			.formats	 = AIC31XX_FORMATS,
    		},
    		.capture = {
    			.stream_name	 = "Capture",
    			.channels_min	 = 2,
    			.channels_max	 = 2,
    			.rates		 = AIC31XX_RATES,
    			.formats	 = AIC31XX_FORMATS,
    		},
    		.ops = &aic31xx_dai_ops,
    		.symmetric_rates = 1,
    	}
    };
    
    #if defined(CONFIG_OF)
    static const struct of_device_id tlv320aic31xx_of_match[] = {
    	{ .compatible = "ti,tlv320aic310x" },
    	{ .compatible = "ti,tlv320aic311x" },
    	{ .compatible = "ti,tlv320aic3100" },
    	{ .compatible = "ti,tlv320aic3110" },
    	{ .compatible = "ti,tlv320aic3120" },
    	{ .compatible = "ti,tlv320aic3111" },
    	{ .compatible = "ti,tlv320dac3100" },
    	{ .compatible = "ti,tlv320dac3101" },
    	{},
    };
    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 = MICBIAS_2_0V;
    	int ret;
    
    	of_property_read_u32(np, "ai31xx-micbias-vg", &value);
    	switch (value) {
    	case MICBIAS_2_0V:
    	case MICBIAS_2_5V:
    	case MICBIAS_AVDDV:
    		aic31xx->pdata.micbias_vg = value;
    		break;
    	default:
    		dev_err(aic31xx->dev,
    			"Bad ai31xx-micbias-vg value %d DT\n",
    			value);
    		aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
    	}
    
    	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 */
    
    static int 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 = devm_gpio_request_one(aic31xx->dev,
    					    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 ret;
    		}
    	}
    
    	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);
    
    	return ret;
    }
    
    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: %s codec_type = %d\n", __func__,
    		id->name, (int) id->driver_data);
    
    	regmap_config = &aic31xx_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;
    
    	ret = aic31xx_device_init(aic31xx);
    	if (ret)
    		return ret;
    
    	if (aic31xx->pdata.codec_type & DAC31XX_BIT)
    		return snd_soc_register_codec(&i2c->dev,
    				&soc_codec_driver_aic31xx,
    				dac31xx_dai_driver,
    				ARRAY_SIZE(dac31xx_dai_driver));
    	else
    		return snd_soc_register_codec(&i2c->dev,
    				&soc_codec_driver_aic31xx,
    				aic31xx_dai_driver,
    				ARRAY_SIZE(aic31xx_dai_driver));
    }
    
    static int aic31xx_i2c_remove(struct i2c_client *i2c)
    {
    	snd_soc_unregister_codec(&i2c->dev);
    	return 0;
    }
    
    static const struct i2c_device_id aic31xx_i2c_id[] = {
    	{ "tlv320aic310x", AIC3100 },
    	{ "tlv320aic311x", AIC3110 },
    	{ "tlv320aic3100", AIC3100 },
    	{ "tlv320aic3110", AIC3110 },
    	{ "tlv320aic3120", AIC3120 },
    	{ "tlv320aic3111", AIC3111 },
    	{ "tlv320dac3100", DAC3100 },
    	{ "tlv320dac3101", DAC3101 },
    	{ }
    };
    MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
    
    #ifdef CONFIG_ACPI
    static const struct acpi_device_id aic31xx_acpi_match[] = {
    	{ "10TI3100", 0 },
    	{ }
    };
    MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
    #endif
    
    static struct i2c_driver aic31xx_i2c_driver = {
    	.driver = {
    		.name	= "tlv320aic31xx-codec",
    		.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
    		.acpi_match_table = ACPI_PTR(aic31xx_acpi_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");
    

    Please help me, what changes to be done and which files.

    Regards

    Ravi V

  • Try this . This changes the processor to the master to generate BCLK and WCLK           

       sound-wm8960 {

                                  compatible = "simple-audio-card";

                                  simple-audio-card,name = "TI-TLV320AIC31xx-Card";

                                  simple-audio-card,format = "i2s";

                                  simple-audio-card,bitclock-master = <&sound0_master:>;

                                  simple-audio-card,frame-master = <&sound0_master:>;

                                  simple-audio-card,widgets =

                                  "Speaker", "Speaker";

                                  simple-audio-card,routing =

                                  "Speaker", "SPK";

     

                                  sound0_master: simple-audio-card,cpu {

                                                 sound-dai = <&sai1>;

                                                                               clocks = <&clk_sai1???>

     

                                  };

     

                                  codec_dai: simple-audio-card,codec {

                                                 sound-dai = <&tlv320aic31xx>;

                                                 

                                  };

                   };

  • &clk {
    assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>;
    assigned-clock-rates = <786432000>, <722534400>;
    };

    sound-wm8960 {
    compatible = "simple-audio-card";
    simple-audio-card,name = "TI-TLV320AIC31xx-Card";
    simple-audio-card,format = "i2s";
    simple-audio-card,bitclock-master = <&sound0_master>;
    simple-audio-card,frame-master = <&sound0_master>;

    simple-audio-card,widgets =
    "Speaker", "Speaker";
    simple-audio-card,routing =
    "Speaker", "SPK";

    sound0_master: simple-audio-card,cpu {
    sound-dai = <&sai1>;
    clocks = <&clk IMX8MQ_CLK_SAI1_ROOT>;
    };

    sound0_master: simple-audio-card,codec {
    sound-dai = <&tlv320aic31xx>;
    };
    };

    I have updated : But same issue.....

    Ans also , i have refereed the link for the clock setting: community.nxp.com/.../948462

    Regards

    Ravi V

  • &clk {
    assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>;
    assigned-clock-rates = <786432000>, <722534400>;
    };

    sound-wm8960 {
    compatible = "simple-audio-card";
    simple-audio-card,name = "TI-TLV320AIC31xx-Card";
    simple-audio-card,format = "i2s";
    simple-audio-card,bitclock-master = <&sound0_master>;
    simple-audio-card,frame-master = <&sound0_master>;

    simple-audio-card,widgets =
    "Speaker", "Speaker";
    simple-audio-card,routing =
    "Speaker", "SPK";

    sound0_master: simple-audio-card,cpu {
    sound-dai = <&sai1>;
    clocks = <&clk IMX8MQ_CLK_SAI1_ROOT>;
    };

    sound0_master: simple-audio-card,codec {
    sound-dai = <&tlv320aic31xx>;
    };
    };

    I have updated as per your suggestion: But same issue, it is not resolved.....

    Ans also , i have refereed the link for the clock setting: community.nxp.com/.../948462

    Regards

  • One question.. With this change the source should now generate LRCK ,BCK  from the processor side . In the past the codec was creating the timings.

    Is it possible using a play command try to run 44.1Khz and 48Khz and see if LRCK and BCK show 48k and 1.53Mhz. Do not worry about the sound 

  • Hi Sanjay,

    After the change, we have checked the freq, it same as privious freq. Its not working.

    I have tried to set  the i2c setting ( 0x0b 0x81 and 0x0c 0x86)  in the console window and the playback speed is good. And also, i executed in commands during bootup time during kernel booting time, it was not working. 

    So, i need your suggestion to set the clk & reg setting in .dts file and tlv320aic31xx.c file. Could you please suggest a solution.

    Regards

    Ravi V

  • Hi Sanjay,

    Can you please some solution.

    Regards

    Ravi V

  • HI Sanjay,

    Any suggestions:

    Regards

    Ravi V

  • I just wished to check? Did you try the aplay command?