rk音频驱动分析之codec

Es8323.c (sound\soc\codecs) 
1.入口函数
dts里面
 status = "okay";
        es8323: es8323@11 {
                status = "okay";
                compatible = "es8323";
                reg = <0x11>;
                pa-en1 = <&gpio1 GPIO_A0 GPIO_ACTIVE_HIGH>;
                pa-en2 = <&gpio1 GPIO_A1 GPIO_ACTIVE_HIGH>;
        };

static const struct i2c_device_id es8323_i2c_id[] = {
 { "es8323", 0 },{ }};
static struct i2c_driver es8323_i2c_driver = {
 .driver = {
  .name = "ES8323",
  .owner = THIS_MODULE,
 },
 .shutdown = es8323_i2c_shutdown,
 .probe = es8323_i2c_probe,
 .remove = es8323_i2c_remove,
 .id_table = es8323_i2c_id,
};

匹配之后就进入probe函数
I2C适配器的能力的相关代码
/* declare our i2c functionality */
static u32 rockchip_i2c_func(struct i2c_adapter *adap)
{
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
/* i2c bus registration info */
static const struct i2c_algorithm rockchip_i2c_algorithm = {
        .master_xfer = rockchip_i2c_xfer,
        .functionality = rockchip_i2c_func,
};

es8323_i2c_probe
    es8323 = devm_kzalloc(&i2c->dev,sizeof(struct es8323_priv), GFP_KERNEL); //分配es8323_priv结构体
    //用来判定设配器的能力,这一点非常重要。你也可以直接查看对应适配器的能力,开头有相关函数声明
    if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) 
    es8323->control_type = SND_SOC_I2C; //设置控制接口
    es8323->spk_ctl_gpio = of_get_named_gpio_flags(i2c->dev.of_node, "pa-en1", 0, &flags); //获取dts的相关控制脚
        es8323->spk_gpio_level = (flags & OF_GPIO_ACTIVE_LOW)? 0:1; //获取默认状态
        //一般gpio_request封装了mem_request(),起保护作用,最后要调用mem_free之类的。主要是告诉内核这地址被占用了。当其它地方调用同一地址的gpio_request就会报告错误,该地址已被申请。在/proc/mem应该会有地址占用表描述。
        ret = gpio_request(es8323->spk_ctl_gpio, NULL); 
        gpio_direction_output(es8323->spk_ctl_gpio,es8323->spk_gpio_level); //设置状态
    。。。。获取另外两个端口。。。。
    ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_es8323, &es8323_dai, 1); //注册codec,单独分析


2.注册codec,单独分析
codec相关结构体,主要是codec的相关操作函数
static struct snd_soc_codec_driver soc_codec_dev_es8323 = {
 .probe = es8323_probe,
 .remove = es8323_remove,
 .suspend = es8323_suspend,
 .resume = es8323_resume,
 .set_bias_level = es8323_set_bias_level,
 .reg_cache_size = ARRAY_SIZE(es8323_reg),
 .reg_word_size = sizeof(u16),
 .reg_cache_default = es8323_reg,
 .reg_cache_step = 1,
}

codec dai相关的函数
static struct snd_soc_dai_ops es8323_ops = {
 .startup = es8323_pcm_startup,
 .hw_params = es8323_pcm_hw_params,
 .set_fmt = es8323_set_dai_fmt,
 .set_sysclk = es8323_set_dai_sysclk,
 .digital_mute = es8323_mute,
};
static struct snd_soc_dai_driver es8323_dai = {
 .name = "ES8323 HiFi",
 .playback = {
  .stream_name = "Playback",
  .channels_min = 1,
  .channels_max = 2,
  .rates = es8323_RATES,// SNDRV_PCM_RATE_48000,
  .formats = es8323_FORMATS,
 },
 .capture = {
  .stream_name = "Capture",
  .channels_min = 1,
  .channels_max = 8,
  .rates = es8323_RATES,// SNDRV_PCM_RATE_48000,
  .formats = es8323_FORMATS,
  },
 .ops = &es8323_ops,
 .symmetric_rates = 1,
};

函数分析
snd_soc_register_codec(&i2c->dev, &soc_codec_dev_es8323, &es8323_dai, 1);
    codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); //分配snd_soc_codec结构体
    /* create CODEC component name */
    codec->name = fmt_single_name(dev, &codec->id); //通过一定规则获取名字
    codec->compress_type = SND_SOC_FLAT_COMPRESSION; //因为没有指定,所有默认是这个模式
    codec->write = codec_drv->write; //这里没有
    codec->read = codec_drv->read; //这里没有
    codec->volatile_register = codec_drv->volatile_register; //这里没有
    codec->readable_register = codec_drv->readable_register; //这里没有
    codec->writable_register = codec_drv->writable_register; //这里没有
    codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; //这里没有
    codec->dapm.bias_level = SND_SOC_BIAS_OFF;
    codec->dapm.dev = dev;
     codec->dapm.codec = codec;
    codec->dapm.seq_notifier = codec_drv->seq_notifier; //这里没有
    codec->dapm.stream_event = codec_drv->stream_event; //这里没有
    codec->dev = dev;
    codec->driver = codec_drv;
    codec->num_dai = num_dai; //这里是1
    /* allocate CODEC register cache */
    if (codec_drv->reg_cache_size && codec_drv->reg_word_size)
        //reg_cache_size这里是52个,word是2 byte,reg_size =52*2=104
        reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
        codec->reg_size = reg_size; //104
        /* it is necessary to make a copy of the default register cache
        * because in the case of using a compression type that requires
        * the default register cache to be marked as the
        * kernel might have freed the array by the time we initialize the cache. */
        有必要复制默认寄存器缓存的副本,因为在需要使用压缩类型的情况下,在初始化缓存时,内核可能释放了数组,需要默认的寄存器缓存被标记
        if (codec_drv->reg_cache_default) //一组默认寄存器
            在kernel中可以通过kmemdup将一种类型的数据赋值给另外同一个类型的数据,把reg_cache_default赋值给reg_def_copy 
            codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, reg_size, GFP_KERNEL);
    if (codec_drv->reg_access_size && codec_drv->reg_access_default) //我们这里没有
    for (i = 0; i < num_dai; i++) { //这里num_dai=1
        //让DAI的数据格式同时拥有大小字节序
        fixup_codec_formats(&dai_drv[i].playback);
            stream->formats |= codec_format_map[i]; //比如SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
        fixup_codec_formats(&dai_drv[i].capture);
    list_add(&codec->list, &codec_list); //把codec->list加到codec_list的最前面
    /* register any DAIs */
     ret = snd_soc_register_dais(dev, dai_drv, num_dai); //注册dai
    for (i = 0; i < count; i++)  //这里count=1
        dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); //分配struct snd_soc_dai *dai;
        /* create DAI component name */
        dai->name = fmt_multiple_name(dev, &dai_drv[i]); //这里名字是ES8323 HiFi
        dai->dev = dev;
        dai->driver = &dai_drv[i];
        dai->dapm.dev = dev;
        list_for_each_entry(codec, &codec_list, list) //从codec_list找出对应的codec
            if (codec->dev == dev)
                dai->codec = codec; //赋值
        list_add(&dai->list, &dai_list); //把dai->list加入到dai_list头部


3.es8323_probe
    codec->read = es8323_read_reg_cache; //es8323 register cache函数,cache是一个数组
    codec->write = es8323_write;
        ret = codec->hw_write(codec->control_data, data, 2);
    //issue a single I2C message in master transmit mode
    codec->hw_write = (hw_write_t)i2c_master_send;  //i2c的写函数
    codec->control_data = container_of(codec->dev, struct i2c_client, dev); //得到i2c_client
    es8323_codec = codec;
    ret = es8323_reset(codec); //写寄存器复位
        snd_soc_write(codec, ES8323_CONTROL1, 0x80);
        return snd_soc_write(codec, ES8323_CONTROL1, 0x00);
    .........
    snd_soc_write(codec, 0x02,0xf3); //一些初始化寄存器设置
    .............
    es8323_set_bias_level(codec, SND_SOC_BIAS_STANDBY); //设置偏压为待机



4.es8323_set_dai_sysclk
/* The set of rates we can generate from the above for each SYSCLK */
static unsigned int rates_12288[] = {
 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
};
static struct snd_pcm_hw_constraint_list constraints_12288 = {
 .count = ARRAY_SIZE(rates_12288),
 .list = rates_12288,
};

    switch (freq) //我们这里设置12288000 
    case 12288000:
        es8323->sysclk_constraints = &constraints_12288; //我们可以从上面为每一个SYSCLK生成一组速率
        es8323->sysclk = freq;


5.es8323_pcm_hw_params //caodec的硬件参数设置
/* codec hifi mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
 /* 8k */
    mclk         rate    fs        sr    usb
 {12288000, 8000, 1536, 0xa, 0x0},
 {11289600, 8000, 1408, 0x9, 0x0},
 {18432000, 8000, 2304, 0xc, 0x0},
 {16934400, 8000, 2112, 0xb, 0x0},
 {12000000, 8000, 1500, 0xb, 0x1},
 /* 11.025k */
 /* 16k */
 /* 22.05k */
 /* 32k */
 /* 44.1k */
。。。。。。。。。。。
 /* 48k */
 /* 88.2k */
 /* 96k */
}

static int es8323_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
    struct snd_soc_dai *dai)
    coeff = get_coeff(es8323->sysclk, params_rate(params));
        for (i = 0; i < ARRAY_SIZE(coeff_div); i++)  //获得对于的rate和mclk
          if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
    switch (params_format(params)) //设置格式,找到对于的codec寄存器数值
    case SNDRV_PCM_FORMAT_S16_LE:
        adciface |= 0x000C;
        daciface |= 0x0018;
    ........................
    /* set iface & srate*/
    snd_soc_write(codec, ES8323_DAC_IFACE, daciface); //设置寄存器DACWL
    snd_soc_write(codec, ES8323_ADC_IFACE, adciface); //ADCWL
    if (coeff >= 0) {
        snd_soc_write(codec, ES8323_IFACE, srate); //主机串行模式,然后采样率,应该是录音
        snd_soc_write(codec, ES8323_ADCCONTROL5, coeff_div[coeff].sr | (coeff_div[coeff].usb) << 4); //采样率的主频
        snd_soc_write(codec, ES8323_DACCONTROL2, coeff_div[coeff].sr | (coeff_div[coeff].usb) << 4); //采样率的主频


6.es8323_set_dai_fmt设置dai的格式
static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    iface = snd_soc_read(codec, ES8323_IFACE); //读取接口相关的寄存器
    adciface = snd_soc_read(codec, ES8323_ADC_IFACE);
    daciface = snd_soc_read(codec, ES8323_DAC_IFACE);
    /* set master/slave audio interface */
    switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) //看是主还是从模式
    case SND_SOC_DAIFMT_CBM_CFM: // MASTER MODE
        iface |= 0x80;
    case SND_SOC_DAIFMT_CBS_CFS: // SLAVE MODE
        iface &= 0x7F;
    /* interface format */ADC数据接口的模式
    switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) 
    case SND_SOC_DAIFMT_I2S: //我们这里是I2S
        adciface &= 0xFC;
        daciface &= 0xF9;
    。。。。。。。
    /* clock inversion */ 时钟翻转
    switch (fmt & SND_SOC_DAIFMT_INV_MASK)
    case SND_SOC_DAIFMT_NB_NF:
    。。。。。。。
    //设置对应的寄存器
    snd_soc_write(codec, ES8323_IFACE, iface);
    snd_soc_write(codec, ES8323_ADC_IFACE, adciface);
    snd_soc_write(codec, ES8323_DAC_IFACE, daciface);


7.static int es8323_mute(struct snd_soc_dai *dai, int mute)
静音函数,静音和播放
    if (mute) //这里soc_pcm_prepare传入0
        //拉低ES8323_CODEC_SET_SPK和ES8323_CODEC_SET_HP控制脚
        es8323_set_gpio(ES8323_CODEC_SET_SPK,!es8323->spk_gpio_level);
        es8323_set_gpio(ES8323_CODEC_SET_HP,!es8323->hp_gpio_level);
        snd_soc_write(codec, ES8323_DACCONTROL3, 0x06);  //静音
    else
        snd_soc_write(codec, ES8323_DACCONTROL3, 0x02); 
        snd_soc_write(codec, 0x30,es8323_DEF_VOL); //设置音量
        snd_soc_write(codec, 0x31,es8323_DEF_VOL); //设置音量
    if(hp_irq_flag == 0) //没有耳机
        es8323_set_gpio(ES8323_CODEC_SET_SPK,es8323->spk_gpio_level);
    else //耳机
        es8323_set_gpio(ES8323_CODEC_SET_HP,es8323->hp_gpio_level);


8.rockchip_i2s_trigger
启动传输
static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
    switch (cmd)
    case SNDRV_PCM_TRIGGER_START: //开始传输
    case SNDRV_PCM_TRIGGER_RESUME:
    case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
            rockchip_snd_rxctrl(i2s, 1); //从codec接收
        else
            rockchip_snd_txctrl(i2s, 1);//传输给codec
    case SNDRV_PCM_TRIGGER_SUSPEND:
    case SNDRV_PCM_TRIGGER_STOP:
    case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
            if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                rockchip_snd_rxctrl(i2s, 0); //停止
            else
                rockchip_snd_txctrl(i2s, 0); //停止
    

9.es8323_set_bias_level //设置codec偏压
    switch (level)
    case SND_SOC_BIAS_ON:这里什么都没有做
    case SND_SOC_BIAS_PREPARE: //进入low power模式,这些寄存器都是这样
        snd_soc_write(codec, ES8323_ANAVOLMANAG, 0x7C);
        snd_soc_write(codec, ES8323_CHIPLOPOW1, 0x00);
        snd_soc_write(codec, ES8323_CHIPLOPOW2, 0x00);
        snd_soc_write(codec, ES8323_CHIPPOWER, 0x00);       
        snd_soc_write(codec, ES8323_ADCPOWER, 0x00);
    case SND_SOC_BIAS_STANDBY: //这个和SND_SOC_BIAS_PREPARE一样
    case SND_SOC_BIAS_OFF: //关闭
        snd_soc_write(codec, ES8323_ADCPOWER, 0xFF);
        snd_soc_write(codec, ES8323_DACPOWER, 0xC0);
        snd_soc_write(codec, ES8323_CHIPLOPOW1, 0xFF);
        snd_soc_write(codec, ES8323_CHIPLOPOW2, 0xFF);
        snd_soc_write(codec, ES8323_CHIPPOWER, 0xFF);
        snd_soc_write(codec, ES8323_ANAVOLMANAG, 0x7B);
    codec->dapm.bias_level = level;

     

    
    

posted @ 2020-11-26 15:47  luoyuna  阅读(2422)  评论(0编辑  收藏  举报