CODEC目前實作内部寄存器的操作一般有SPI、IIC和L3.這裡介紹L3.
L3接口實際上是一種串行接口,它由3根信号線組成,完成處理器和C0DEC之間的資料和控制信号交換.DAl341TS就是采用L3接口.
L3DATA:處理器接口資料線;
L3MODE:處理器接口模式信号線;
L3CLOCK:處理器接口時鐘信号線.
一般而言,一款CPU的硬體音頻系統一般帶有L3接口,否則隻能用GPIO模拟了.
L3總線有寫位址和資料之分,對于寫位址L3MODE為L(0),寫資料L3MODE為H(1),時鐘和模式開始都應該為1,資料線開始為0.先寫位址在些資料,先發低位在發高位.
當發起資料通訊時,一般選標明位址模式,接下來就是資料傳輸.
以UDA1341TS為例,位址模式:
下面根據此時序圖寫出示意代碼.根據時序圖寫代碼,首先要學會看時序圖.是以,需要注意下面的知識點:
1.時序圖從左到右看,有箭頭的地方表示有時序的要求,即需要寫代碼;
2.每一次電平變化都應該有時序的要求;
3.箭頭都是匹對的,左右對向為一組,兩箭頭之間便是狀态保持時間,這對應代碼适當的延時;
根據上述三點,從左到右,成對看箭頭.
首先L3CLOCK為高電平,L3MODE為高電平;L3MODE變為低之前,必須保持th時間段的狀态保持:
L3CLOCK = 1;
L3MODE = 1;
udelay(th);
L3MODE = 0;
L3MODE拉低之後,L3CLOCK不能立馬拉低,還需要保持tsu時間段的狀态保持:
udelay(tsu);
L3CLOCK = 0;
與此同時,L3DATA輸出一個位的資料.此時L3CLOCK要變成高電平之前,需要保持tsu時間段的狀态保持,資料才穩定:
L3DATA = X(X = 0,1);
udelay(tsu);
L3CLOCK = 1;
L3CLOCK變成高電平後,需要保持th時間段的狀态,保證資料被讀取:
udelay(th);
當一個位元組被傳輸完之後,L3MODE被拉高之前,L3CLOCK需要th時間段的高電平狀态保持:
L3CLOCK = 1;
L3MODE = 1;
當L3MODE被拉高之後,L3CLOCK不能立馬拉氏.還需要tsu時間段的高電平狀态保持:
udelay(tsu);
至此,形成了1Byte的周期.
是以,完整的時序示意代碼如下:
L3CLOCK = 1;
L3MODE = 1;
udelay(th);
L3MODE = 0;
udelay(tsu);
for(i = 0; i < 8; ++i)
{
L3CLOCK = 0;
L3DATA = X(X = 0,1);
udelay(tsu);
L3CLOCK = 1;
udelay(th);
}
L3MODE = 1;
udelay(tsu);
對應核心代碼sound/soc/codecs/l3.c:
int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
{
adap->setclk(1);
adap->setmode(1);
udelay(adap->mode);
adap->setmode(0);
udelay(adap->mode_setup);
sendbyte(adap, addr);
udelay(adap->mode_hold);
}
其中,sendbyte()函數如下:
static void sendbyte(struct l3_pins *adap, unsigned int byte)
{
int i;
for (i = 0; i < 8; i++) {
adap->setclk(0);
udelay(adap->data_hold);
adap->setdat(byte & 1);
udelay(adap->data_setup);
adap->setclk(1);
udelay(adap->clock_high);
byte >>= 1;
}
}
l3_write()函數在接下來的sendbytes()函數完成了示意代碼中L3MODE = 1;udelay(tsu);是以,沒有在上述分析中表現出這樣的代碼.
資料模式:
當然,可以将位址後位址後面緊随的資料一并批量傳輸:
大體講述此時序圖的意義.L3MODE為低時L3DATA傳輸的是位址資料;當L3MODE為高時,L3DATA傳輸的是資料資訊.每8個bit之間需要tstp時間段的延時.可以一次性完成2個Byte的資料傳輸.
對應sound/soc/codecs/l3.c:
/*
* Send a set of bytes to the chip. We need to pulse the MODE line
* between each byte, but never at the start nor at the end of the
* transfer.
*/
static void sendbytes(struct l3_pins *adap, const u8 *buf,
int len)
{
int i;
for (i = 0; i < len; i++) {
if (i) {
udelay(adap->mode_hold);
adap->setmode(0);
udelay(adap->mode);
}
adap->setmode(1);
udelay(adap->mode_setup);
sendbyte(adap, buf[i]);
}
}