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]);
}
}