全部博文(685)
分类: LINUX
2015-01-27 11:46:02
调试Audio CODEC时,有时候需要读codec寄存器的值以确认是否配置寄存器成功。
记得之前调试wm8978时,发现这个CODEC的寄存器不能读,每次读的结果都是0xff.
后来在linux上调试wm8978时,用snd_soc_read()又能读到所配置的值,感觉很诧异。当时也没有细究。
这两天有空,在linux内核中看了一下相关代码,发现关于通过I2C读写CODEC的代码在 sound/soc/soc-cache.c中。
在这个.c文件中定义了不少类似 snd_soc_X_Y_read() 和 snd_soc_X_Y_write()的函数,X代表地址位数,Y代码
数据位数,例如snd_soc_7_9_read()用于地址是7位,数据是9位的CODEC,wolfson的CODEC大多数是这种情况。
另外有个用于具体的CODEC驱动去设置X,Y值的接口,以便选择对应的读写函数,这个接口是:
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control)
例如wm8960.c中有如下配置调用:
ret =snd_soc_codec_set_cache_io(codec,7,9,control);
现在说一下snd_soc_X_Y_write()这类函数,例如:
static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= codec->reg_cache_size)
return -1;
return cache[reg];
}
一看代码,原来这里的读,竟然不是从CODEC的寄存器中读出来的,而是从一个cache缓存中读出来的。
再看一下对应的write函数就一清二楚了,原来在write时将所写的寄存器的值同时缓存到cache中,read时
直接从cache中读出。
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u16 *cache = codec->reg_cache;
u8 data[2];
int ret;
BUG_ON(codec->volatile_register);
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
if (reg < codec->reg_cache_size)
cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
return 0;
}
dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
ret = codec->hw_write(codec->control_data, data, 2);
if (ret == 2)
return 0;
if (ret < 0)
return ret;
else
return -EIO;
}
这样,近期一个奇怪的问题又有好解释了:
通过I2C配置sensor后,通过aplay播放音乐无动静(无声音),但通过snd_soc_read()读CODEC(wm8960)各寄存器的值
又是正常的(和能正常播放时的配置一样),用示波器量了一下CODEC的LRCK管脚,没有任何东西(本应该有clock输出的,因为
CODEC被配置为master模式)。原来snd_soc_read()读到的值根本就是之前写进去的缓存,并不是真正CODEC中已经配置的值,
显然CODEC没有正常配置,所以没有LRCK信号输出。