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;
