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) //一组默认寄存器
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;