Linux alsa驱动中的CODEC寄存器配置问题

来源:互联网 发布:tvb网络电视直播手机版 编辑:程序博客网 时间:2024/05/16 10:51

 调试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信号输出。

原创粉丝点击