天天看點

TLV320AIC310X音頻

轉載自Ti論壇:http://www.deyisupport.com/question_answer/analog/audio/f/42/t/67485.aspx?pi239031348=1

能看,隻是圖不知道為什麼消失了,對着手冊仔細摸索了。如果誰有興趣可以一起探讨。

                                                                                                 TLV320AIC310X音頻CODEC内部寄存器的正确配置

                                                                                                                                      聶景貴        德州儀器應用工程師

         摘要

TLV320AIC310X,TI通用音頻CODEC系列,包含有AIC3101/04/05/06/07。 以其優越的音質效果,靈活的信号處理能力,被廣泛應用于便提式消費類電子産品中,例如音樂手機,PMP,DV,錄音筆等。然而,對于許多初始接觸此類CODEC的工程師來講,面對名目繁多,使用靈活的内部寄存器設定時,要正确了解使用該器件仍然是一件比較困難的事。

本文詳細讨論了AIC310X内部寄存器設定的含義,以幫助産品研發人員正确了解内部寄存器的含義,充分發揮該類器件的功能及縮短産品研發周期。本文所包含執行個體中寄存器的配置可以直接移植到使用者應用系統主程式之中,無需作任何修改或僅僅作極少數的調整根據不同設定要求,例如系統主時鐘差別,輸入輸出端子不同組合等。

1   AIC310X内部寄存器的配置設定

AIC310X内部寄存器被配置設定成兩頁:Page0和Page1。Page0寄存器用于器件功能的配置,Page1僅用于音效處理數字濾波器系數的設定,例如,低音加重,3D音效等。盡管每一頁含有多達128個寄存器(包含保留寄存器以及隻讀寄存器),事實上,在許多應用場合下,使用者僅需要對少數幾個寄存器對其進行操作,而絕大數可以使用其預設值,無需任何操作。

AIC310X内部寄存器I2C讀寫格式如下

本文以AIC3104為例,針對其内部不同的功能子產品以應用執行個體的方式,對相關寄存器作詳細的探讨,以友善使用者根據應用要求正确了解與配置AIC310X内部寄存器。

提示1:在AIC310X音頻CODEC初始上電時,必須確定至少10ns 以上的硬體複位低周期,以便後續I2C讀寫正常。

2   AIC310X内部時鐘,I2S接口,輸出級配置寄存器

下述功能子產品寄存器的配置可以在系統初始化時被執行,在應用中系統主處理器不會對其進行頻繁的操作。

2.1 時鐘寄存器

AIC310X内部時鐘的産生非常靈活,一個顯著的特點是即使在系統不能提供主時鐘(MCLK)的情況下,仍可以由音頻接口的位時鐘(BCLK)來産生CODEC内部所需要的所有動作時鐘。有兩個通路用于時鐘的産生,對于正常音頻輸入主時鐘,例如11.2896 MHz /12.288MHz,AIC310X可以使用内部整數倍分頻器(Q值),以降低系統的功耗。其他時鐘如12M,13MHz 等非正常音頻主時鐘,可以利用内部PLL來精密産生。AIC310X時鐘寄存器由Register(簡寫成Reg) 2到7以及11,101,102所組成,其時鐘配置樹及對應的寄存器如圖1所示,粗體為上電預設值。

         圖 1      AIC310X 内部時鐘産生流程

執行個體1:24MHz系統主時鐘(MCLK)輸入,使用PLL,ADC/DAC采樣頻率為48KHz,配置PLL的P.R.J.D值如下:

P=2,   R=1,    J=8,    D=1920

時鐘寄存器設定如下:

W30  65  00          使用PLL來産生codec内部時鐘

W30  07  00          選擇48KHz參考采樣頻率

W30  03  P2          允許PLL,P=2

W30  04  20           J=8

W30  05  1E           1E為D值的高8位

W30  06  00           00為D值的低6位

提示2:D值的轉換(十進制轉換為D值2個16進制值)

Step 1: 轉換十進制D值到16進制,再到二進制

1920=0x780H=0111 10000000B

Step 2: 未滿14位二進制值補足零到高位以形成完整的14位二進制值

0111 1000 0000B==00 0111 1000 0000B

Step 3: 根據D值寄存器存貯的規定,補足兩個零到上述14位D值的低位以形成兩個完整的位元組(寄存器6要求D1.D0位為00 )

00 0111 1000 0000B →00 0111 1000 0000 00B

Step 4: 将上述16位二進制值分成2個位元組分别用于Reg 6和5

Reg 6=00 0111 10=1E  .Reg 5=00 0000 00=00

提示3:Reg 5的寫入必須立即緊跟着 Reg 6,兩個寄存器必須同時寫入以確定PLL正常動作。

提示4:在配置完PLL後,必須等待50ms以上再上電 ADC 或DAC。

2.2 音頻I2S接口寄存器

AIC310X除支援标準格式音頻接口外,還支援分時複用模式(TDM),幾個音頻CODEC可以共享一根I2S總線,節省此類應用中主處理的硬體資源。另外,AIC310X的音頻接口可根據系統要求靈活地配置成I2S主模式(BCLK/WCLK由AIC310X産生)或從模式(BCLK/WCLK輸入到AIC310X),Reg 8.9.10控制AIC310X音頻接口。

Reg 8: D7-D6  接口主從模式控制

         11   主模式, BCLK/WCLK從AIC310X輸出

00   從模式, BCLK/WCLK輸入到AIC310X

D5  僅分時複用(TDM)時使用

                                 0   I2S DATA線不設定為高阻狀态

1   I2S DATA線設定為高阻狀态

D4  僅主模式時使用

0   當内部ADC以及DAC POWER Off時BCLK/WCLK停止輸出

1   當内部ADC以及DAC POWER Off時BCLK/WCLK仍在輸出

Reg 9: D7-D6  資料接口模式選擇

00=I2S       01=DSP      10=RJ        11=LJ

D5-D4  資料字長選擇

00=16bits    01=20bits   10=24bits    11=32bits

D3  僅有效于主模式

0    連續BCLK時鐘輸出,每WCLK中BCLK時鐘數目= 2X資料字長

1    固定BCLK時鐘輸出,每WCLK中BCLK時鐘數目= 256

      D2-D1  ADC/DAC重新同步

1    當一幀中群時延超過±1/4fs時重新自動同步CODEC時鐘

0    不重新同步

D0  重新同步時靜音的動作

1    重新同步期間,ADC/DAC自動靜音

0    重新同步期間,ADC/DAC 并不自動靜音

Reg10: 通常僅用于分時複用模式(TDM),用于控制在一幀中資料起始位的位置。

提示5:建議在正常應用中當 Reg 9 D2D1D0設定為1,以消除由于資料(DATA)輸入不同步而産生的雜音現象。

執行個體2:配置音頻接口主模式,24位,I2S格式

         W30 08 D0            接口主模式,即使在ADC以及DAC POWER Off時BCLK/WCLK仍有輸出

         W30 09 27            24bit ,I2S格式,允許重新同步

2.3 輸出級配置

Reg 14.38.40.42設定了AIC310X輸出端子的連接配接模式,共模電壓(直流偏置電壓)及電容輸出型驅動器上電延時等。

Reg 14   配置HPLOUT/HPROUT及HPLCOM/HPRCOM輸出端子連接配接方式,圖2是二種典型的應用:

                            Cap mode Stereo Headphone

                            External Stereo Single-end Amp

                                      Stereo Line out

                                           (1)

                                 Cap mode Stereo headphone

                                 External Mono Differential Amp

                           Stereo Line out

                      (2)

圖 2    AIC310X 常用輸出配置

Reg 38   輸出級驅動器短路檢測, 建議使用預設值

Reg 40   根據CODEC的電源電壓配置适當的輸出直流偏置電壓,以擷取無失真信号最大擺幅

Reg 42   控制輸出直流偏壓對輸出電容充電的速度以消除電容輸出應用時的POP聲

執行個體3:3.3V CODEC 電源, HPLOUT/HPROUT電容型輸出

W30 0E 80            電容型輸出

W30 28 40            輸出直流偏壓電壓設定為1.65V

W30 2A 8E            輸出級上升延時400ms,信号上升時間4ms

3. ADC通道寄存器

相對于其他類型的CODEC,AIC310X ADC通道增加了兩個附加功能:AGC及數字音效處理。它們可以對輸入信号進行數字域的處理以進一步地改善錄制信号品質,相關寄存器的配置将在章節5中詳細讨論。除此之外,由Reg 15 到 Reg 25 控制模拟輸入到ADC通道的選擇及ADC的動作 。

AIC310X的模拟輸入增加了許多靈活性,包括通道間混音,通道間自由切換,通道間輸入電平的比對(例如FM信号輸入與基帶信号輸入),支援差分或單端輸入(AIC3105除外) 等。内部內建的低噪聲PGA(可程式設計增益放大器)可用于小信号的放大,可選的偏置電壓輸出支援了多種麥克風偏置電壓的要求。

AIC310X ADC通道模拟輸入及相應的控制寄存器如圖3所示(以AIC3104 為例)

            圖3      ADC通道模拟輸入及相應的控制寄存器            

執行個體4:單端MIC從AIC310X MIC1/LP輸入。MIC偏置電壓為2.5V,放大增益為26dB。I2S L/R通道同時輸出麥克風信号

    W30 13 04           連接配接MIC1LP到  L-PGA,MIC1設定為單端輸入模式,L-ADC上電

W30 18 00           同時連接配接MIC1LP到R-PGA

W30 16 7C           R-ADC上電

W30 19 40           麥克風偏置電壓為2.5V

W30 0F 34           L-PGA增益設定為26dB

W30 10 34           R-PGA增益設定為26dB

4. DAC模拟輸出通道

AIC310X模拟輸出比較靈活,圖4顯示了DAC及模拟輸出通道相關寄存器的設定。

               圖4       DAC及模拟輸出通道寄存器的設定

提示3: ① AIC310X支援3路DAC輸出,DAC-1/DAC-2/DAC-3,建議應用中僅适用DAC-1輸出,以簡化寄存器設定,提高系統的性能。

② 所有模拟輸出端子可實行電平的調整,建議正常應用中電平設定值為0dB,最大不應大于3dB。

③ AIC 310X支援模拟及數字音量調整,建議使用模拟音量調整。

④ HPLCOM/HPRCOM獨立應用時,注意寄存器的設定順序如執行個體7,8所示。

執行個體5:配置圖2(1)所示的輸出,Stereo Headphone, Stereo external audio amplifier.     

W30 25 E0           L-DAC/R-DAC上電,HPLCOM獨立單端輸出

W30 29 01           L-DAC選擇DAC-L1,R-DAC選擇 DAC-R1,左通道DAC數字音量跟随右通道音量值。

W30 2C 09           設定DAC數字音量=0dB。

W30 26 10           HPRCOM獨立單端輸出。

W30 33 00           HPLOUT上電非靜音,電平設定= 0dB

W30 2F 80           HPLOUT通道模拟音量設定,DAC-L1引入到HPLOUT,音量= 0dB

W30 3A 00           HPLCOM上電非靜音,電平設定=0dB

W30 36 80           HPLCOM模拟音量設定, DAC-L1引入到HPLCOM,音量=0dB

W30 41 00           HPROUT上電,非靜音,電平設定=0dB

W30 40 80           HPROUT模拟音量設定,DAC-R1引入到HPROUT,音量=0dB

W30 48 00           HPRCOM上電非靜音,電平=0dB

W30 47 80           HPRCOM模拟音量設定DAC-R1引入到HPRCOM,音量=0dB

W30 07 8A           L-DAC播放I2S-L輸入信号, R-DAC播放I2S-R輸入信号

 執行個體6:配置圖2⑵所示的輸出, Stereo Headphone, Differential Mono audio amplifier, Stereo Line out

W30 25 E0          同執行個體5

W30 29 01          同執行個體5

W30 2C 00          同執行個體5

W30 26 18          HPRCOM配置成HPLCOM的差分對

W30 52 80          DAC-L1引入到線性輸出端子,音量=0dB

W30 5C 80          DAC-R1引入到線性輸出端子,音量=0dB

W30 56 09          L路線性輸出端子上電非靜音,電平設定=0dB

W30 5D 09          R路線性輸出端子上電非靜音,電平設定=0dB

W30 33 00          同執行個體5

W30 2F 80          同執行個體5

W30 3A 00          同執行個體5

W30 36 8C          DAC-L1引入到HPLCOM,音量=-6dB

W30 39 8C          DAC-R1引入到HPLCOM,音量=-6dB

注:R36,R39将左右路輸入信号混合以産生單聲道輸出信号

                            W30 41 00          同執行個體5

                            W30 40 80          同執行個體5

                            W30 07 8A          同執行個體5

5   AIC310X附加功能

三個附加功能進一步增強AIC310X音色處理效果及應用靈活性。

①AGC

②數字音效濾波器

③模拟有源及無源旁路直通

5.1 AGC

為了提高語音錄制效果,AIC310X提供了AGC功能來維持錄音電平的恒定輸出及減少環境噪聲,9個專用寄存器Reg 26到R35控制了整個的動作。了解AGC的幾個變量有助于正确設定AGC的參數

                             Target Gain               錄音信号最終恒定輸出電平值

                             Attack Time               決定了AGC降低PGA增益的速度

                             Decay Time                決定了AGC增加PGA增益的速度

                             Noise gate threshold      輸入信号平均能量低于此值時,AGC認為是噪聲而保持輸出在靜音

                             Max PGA gain applicable   AGC能夠放大輸入信号的增益最大值

                             Hysteresis                用于消除AGC動作時的呼吸效應

                             Noise detect Debounce     設定一個時間視窗來檢測輸入噪聲信号電平

                             Signal detect Debounce    設定一個時間視窗來檢測輸入信号電平

提示7:① AGC Max PGA Gain applicable( 簡稱AGC Gain)與PGA Gain 關關聯作:

當PGA Gain>AGC Gain時,AGC放大信号最大增益由AGC Gain決定。當PGA Gain<AGC Gain,AGC放大信号的最大增益由PGA Gain決定。

② Hysteresis動作原理是:

AGC輸出從靜音轉變為正常語音信号輸出僅當輸入信号電平≥ Noise gate threshold + Hysteresis。

AGC輸出從正常語音信号轉變為靜音輸出僅當輸入信号電平≤ Noise gate threshold - Hysteresis。

Hysteresis 的動作如圖5 所示,目的是減少臨界狀态(Noise gate threshold)時AGC呼吸效應。

                      圖5      Hysteresis 的動作

③ AGC功能的最佳應用需要有一定的經驗及技巧,尤其是Noise gate threshold及Hysteresis的設定。

   Step1 :  在沒有語音信号輸入時,降低Max PGA gain applicable 以使輸出噪聲達到可接受水準。

   Step2 :  輸入最低的語音信号,增加Noise gate threshold以事輕微信号可以被放大或檢測。 

   Step3 :  如果語音信号在結尾時比較嘈雜,減少Decay Time。如果語音信号在開始時較差,增加Attack Time

   Step4 :  反複調整AGC 變量以獲得最佳錄制語音信号

執行個體8  環境噪聲相對于輸入信号幅度較小。AGC 變量設定如下:

                  Target gain = -5.5 db

                  Attack time = 20ms,Decay time = 500ms

                  Noise threshold = -84db

                  Maximum gain applicable =32db

                  Hysteresis = 1db

                  Noise detect debounce = 512ms,Signal detect debounce = 32ms

        寄存器設定值如下:

                  W30 1A 8F         Left AGC enable, Target gain = -5.5db, Attack time = 20ms, decay time = 500ms

                  W30 1B 9A         Left AGC Maximum gain applicable = 32db

                  W30 1C 38         Left AGC Hysteresis =1db, noise threshold = -84db

                  W30 22 7F         Left AGC Noise detect debounce = 512ms, signal debounce = 32ms

                  W30 1D 8F         Right AGC enable, Target gain = -5.5db, Attack = 20ms, decay = 500ms

                  W30 1E 9A         Right AGC Maximum gain applicable = 32db

                  W30 1C 38         Right AGC Hysteresis =1db, noise threshold = -84db

                  W30 23 7F         Right AGC Noise detect debounce = 512ms, signal debounce = 32ms

執行個體8  環境噪聲相對于輸入信号幅度較大,AGC 變量設定如下:

                  Target gain = -5.5 db

                  Attack time = 20ms,Decay time = 500ms

                  Noise threshold = -80db

                  Maximum gain applicable =30db

                  Hysteresis = 3db

                  Noise detect debounce = 512ms,Signal detect debounce = 32ms

         寄存器設定值如下:

                  W30 1A 8F         Left AGC enable, Target gain = -5.5db, Attack time = 20ms, decay time = 500ms

                  W30 1B 96         Left AGC Maximum gain applicable = 30db

                  W30 1C b6         Left AGC Hysteresis =3db, noise threshold = -80db

                  W30 22 7F         Left AGC Noise detect debounce = 512ms, signal debounce = 32ms

                  W30 1D 8F         Right AGC enable, Target gain = -5.5db, Attack time = 20ms, decay time = 500ms

                  W30 1E 96         Right AGC Maximum gain applicable = 30db

                  W30 1C b6         Right AGC Hysteresis =3db, noise threshold = -80db

                  W30 23 7F         Right AGC Noise detect debounce = 512ms, signal debounce = 32ms

6.2 數字音效處理濾波器

AIC310X提供了各種數字音效處理以進一步提高音質效果,低音加重/EQ/3D是最普遍的應用。Page1寄存器用于存放數字音效處理濾波器的設定值。

提示8:① 為了友善音效濾波器系數的生成,請至www.ti.com下載下傳TLV320AIC310XEVM示範軟體,利用此軟體可友善使用者生成各種音效處理的濾波器系數值。

② 在應用中,動态更改音效時,請注意以下寄存器寫入時序

        Step1  取消數字音效處理器

Step2  轉到Page1

Step3  寫入新的濾波器設定值到相關寄存器

Step4  轉回Page0

Step4  重新允許數字音效處理器

執行個體9:由其他音效轉為3D音效,3D具有較強的擴充深度。

                  W30 0C 00          取消數字音效處理器 Reg12 D3D2D1D0 = 0000

W30 00 01          轉到Page1

W30 35 7F 7F       3D 擴充深度系數

W30 00 00          轉到Page0

W30 08 04          3D音效處理允許  Reg8 D2 = 1

執行個體10:由3D音效轉為EQ音效。EQ中心頻率400Hz,帶寬200Hz,增益9dB

                  W30 08 00          3D音效處理關閉  Reg8 D2 = 0

W30 0C 00          # 取消數字音效處理器 (僅在動态調整數字音效濾波器系數寫入)

W30 00 01          轉到Page1

W30 01 7F FF       Left通道濾波器系數

W30 03 85 25       Left通道濾波器系數

W30 05 76 1D       Left通道濾波器系數

W30 07 00 00       Left通道濾波器系數

W30 09 41 A3       Left通道濾波器系數

W30 0B 00 00       Left通道濾波器系數

W30 0D 7D FF       Left通道濾波器系數

W30 0F 83 99       Left通道濾波器系數

W30 11 00 00       Left通道濾波器系數

W30 13 00 00       Left通道濾波器系數

W30 15 3A F3       Left通道濾波器系數

W30 17 F4 C3       Left通道濾波器系數

W30 19 50 4B       Left通道濾波器系數

W30 1B 7F 7F       Left通道濾波器系數

W30 1D 85 25       Right通道濾波器系數

W30 1F 76 1D       Right通道濾波器系數

W30 21 00 00       Right通道濾波器系數

W30 23 41 A3       Right通道濾波器系數

W30 25 00 00       Right通道濾波器系數

W30 27 7D FF       Right通道濾波器系數

W30 29 83 99       Right通道濾波器系數

W30 2B 00 00       Right通道濾波器系數

W30 2D 00 00       Right通道濾波器系數

W30 2F 3A F3       Right通道濾波器系數

W30 31 F4 C3       Right通道濾波器系數

W30 33 50 4B       Right通道濾波器系數

W30 00 00          轉到Page0

W30 0C 0A          打開數字音效處理器 Reg12 D3=1,D1 = 1

6.3   模拟有源及無源旁邊直通

6.3.1 有源PGA輸出旁邊

PGA的輸出可以旁路ADC及DAC而直接引入到所有輸出端子,其設定和DAC輸出完全一樣,僅僅相關寄存器序号相差數值1, 例如:

PGA_L/R到HPL/Rout               DAC_L/R到HPL/Rout

W30 2E 80                       W30 2F 80

W30 3F 80                       W30 40 80

6.3.2 無源旁邊功能

無源旁邊直通可以将輸入信号直接從輸入端子引到輸出端子,旁路掉内部所有電路,此種模式可以工作在無時鐘狀态。

提示9: AIC3104無源旁邊功能僅有效于MIC/Line1通道,MIC/Line2通道無此功能。         

執行個體11: 引入MIC1LP/RP到LEFT_LOP / RIGHT_LOP

W30 6C 11          MIC1LP to LEFT_LOP, MIC1RP to RIGHT_LOP

7   結束語

本文以應用執行個體的方式詳細叙述了AIC310X 内部功能子產品寄存器的設定,最終的應用可參考各功能子產品應用執行個體中寄存器的設定參數來作相應的調整。有關詳細的寄存器描述請參考AIC310X相關器件的資料手冊。應用中注意提示部分的内容。

8   參考文獻

      1:TLV320AIC3104,LOW-POWER STEREO AUDIO CODEC FOR PORTABLE AUDIO/TELEPHONY, 資料手冊.

    2: TLV320AIC3104 Programming Made Easy,TLV320AIC3104應用報告, WWW.TI.COM

    這前兩周一直在調AIC3104的驅動,這是個音頻codec晶片,可以實作語音對講功能。AIC3104是通過I2C方式與CPU通信,來設定寄存器,另外是IIS接口進行語音的Mic_in和Line_out功能。已經通了。能夠實作功能了。。剛好給樓主分享下。樓主可以參考參考。。 下面是aic3104的驅動源代碼:

  1. #include <linux/unistd.h>  
  2. #include <linux/module.h>  
  3. //#include <linux/config.h>  
  4. #include <linux/errno.h>  
  5. #include <linux/miscdevice.h>  
  6. #include <linux/fcntl.h>  
  7. #include <linux/init.h>  
  8. #include <linux/delay.h>  
  9. #include <linux/proc_fs.h>  
  10. #include <linux/workqueue.h>  
  11. #include <asm/uaccess.h>  
  12. #include <asm/system.h>  
  13. #include <asm/io.h>  
  14. //#include <linux/kcom.h>  
  15. #include <linux/random.h>  
  16. //#include "stapp_main.h"  
  17. #include "sti7105.h"  
  18. #include "stsys.h"  
  19. #include "stddefs.h"  
  20. #include "sti2c.h"  
  21. #include "staudlx_aic3104.h"  
  22. //#include "stcommon.h"  
  23. //#include "stavmem.h"  
  24. ///PRE-DEFINITIONS/  
  25. //module name string  
  26. #define MOD_STR     "aic3104"  
  27. #define MOD_STR_E    "aic3104 ERROR"  
  28. //chip and id register addr  
  29. #define CHIP_A_I2C_ADDR  0x30//0x30//0x18  
  30. #define I2C0 0x00  
  31. //#define TRUE (bool) 1  
  32. #define AIC3104_WORK_MODE  0x00  
  33. #define GLOBAL_DEBUG  
  34. //AIC3104 version info.  
  35. #define AIC3104_VER_MIN  0//  0~63  
  36. #define AIC3104_VER_SEC  0//  0~63  
  37. #define AIC3104_VER_MAJ  1//  0~31  
  38. #define AIC3104_VER_DAY  25// 1~31  
  39. #define AIC3104_VER_MON  3// 1~12  
  40. #define AIC3104_VER_YER  10// 00~63  
  41. static STI2C_Handle_t i2c_handle;  
  42. static int nbpages = 0, chains[2] = {0,0};  
  43. typedef enum _tagDRV_ERR_CODE_  
  44. {  
  45.  //general return code  
  46.  NO_ERROR = 0,  
  47.  ERR_NO_DEV ,  
  48.  ERR_GPIO_I2C_RD,  
  49.  ERR_GPIO_I2C_WR,  
  50.  ERR_VERSION_CHK,  
  51.  ERR_DRV_REG,  
  52.  ERR_OUT_OF_RANGE,  
  53.  ERR_INVALID_CMD  
  54. }DRV_ERR_CODE;  
  55. //#define cfg_bytes_write(buf,NumToWrite,Timeout,nwrite)  STI2C_Write(i2c_handle,buf, NumToWrite, Timeout, nwrite)  
  56. //#define cfg_bytes_read(buf,NumToRead,Timeout,nread)  STI2C_Read(i2c_handle,buf, NumToRead, Timeout, nread)  
  57. /// 子產品軟體版本定義  
  58. typedef struct {  
  59.   unsigned  minver : 6; //  0~63  
  60.   unsigned  secver : 6; //  0~63  
  61.   unsigned  majver : 5; //  0~31  
  62.   unsigned  day : 5; // 日: 1~31  
  63.   unsigned  month : 4; // 月: 1~12  
  64.   unsigned  year : 6; // 年: 2000~2063  
  65. } SWVERSION, *PSWVERSION;  
  66. #define VINFO2STR(str, v) sprintf(str, "V%d.%d.%d build%04d%02d%02d\n", v.majver, v.secver, v.minver, v.year+2000, v.month, v.day)  
  67. typedef struct aic3104_information {  
  68.  U8 *Buffer_p;   
  69.  U32 Size;  
  70. } aic3104_info_t;  
  71. //data type  
  72. ///PRE-DEFINITIONS/  
  73. static const U8 *MODULE_NAME = NULL, *MODULE_NAME_E = NULL;  
  74. //aic3104初始化資料,拷貝自楊總的代碼,未作任何修改  
  75. static U8 init_data[] =  
  76. {  
  77.  2, 0x00,  
  78.  4, 0xc0,  
  79.  7, 0x0a,  
  80.  8, AIC3104_WORK_MODE,  
  81.  9, 0x08,  
  82.  14, 0x88,  
  83.  15, 0x00,  
  84.  16, 0x00,  
  85.  17, 0x0f,  
  86.  18, 0xf0,  
  87.  19, 0x7f,  
  88.  22, 0x7f,  
  89.  25, 0x80,  
  90.  37, 0xd0,  
  91.  38, 0x0c,  
  92.  40, 0x82,  
  93.  43, 0x00,  
  94.  44, 0x00,  
  95.  47, 0x80,  
  96.  51, 0x0f,  
  97.  64, 0x80,  
  98.  65, 0x0f,  
  99.  82, 0x80,  
  100.  86, 0x0b,  
  101.  92, 0x80,  
  102.  93, 0x0b,  
  103.  101, 0x01  
  104. };  
  105. ST_DeviceName_t PIO_DeviceName[] = {"PIO0","PIO1","PIO2","PIO3","PIO4","PIO5","PIO6","PIO7","PIO8","PIO9","PIO10","PIO11","PIO12","PIO13","PIO14","PIO15","PIO16","PIO17","PIO18","PIO19","PIO20","PIO21","PIO22","PIO23","PIO24","PIO25","PIO26"};  
  106. extern S32 GetAudioHoldSignal(void);  
  107. static S32 chip_detect(void)  
  108. {  
  109.         U32 ErrorCode;  
  110.  U32 nread ,nwrite;  
  111.  U8 temp_buf[2];  
  112.  if (NULL == temp_buf)  
  113.         {  
  114.   return -1;  
  115.         }  
  116. // if(cfg_bytes_read(CHIP_A_I2C_ADDR, 0x08, &buf, 1))  
  117.  temp_buf[0] = 0x08;    
  118.  ErrorCode = STI2C_WriteNoStop(i2c_handle, temp_buf, 1, 100, &nwrite);  
  119.  if(ST_NO_ERROR != ErrorCode )  
  120.  {  
  121.   printk("I2C write addr error : 0x%x\n",ErrorCode);  
  122.   return ErrorCode;  
  123.  }  
  124.  ErrorCode = STI2C_Read(i2c_handle, temp_buf, 1, 100, &nread);  
  125.  if(ST_NO_ERROR != ErrorCode )  
  126.  {  
  127.   printk("I2C read data error : 0x%x\n",ErrorCode);  
  128.   return ErrorCode;  
  129.  }  
  130. // printk("Reg 08 = 0x%x\n",temp_buf[0]);  
  131.  return NO_ERROR;  
  132. }  
  133. static U32 audio_detect(void)  
  134. {  
  135. #if 0  
  136.  S32 state;  
  137.  state = GetAudioHoldSignal();  
  138.  if(state < 0)  
  139.  {  
  140.   printk("\n%s: GetAudioHoldSignal() call failed!", MODULE_NAME_E);  
  141.   return -ERR_NO_DEV;//Not support audio  
  142.  }  
  143.  return state;  
  144. #else  
  145.  return 0;//audio is always supported  
  146. #endif  
  147. }  
  148. static S32 audio_mode_init(void)  
  149. {  
  150.  U32 i;  
  151. // U32 addr,dat;  
  152.  S32 ret = NO_ERROR;  
  153.  U32 nwrite;  
  154.  STI2C_Params_t I2C_Params;  
  155.  U32 ErrorCode;  
  156.  I2C_Params.I2cAddress = 0x30;  
  157.  I2C_Params.AddressType      = STI2C_ADDRESS_7_BITS;  
  158.         I2C_Params.BaudRate         = STI2C_RATE_NORMAL;  
  159.         I2C_Params.BusAccessTimeOut = 100000;  
  160.         ErrorCode = STI2C_SetParams(i2c_handle, &I2C_Params);  
  161.  if(ST_NO_ERROR != ErrorCode)  
  162.  {  
  163.   printk("I2C set params error:%u\n",ErrorCode);  
  164.   return -1;  
  165.  }  
  166. // printk("I2C set params sucess!\n");  
  167.  for(i = 0; i < sizeof(init_data); i += 2)  
  168.  {  
  169.  // addr = init_data[i];  
  170.  // dat = init_data[i + 1];  
  171.     //    ret |= cfg_bytes_write(CHIP_A_I2C_ADDR,addr,&dat,1);  
  172.   ret |= STI2C_Write(i2c_handle,&init_data[i],2,100,&nwrite);  
  173.   if(ST_NO_ERROR != ErrorCode)  
  174.   {  
  175.    printk("I2C write data error : 0x%x",ErrorCode);  
  176.   }  
  177. //  printk("init write data : [%d] >> %x\n",init_data[i],init_data[i+1]);  
  178.   if(ret)  
  179.   {  
  180.    //printk("\n%s: i2c write failed in audio_mode_init() when write 0x%02x to 0x%02x", MODULE_NAME_E, dat, addr);  
  181.    printk("\n%s: i2c write failed in audio_mode_init() when write 0x%02x to 0x%02x", MODULE_NAME_E, init_data[i],init_data[i+1]);  
  182.    return -ERR_GPIO_I2C_WR;  
  183.   }  
  184.  }  
  185.  return NO_ERROR;  
  186. }  
  187. #ifdef GLOBAL_DEBUG  
  188. S32 reg_dump(void)  
  189. {  
  190.  U32 i;  
  191. // U32 addr, dat;  
  192.  S32 ret = NO_ERROR;  
  193.  U32 nread,nwrite;  
  194.  U8 temp_buf[54];  
  195.  U32 ErrorCode;  
  196. // printk("start read data :\n\n\n\n");  
  197.  for(i = 0; i < sizeof(init_data); i += 2)  
  198.  {  
  199. //  addr = init_data[i];  
  200. //  dat = 0xff;  
  201.  // ret |= cfg_bytes_read(CHIP_A_I2C_ADDR, addr, &dat, 1);  
  202.   ErrorCode = STI2C_WriteNoStop(i2c_handle,&init_data[i],1,100,&nwrite);  
  203.   if(ST_NO_ERROR != ErrorCode)  
  204.   {  
  205.    printk("reg_dmup: I2C write addr error:0x%x",ErrorCode);  
  206.    return ErrorCode;  
  207.   }  
  208. //  printk("write reg addr = %d\n",init_data[i]);  
  209.   ErrorCode = STI2C_Read(i2c_handle,&temp_buf[i + 1],1,100,&nread);  
  210.   if(ST_NO_ERROR != ErrorCode)  
  211.   {  
  212.    printk("reg_dmup: I2C write data error:0x%x",ErrorCode);  
  213.    return ErrorCode;  
  214.   }  
  215. //  printk("read data = 0x%x\n",temp_buf[i + 1]);  
  216.   if(init_data[i + 1] != temp_buf[i + 1])  
  217.   {  
  218.    printk("\n%s: data verify failed in addr %d:0x%x, read out 0x%x\n", MODULE_NAME, init_data[i], init_data[i + 1], temp_buf[i + 1]);  
  219.   }  
  220.  }  
  221. // printk("reg_dmup: sucess!\n");  
  222.  return ret;  
  223. }  
  224. #endif  
  225. static S32 dev_open1(struct inode * inode, struct file * file)  
  226. {  
  227.  return NO_ERROR;  
  228. }  
  229. static S32 dev_ioctl1(struct inode *inode, struct file *file, U32 cmd, U32 arg)  
  230. {  
  231. // U32 buf;  
  232.  U32 ret;  
  233.  U8 temp_buf[2];  
  234.  U32 __user *argp = (U32 __user *)arg;  
  235.  U32 nwrite;  
  236.  switch(cmd)  
  237.  {  
  238.   case AIC3104_SET_MIC_IN_MODE:  
  239.  //  buf = 0x70;  
  240.    temp_buf[0] = 0x15;  
  241.    temp_buf[1] = 0x70;  
  242.  //  ret = cfg_bytes_write(CHIP_A_I2C_ADDR, 0x15, &buf, 1);  
  243.    ret = STI2C_Write(i2c_handle,temp_buf,2,100,&nwrite);  
  244.    if(ST_NO_ERROR != ret)   
  245.    {  
  246.     printk("dev_ioctl: i2c write error :0x%x ",ret);  
  247.    }    
  248.  //  buf = 0x40;  
  249.    temp_buf[0] = 0x25;  
  250.    temp_buf[1] = 0x40;  
  251.  //  ret |= cfg_bytes_write(CHIP_A_I2C_ADDR, 0x25, &buf, 1);  
  252.    ret = STI2C_Write(i2c_handle, temp_buf,2,100,&nwrite);  
  253.    if(ret)  
  254.    {  
  255.     printk("\n%s: i2c write failed in mic in setting", MODULE_NAME_E);  
  256.     return -AIC3104_SET_MIC_IN_MODE_FAIL;  
  257.    }  
  258.    break;  
  259.   case AIC3104_SET_LINE_IN_MODE:  
  260.   // buf = 0x00;  
  261.    temp_buf[0] = 0x15;  
  262.    temp_buf[1] = 0x00;  
  263.   // ret = cfg_bytes_write(CHIP_A_I2C_ADDR, 0x15, &buf, 1);  
  264.    ret = STI2C_Write(i2c_handle,temp_buf,2,100,&nwrite);  
  265.    if(ST_NO_ERROR != ret)   
  266.    {  
  267.     printk("dev_ioctl: i2c write error :0x%x ",ret);  
  268.    }  
  269.   // buf = 0x00;  
  270.    temp_buf[0] = 0x25;  
  271.    temp_buf[1] = 0x00;  
  272.   // ret |= cfg_bytes_write(CHIP_A_I2C_ADDR, 0x25, &buf, 1);  
  273.    ret = STI2C_Write(i2c_handle,temp_buf,2,100,&nwrite);  
  274.    if(ret)  
  275.    {  
  276.     printk("\n%s: i2c write failed in mic in setting", MODULE_NAME_E);  
  277.     return -AIC3104_SET_MIC_IN_MODE_FAIL;  
  278.    }  
  279.    break;  
  280.   case AIC3104_GET_SW_VER:  
  281.    {  
  282.     SWVERSION ver;  
  283.     ver.day = AIC3104_VER_DAY;  
  284.     ver.month = AIC3104_VER_MON;  
  285.     ver.year = AIC3104_VER_YER;  
  286.     ver.minver = AIC3104_VER_MIN;  
  287.     ver.secver = AIC3104_VER_SEC;  
  288.     ver.majver = AIC3104_VER_MAJ;  
  289.     if(copy_to_user(argp, &ver, sizeof(SWVERSION)))  
  290.     {  
  291.      printk("\n%s: GET_SW_VERSION copy_to_user() failed.", MODULE_NAME_E);  
  292.      return -AIC3104_GET_SW_VER_FAIL;  
  293.     }  
  294.    }  
  295.    break;  
  296.   default:  
  297.    printk("\n%s: un-supported ioctl command[0x%08x]!", MODULE_NAME_E, cmd);  
  298.    return -AIC3104_IOCTL_FAIL;  
  299.  }  
  300.  return AIC3104_IOCTL_OK;  
  301. }  
  302. static  U32 dev_close1(struct inode * inodep, struct file * filep)  
  303. {  
  304.  return NO_ERROR;  
  305. }  
  306. static struct file_operations dev_fops =  
  307. {  
  308.  .owner = THIS_MODULE,  
  309.  .open = dev_open1,  
  310.  .ioctl  = dev_ioctl1,  
  311.  .release = dev_close1  
  312. };  
  313. static struct miscdevice device_driver =  
  314. {  
  315.  MISC_DYNAMIC_MINOR,  
  316.  "aic3104",  
  317.  &dev_fops  
  318. };  
  319. static void chip_init(void)  
  320. {  
  321. //#if(!RST_FOR_HB8016T)  
  322. #if 0  
  323.  U8 i;  
  324.  U32 j;  
  325.  Reset aic3104 in 7024T  
  326.  //set as a gpio  
  327.  j = HW_REG32(PORT_26_MODE);  
  328.  j &= 0xfc;  
  329.  HW_REG32(PORT_26_MODE) = j;  
  330.  //disable INT  
  331.  i = HW_REG8(GPIO_2_IE);  
  332.  i &= 0xbf;  
  333.  HW_REG8(GPIO_2_IE) = i;  
  334.  //set reset-port as output  
  335.  i = HW_REG8(GPIO_2_DIR);  
  336.  i |= 0x40;  
  337.  HW_REG8(GPIO_2_DIR) = i;  
  338.  HW_REG8(GPIO_26_DAT) = GPIO_26;  
  339.  udelay(500);  
  340.  HW_REG8(GPIO_26_DAT) = 0;//10ns is enough  
  341.  for(i = 0; i < 100; i++)  
  342.  {  
  343.   udelay(1000);  
  344.  }  
  345.  HW_REG8(GPIO_26_DAT) = GPIO_26;  
  346.  udelay(500);  
  347. #endif  
  348. //#endif  
  349. }  
  350. static S32 __init dev_init1(void)  
  351. {  
  352.  S32 ret = 0;  
  353.  MODULE_NAME = MOD_STR;  
  354.  MODULE_NAME_E = MOD_STR_E;  
  355.  STI2C_InitParams_t I2C_InitParams;  
  356.  STI2C_OpenParams_t I2C_OpenParams;  
  357.  U32 ErrCode;  
  358.  U32 ReadReg;  
  359. // SYS_ClearBitsDev32LE(ST7105_CFG_BASE_ADDRESS+0x154,(1<< 2));  
  360. // SYS_ClearBitsDev32LE(ST7105_CFG_BASE_ADDRESS+0x154,(1<< 3));  
  361. // SYS_SetBitsDev32LE  (ST7105_CFG_BASE_ADDRESS+0x154,(1<<10));  
  362. // SYS_SetBitsDev32LE  (ST7105_CFG_BASE_ADDRESS+0x154,(1<<11));  
  363.  STSYS_WriteRegDev32LE(ST7105_CFG_BASE_ADDRESS+0x154,0x6c00);  
  364.  ReadReg = STSYS_ReadRegDev32LE(ST7105_CFG_BASE_ADDRESS+0x154);  
  365.  STSYS_WriteRegDev32LE(0xFD020030,0xb9);  
  366.  STSYS_WriteRegDev32LE(0xFD020030,0x39);  
  367. // printk("<1> PIO2 Config Reg is %x\n",ReadReg);  
  368. //  ErrCode=ST_GetClockInfo(&CLOCK_Info);  
  369. //  if (ErrCode!=ST_NO_ERROR)  
  370. //   {  
  371. //     printk("Get Clock info error : %u\n",ErrCode);  
  372. //  return(ErrCode);  
  373. //   }   
  374.  memset(&I2C_InitParams,0,sizeof(STI2C_InitParams_t));  
  375.  I2C_InitParams.BaseAddress         = (U32 *)ST7105_SSC0_BASE_ADDRESS;  
  376.   I2C_InitParams.InterruptNumber     = ST7105_SSC0_INTERRUPT;  
  377. //  I2C_InitParams.InterruptLevel      = SSC_0_INTERRUPT_LEVEL;  
  378.  I2C_InitParams.MasterSlave         = STI2C_MASTER;  
  379.   I2C_InitParams.BaudRate            = STI2C_RATE_NORMAL;  
  380.   I2C_InitParams.MaxHandles          = 8;  
  381.   I2C_InitParams.ClockFrequency      = 0x5f5e100;  
  382. // I2C_InitParams.DriverPartition     = cache_partition_sdk[0];  
  383.   I2C_InitParams.PIOforSDA.BitMask   = PIO_BIT_3;  
  384.   I2C_InitParams.PIOforSCL.BitMask   = PIO_BIT_2;  
  385.   I2C_InitParams.EvtHandlerName[0]   = '\0';  
  386.   I2C_InitParams.GlitchWidth         = 0;  
  387.   I2C_InitParams.SlaveAddress        = 0;  
  388.   I2C_InitParams.FifoEnabled         = FALSE;  
  389.   strcpy(I2C_InitParams.PIOforSDA.PortName,PIO_DeviceName[2]);  
  390.   strcpy(I2C_InitParams.PIOforSCL.PortName,PIO_DeviceName[2]);  
  391.   ErrCode=STI2C_Init("I2C0",&I2C_InitParams);  
  392.   if (ErrCode!=ST_NO_ERROR)  
  393.   {  
  394.   printk("I2C Init ERROR : %u\n",ErrCode);  
  395.   return(ErrCode);  
  396.    }  
  397. //      printk("I2C init succes!\n");         
  398.         memset(&I2C_OpenParams,0,sizeof(STI2C_OpenParams_t));  
  399.  I2C_OpenParams.BusAccessTimeOut = 100000;  
  400.  I2C_OpenParams.AddressType      = STI2C_ADDRESS_7_BITS;  
  401.  I2C_OpenParams.I2cAddress       = 0x30;  
  402.  I2C_OpenParams.BaudRate         = STI2C_RATE_NORMAL;  
  403.  ErrCode=STI2C_Open("I2C0",&I2C_OpenParams, &i2c_handle);  
  404.  if (ST_NO_ERROR != ErrCode )  
  405.  {  
  406.   printk("<1> aic3104 i2c error: %u\n", ErrCode);  
  407.   printk("<2> I2cAddress is %x\n",I2C_OpenParams.I2cAddress);  
  408.   return;  
  409.  }  
  410. // printk("i2c_handle = 0x%x\n",i2c_handle);  
  411. // printk("I2C open success!\n");  
  412.  chip_init();  
  413. // printk("chip init success!\n");  
  414.  //detect support audio or not  
  415.  if(audio_detect())  
  416.  {  
  417.   printk("\n%s: hw config error, audio is not supported by this board!", MODULE_NAME_E);  
  418.   goto dev_init_exit;  
  419.  }  
  420. // printk("audio detect success!\n");  
  421.  //detect the chip  
  422.  if(chip_detect())  
  423.  {  
  424.   printk("\n%s: hw config error, can't find chip aic3104!", MODULE_NAME_E);  
  425.   goto dev_init_exit;  
  426.  }  
  427. // printk("chip detect success!\n");  
  428.  //init chip  
  429.  if(audio_mode_init())  
  430.  {  
  431.   goto dev_init_exit;  
  432.  }  
  433. // printk("audio_mode_init success!\n");  
  434. #ifdef GLOBAL_DEBUG  
  435.  //if(0)//reg_dump())  
  436.  if(reg_dump())  
  437.  {  
  438.   goto dev_init_exit;  
  439.  }  
  440. #endif  
  441. #if(!((0xd0 == AIC3104_WORK_MODE) || (0x00 == AIC3104_WORK_MODE)))  
  442.  #error "Work mode config error, compile stopped!";  
  443. #endif  
  444.  //register driver  
  445.  ret = misc_register(&device_driver);  
  446.  if(ret)  
  447.  {  
  448.   printk("\n%s: chip found but register failed[%d]", MODULE_NAME_E, ret);  
  449.   goto dev_init_exit;  
  450.  }  
  451.  printk("<1>audio codec driver registered successfully!\n");  
  452.  //KDPF(("\n%s: audio codec driver registered successfully, acts as %s!\n", MODULE_NAME, AIC3104_WORK_MODE ? "MASTER" : "SLAVE"))  
  453.  return NO_ERROR;  
  454. dev_init_exit:  
  455.  return -ERR_NO_DEV;  
  456. }  
  457. static void __exit dev_exit(void)  
  458. {  
  459.  misc_deregister(&device_driver);  
  460. }  
  461. module_init(dev_init1);  
  462. module_exit(dev_exit);  
  463. #ifdef MODULE  
  464. #include <linux/compile.h>  
  465. #endif  
  466. //module_param(norm_mode, int, S_IRUGO);  
  467. MODULE_INFO(build, UTS_VERSION);  
  468. MODULE_LICENSE("GPL");  
  469. MODULE_AUTHOR("hisilicon");  

繼續閱讀