日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

S5PV210 WM8960 ASOC 移植

發布時間:2023/12/20 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 S5PV210 WM8960 ASOC 移植 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內核版本Linux 3.9.11 ? ? ?編譯器版本 4.5.1

Asoc框架是linux內核采用的一種音頻子系統框架。他在alsa框架的基礎上又封裝了一層。實際上就把asoc移植看成alsa移植即可。(雖然2個我都不太懂,初學asoc驅動)
在對實際文件分析后我把alsa框架需要修改的主要為如下幾類:

SMDK_xxxx.c文件 --> Machine I2C子系統驅動 -->codec I2S控制器驅動

其中I2S控制器驅動和I2C子系統驅動由內核已經給出。I2S驅動主要是設置I2S相關的寄存器,便于ASOC其他部分(框架理解不是很透徹,這里可以看成PCM數據發送)發送數據。
而I2C子系統驅動則負責配置WM8960的寄存器。SMDK.c文件主要是負責將asoc各個部分通過一個結構體描述連接起來。他們都是由asoc更上層的結構進行調用的。

對于我們移植來說,主要是關心SMDK_xxxx.c這樣的Machine部分的文件。如果內核沒有的話,就需要自己動手寫了,我這里是沒有的,所以我去找了個S3c2451的WM8960的Machine文件,接下來說下修改步驟。
想要正確播放出聲音,第一步就需要修改machine中的dai結構體:

下面只說下主要的成員:

Cpu_dai_name? ?? ? ? 對應i2s控制器驅動
Codec_dai_name ? ? 對應于內核提供的codec文件中的同名dai 圖3 給出
Platform_name ? ? ? 用于數據傳輸的平臺名稱 (我猜的 I2SDMA?)
Codec_name ? ? ? ? ? 對應于控制codec的 i2c驅動
ops ? ? ? ? ? ? ? ? ? ? ? ? 主要成員是.hw_params變量,當通過alsa-util測試播放的時候,應用會通過 這個函數傳入一些控制參數來設置i2s和wm8960。 通過 圖2 劃線的2個參數就能對應到codec和i2s各自的控制函數當中。分別進行設置。參數則通過查看他們對應的函數就能得出。

圖2

圖3

修改后若使用默認的設置無法播放,則需要檢查設置讓關鍵的寄存器值變正確。
IIS設置主要要設置時鐘源選I2SCLK,通過EPLL產生時鐘,設置可以查看芯片手冊中的i2s時鐘路線圖,然后就是bfs,rfs,psr參數,通常使用bfs=32 rfs=256,因為wm8960中默認設置還會將傳入的頻率/256和/32,所以為了保證頻率正確就這樣設置,這兩個可以通過應用傳參得到。而psr就需要我們通過計算得到了,比如44100hz采樣率就是5 采樣率是22050時就是10。這是通過公式算出來的。(psr是i2s預分頻寄存器)

N + 1 = (67.7Mhz) / (256 * 44.1Khz) = 5.99N + 1 = (67.7Mhz) / (256 * 22.05Khz) = 11

我們只需要讓這些值真確寫入寄存器就好了。設置通過i2s控制器驅動中的i2s_set_clkdiv函數,當然這些只是設置,并沒有實際寫入到寄存器,真正寫入到寄存器的是config_setup函數,里面調用

set_bfs(i2s, bfs); set_rfs(i2s, rfs);

寫入寄存器,psr在最后進行設置。

if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {psr =m_psr;// i2s->rclk_srcrate / i2s->frmclk / rfs;printk("i2s %s setup psr:%d \r\n",__func__,psr);writel(((psr ) << 8) | PSR_PSREN, i2s->addr + I2SPSR);dev_dbg(&i2s->pdev->dev,"RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",i2s->rclk_srcrate, psr, rfs, bfs);}

可以看到我用m_psr替換掉了原始的psr計算,這是因為,我在machine中已經計算好了psr的值,傳入設置好的時候,不用計算直接寫入即可。
并且,i2s驅動中的set_clkdiv可能會少 rfs和psr的設置,加入即可。
(這些修改的部分是通過machine中的.hw_params函數設置的)
以下代碼是I2S.c中的代碼,添加了2和3兩個選項(這是通過調試得到的缺少的部分)。

#define DIV_RCLK 2 #define DIV_PSR 3 static int i2s_set_clkdiv(struct snd_soc_dai *dai,int div_id, int div) {struct i2s_dai *i2s = to_info(dai);struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;switch (div_id) {case SAMSUNG_I2S_DIV_BCLK:if ((any_active(i2s) && div && (get_bfs(i2s) != div))|| (other && other->bfs && (other->bfs != div))) {dev_err(&i2s->pdev->dev,"%s:%d Other DAI busy\n", __func__, __LINE__);return -EAGAIN;}printk(KERN_ERR"bfs:%d\r\n",div);i2s->bfs = div;break;case DIV_RCLK:if ((any_active(i2s) && div && (get_rfs(i2s) != div))|| (other && other->rfs && (other->rfs != div))) {dev_err(&i2s->pdev->dev,"%s:%d Other DAI busy\n", __func__, __LINE__);return -EAGAIN;}printk(KERN_ERR"rfs:%d\r\n",div);i2s->rfs = div;break;case DIV_PSR:{m_psr=div;}break;default:dev_err(&i2s->pdev->dev,"Invalid clock divider(%d)\n", div_id);return -EINVAL;}return 0; }

這里還需要注意一個函數就是i2s_txctrl ,這個函數控制著i2s的輸出,在函數的末尾可以看到設置IISCON和IISMOD寄存器,如果不出聲音可以在此跟蹤一下這兩個寄存器的狀態。
正確的狀態不知道的話可以先寫下裸機wm8960驅動以后再來驗證,裸機驅動wm8960的代碼網上還是比較多的。
我這里改成了con |1, 原因可以通過看手冊和跟蹤寄存器得出。


到此I2S部分和machine部分就修改完了。還要注意一點,如果iis設置全對,還是沒有聲音,這時就要考慮codec驅動的初始化問題了,以wm8960.c為例,我是在代碼中的wm8960_probe函數中看到了wm8960的一些寄存器初始化函數調用,一些關鍵的設置并不正確,于是修改為如下:

static int wm8960_probe(struct snd_soc_codec *codec) {struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);struct wm8960_data *pdata = dev_get_platdata(codec->dev);int ret;wm8960->set_bias_level = wm8960_set_bias_level_out3;if (!pdata) {dev_warn(codec->dev, "No platform data supplied\n");} else {if (pdata->capless)wm8960->set_bias_level = wm8960_set_bias_level_capless;}ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);if (ret < 0) {dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);return ret;}ret = wm8960_reset(codec);if (ret < 0) {dev_err(codec->dev, "Failed to issue reset\n");return ret;}wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);/* Latch the update bits *//*snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100);snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100);*///powersnd_soc_update_bits(codec, WM8960_POWER1,0x1c0,0x1c0);snd_soc_update_bits(codec, WM8960_POWER2,0x1f8 ,0x1f8);snd_soc_update_bits(codec, WM8960_POWER3,0x00c ,0x00c);// clock CLKSEL = 0 : no PLL -> SYSCLK using MCLKsnd_soc_update_bits(codec, 0x4,0, 0x0); // no mute oksnd_soc_update_bits(codec, 0x5,0, 0x0); // set no mute//snd_soc_update_bits(codec, 0x5, 0x08);// set mute // audio interfacesnd_soc_update_bits(codec, 0x7,0x2, 0x2);// 00 = 16bits, 10 = IIS format// volume +6db oksnd_soc_update_bits(codec, 0x2,0x1ff, 0x60 | 0x100);// WM8960_LOUT1snd_soc_update_bits(codec, 0x3,0x1ff, 0x60 | 0x100);// WM8960_ROUT1snd_soc_update_bits(codec, 0xa,0x1ff, 0xFF | 0x100);// Left DAC volumesnd_soc_update_bits(codec, 0xb,0x1ff, 0xFF | 0x100);// Right DAC volume// mixer controlsnd_soc_update_bits(codec, 0x22,0x180, 1<<8 | 1<<7); // Left output mixer controlsnd_soc_update_bits(codec, 0x25,0x180, 1<<8 | 1<<7); // Right output mixer controlprintk(KERN_ERR"wm8960 init done!\r\n");snd_soc_add_codec_controls(codec, wm8960_snd_controls,ARRAY_SIZE(wm8960_snd_controls));wm8960_add_widgets(codec);return 0; }

注釋掉的是原來的,wm8960寄存器地址在wm8960.h中都有定義的,我為了省事直接把裸機代碼拿過來用了,效果是一樣的。主要設置了電源,時鐘,音量和聲音輸出,這些缺1不可(測試過)。
這樣修改完后聲音應該能放出來了。
如果出聲音了,速率不對,偏快或偏慢,那是因為EPLL時鐘設置不對,IIS需要67.7M的時鐘頻率才能正確播放。,當然80M的頻率播放也蠻有意思的,音調被改變,一樣的音樂,不一樣的感受。^_^

另外提一下asoc驅動移植注意。

smdk_8960.c是我手動添加的,還需要修改Makefile和Kconfig文件,才能被配置和編譯。
首先需要在smdk_s5pv210.c中的device __init數值,確定iis0和i2c0設備在數組中。(我的wm8960 用的是iis0和i2c0),將wm8960作為i2c子設備添加到 i2c0中,配置內核支持i2c,asoc然后啟動后確定i2c0,wm8960,asoc正確被加載(看輸出),i2s0會在wm8960匹配成功后會出現如下類似輸出:

soc-audio soc-audio: wm8960-hifi <-> samsung-i2s.0 mapping ok

最終成功時會有如下輸出:

ALSA device list:#0: SMDK-I2S

也就是成功注冊了一個聲卡設備。
在/dev目錄下會出現這些設備節點:

controlC0 --> 用于聲卡的控制,例如通道選擇,混音,麥克風的控制等 pcmC0D0c --> 用于錄音的pcm設備 pcmC0D0p --> 用于播放的pcm設備 timer --> 定時器

最后通過alsa-util調用alsa-lib庫 播放wav文件 如果需要播放MP3還需要libmad(MP3解碼庫)的支持,直接讓alsa-lib使用libmad庫我還沒找到方法,但可以通過自己寫一個程序,調用libmad和alsa-lib來播放MP3,代碼網上可以搜到。

附上測試播放調試圖:
WAV文件:

MP3文件:

可以看到,播放MP3和WAV的驅動輸出基本是一樣的,最原始的音頻數據是WAV,播放MP3只是通過軟解碼轉換成WAV文件流而已。

心得體會

對于這些帶框架的驅動學習,如果遇到問題不知道出在哪里可以先去調試一下裸機代碼,確定寄存器的正確配置后再來調驅動框架會有事半功倍的效果。^_^

總結

以上是生活随笔為你收集整理的S5PV210 WM8960 ASOC 移植的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。