Android音频驱动-ASOC之Codec
来源:互联网 发布:linux启动卡在进度条 编辑:程序博客网 时间:2024/05/20 05:09
对于回放来说,userspace 送过来的音频数据是经过采样量化的数字信号,在 codec 经过 DAC 转换成模拟信号然后输出到外放或耳机,
这样我们就可以听到声音了。Codec 字面意思是编解码器,但芯片里面的功能部件很多,常见的有 AIF、DAC、ADC、Mixer、PGA、
Line-in、Line-out,有些高端的 codec 芯片还有 EQ、DSP、SRC、DRC、AGC、Echo-Canceller、Noise-Suppression 等部件。
/* codec driver */struct snd_soc_codec_driver { /* driver ops */ int (*probe)(struct snd_soc_codec *); int (*remove)(struct snd_soc_codec *); int (*suspend)(struct snd_soc_codec *); int (*resume)(struct snd_soc_codec *); struct snd_soc_component_driver component_driver; /* Default control and setup, added after probe() is run */ const struct snd_kcontrol_new *controls; int num_controls; const struct snd_soc_dapm_widget *dapm_widgets; int num_dapm_widgets; const struct snd_soc_dapm_route *dapm_routes; int num_dapm_routes; /* codec wide operations */ int (*set_sysclk)(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source, unsigned int freq_in, unsigned int freq_out); /* codec IO */ struct regmap *(*get_regmap)(struct device *); unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); unsigned int reg_cache_size; short reg_cache_step; short reg_word_size; const void *reg_cache_default; /* codec bias level */ int (*set_bias_level)(struct snd_soc_codec *, enum snd_soc_bias_level level); bool idle_bias_off; bool suspend_bias_off; void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */};struct snd_soc_dai_driver { /* DAI description */ const char *name; unsigned int id; int ac97_control; unsigned int base; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); int (*remove)(struct snd_soc_dai *dai); int (*suspend)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai); /* compress dai */ bool compress_dai; /* ops */ const struct snd_soc_dai_ops *ops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* probe ordering - for components with runtime dependencies */ int probe_order; int remove_order;};
mt_soc_codec_63xx.c
static int __init mtk_mt6331_codec_init(void){ int ret = 0; soc_mtk_codec6331_dev = platform_device_alloc(MT_SOC_CODEC_NAME, -1); ret = platform_device_add(soc_mtk_codec6331_dev); InitGlobalVarDefault(); return platform_driver_register(&mtk_codec_6331_driver);}//platform driver的实例,mtk_codec_6331_driver和soc_mtk_codec6331_dev匹配会调用probe函数/*static struct platform_driver mtk_codec_6331_driver = { .driver = { .name = MT_SOC_CODEC_NAME, .owner = THIS_MODULE, }, .probe = mtk_mt6331_codec_dev_probe, .remove = mtk_mt6331_codec_dev_remove,};*/static int mtk_mt6331_codec_dev_probe(struct platform_device *pdev){ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); if (pdev->dev.dma_mask == NULL) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; if (pdev->dev.of_node) dev_set_name(&pdev->dev, "%s", MT_SOC_CODEC_NAME); return snd_soc_register_codec(&pdev->dev, &soc_mtk_codec, mtk_6331_dai_codecs, ARRAY_SIZE(mtk_6331_dai_codecs));//注册codec和codec dai driver}/*static const struct snd_soc_dapm_widget mt6331_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("EARPIECE"), SND_SOC_DAPM_OUTPUT("HEADSET"), SND_SOC_DAPM_OUTPUT("SPEAKER"),};static const struct snd_soc_dapm_route mtk_audio_map[] = { {"VOICE_Mux_E", "Voice Mux", "SPEAKER PGA"},};//codec driverstatic struct snd_soc_codec_driver soc_mtk_codec = { .probe = mt6331_codec_probe, .remove = mt6331_codec_remove, .read = mt6331_read, .write = mt6331_write, .dapm_widgets = mt6331_dapm_widgets,//保存dapm widgest实例 .num_dapm_widgets = ARRAY_SIZE(mt6331_dapm_widgets), .dapm_routes = mtk_audio_map,//保存dapm routes实例 .num_dapm_routes = ARRAY_SIZE(mtk_audio_map),};*//*static const struct snd_soc_dai_ops mt6323_aif1_dai_ops = { .startup = mt63xx_codec_startup, .prepare = mt63xx_codec_prepare, .trigger = mt6323_codec_trigger,};//codec dai driver,操作PCM设备时会调用static struct snd_soc_dai_driver mtk_6331_dai_codecs[] = { { .name = MT_SOC_CODEC_I2S0TXDAI_NAME,//匹配machine的codec dai name .ops = &mt6323_aif1_dai_ops, .playback = { .stream_name = MT_SOC_I2SDL1_STREAM_NAME, .channels_min = 1, .channels_max = 2, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SND_SOC_ADV_MT_FMTS, } }, ......}*/
注册codec driver和codec dai drvier实例
int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai){ struct snd_soc_codec *codec; struct snd_soc_dai *dai; int ret, i; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);//初始化codec if (codec == NULL) return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev);//初始化codec component if (codec_drv->controls) { codec->component.controls = codec_drv->controls; codec->component.num_controls = codec_drv->num_controls; } if (codec_drv->dapm_widgets) { codec->component.dapm_widgets = codec_drv->dapm_widgets; codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; } if (codec_drv->dapm_routes) { codec->component.dapm_routes = codec_drv->dapm_routes; codec->component.num_dapm_routes = codec_drv->num_dapm_routes; } if (codec_drv->probe) codec->component.probe = snd_soc_codec_drv_probe;//保存codec driver的probe if (codec_drv->remove) codec->component.remove = snd_soc_codec_drv_remove;//保存codec driver的remove if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write;//保存codec driver的write if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read;//保存codec driver的read codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.idle_bias_off = codec_drv->idle_bias_off; codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; codec->dev = dev; codec->driver = codec_drv; codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); if (codec_drv->get_regmap) codec->component.regmap = codec_drv->get_regmap(dev); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); } ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);//注册codec dai driver list_for_each_entry(dai, &codec->component.dai_list, list) dai->codec = codec; mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&codec->component);//将codec component插入component_list链表 list_add(&codec->list, &codec_list);//将codec插入codec_list链表 mutex_unlock(&client_mutex); return 0;}/*static int snd_soc_codec_drv_probe(struct snd_soc_component *component){ struct snd_soc_codec *codec = snd_soc_component_to_codec(component); return codec->driver->probe(codec);//调用codec driver的probe函数}*/
初始化codec对应的component
static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev){ struct snd_soc_dapm_context *dapm; component->name = fmt_single_name(dev, &component->id);//通过name和machine的codec name匹配 component->dev = dev; component->driver = driver; component->probe = component->driver->probe; component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; dapm = component->dapm_ptr; dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; component->controls = driver->controls; component->num_controls = driver->num_controls; component->dapm_widgets = driver->dapm_widgets; component->num_dapm_widgets = driver->num_dapm_widgets; component->dapm_routes = driver->dapm_routes; component->num_dapm_routes = driver->num_dapm_routes; INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); return 0;}static char *fmt_single_name(struct device *dev, int *id)//获取codec name MT_SOC_CODEC_NAME{ char *found, name[NAME_SIZE]; int id1, id2; strlcpy(name, dev_name(dev), NAME_SIZE); found = strstr(name, dev->driver->name); if (found) { if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) { /* discard ID from name if ID == -1 */ if (*id == -1) found[strlen(dev->driver->name)] = '\0'; } } else { /* I2C component devices are named "bus-addr" */ if (sscanf(name, "%x-%x", &id1, &id2) == 2) { char tmp[NAME_SIZE]; /* create unique ID number from I2C addr and bus */ *id = ((id1 & 0xffff) << 16) + id2; /* sanitize component name for DAI link creation */ snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); strlcpy(name, tmp, NAME_SIZE); } else *id = 0; } return kstrdup(name, GFP_KERNEL);}
将codec dai添加到component管理链表dai_list,一个codec对应多个codec dai
static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count, bool legacy_dai_naming){ struct device *dev = component->dev; struct snd_soc_dai *dai; unsigned int i; int ret; component->dai_drv = dai_drv; component->num_dai = count; for (i = 0; i < count; i++) { dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); if (count == 1 && legacy_dai_naming) { dai->name = fmt_single_name(dev, &dai->id); } else { dai->name = fmt_multiple_name(dev, &dai_drv[i]);//通过name和machine的codec dai name匹配 if (dai_drv[i].id) dai->id = dai_drv[i].id; else dai->id = i; } dai->component = component; dai->dev = dev; dai->driver = &dai_drv[i];//保存codec dai driver if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; list_add(&dai->list, &component->dai_list);//将codec dai添加到component管理链表dai_list } return 0;}static inline char *fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv){ return kstrdup(dai_drv->name, GFP_KERNEL);//使用codec dai driver的name MT_SOC_CODEC_I2S0TXDAI_NAME}
总结:codec dai driver数组对象mtk_6331_dai_codecs里的codec dai信息被抽取出来放入snd_soc_dai中,component可以通过dai_list来管理snd_soc_dai链表,最后将component插入到全局变量component_list中,并将codec插入到全局变量codec_list中。
注册声卡时会调用codec driver实例的回调函数probe
//codec driver的probe函数,在声卡注册时调用static int mt6331_codec_probe(struct snd_soc_codec *codec){ struct snd_soc_dapm_context *dapm = &codec->dapm; pin_extspkamp = pin_extspkamp_2 = pin_vowclk = pin_audmiso = pin_rcvspkswitch = 0; pin_mode_extspkamp = pin_mode_extspkamp_2 = pin_mode_vowclk = pin_mode_audmiso = pin_mode_rcvspkswitch = 0; pin_hpswitchtoground = pin_mode_hpswitchtoground = 0; snd_soc_dapm_new_controls(dapm, mt6331_dapm_widgets, ARRAY_SIZE(mt6331_dapm_widgets)); snd_soc_dapm_add_routes(dapm, mtk_audio_map, ARRAY_SIZE(mtk_audio_map)); /* add codec controls */ snd_soc_add_codec_controls(codec, mt6331_snd_controls, ARRAY_SIZE(mt6331_snd_controls)); snd_soc_add_codec_controls(codec, mt6331_UL_Codec_controls, ARRAY_SIZE(mt6331_UL_Codec_controls)); snd_soc_add_codec_controls(codec, mt6331_Voice_Switch, ARRAY_SIZE(mt6331_Voice_Switch)); snd_soc_add_codec_controls(codec, mt6331_pmic_Test_controls, ARRAY_SIZE(mt6331_pmic_Test_controls)); snd_soc_add_codec_controls(codec, Audio_snd_auxadc_controls, ARRAY_SIZE(Audio_snd_auxadc_controls)); /* here to set private data */ mCodec_data = kzalloc(sizeof(mt6331_Codec_Data_Priv), GFP_KERNEL); snd_soc_codec_set_drvdata(codec, mCodec_data); memset((void *)mCodec_data, 0, sizeof(mt6331_Codec_Data_Priv)); mt6331_codec_init_reg(codec); InitCodecDefault(); mInitCodec = true; mClkBufferfromPMIC = is_clk_buf_from_pmic(); return 0;}
上面代码为probe函数,里面有很多重要知识,下面进行一一分析。
snd_soc_dapm_new_controls函数所完成的主要功能:
为widget分配内存,并拷贝参数中传入的在驱动中定义好的模板设置power_check回调函数把widget挂在声卡的widgets链表中
/*snd_soc_dapm_new_controls(dapm, mt6331_dapm_widgets, ARRAY_SIZE(mt6331_dapm_widgets));*/int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num){ struct snd_soc_dapm_widget *w; int i; int ret = 0; for (i = 0; i < num; i++) { w = snd_soc_dapm_new_control(dapm, widget); if (!w) { break; } widget++; } return ret;}/*static const struct snd_soc_dapm_widget mt6331_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("EARPIECE"),//听筒 SND_SOC_DAPM_OUTPUT("HEADSET"),//耳机 SND_SOC_DAPM_OUTPUT("SPEAKER"),//喇叭};*/
如果widget之间没有连接关系,dapm就无法实现动态的电源管理工作,正是widget之间有了连结关系,
这些连接关系形成了一条所谓的完成的音频路径,dapm可以顺着这条路径,统一控制路径上所有widget的电源状态,
前面我们已经知道,widget之间是使用snd_soc_path结构进行连接的,驱动要做的是定义一个snd_soc_route结构数组,
该数组的每个条目描述了目的widget的和源widget的名称,以及控制这个连接的kcontrol的名称,最终,
驱动程序使用api函数snd_soc_dapm_add_routes来注册这些连接信息,接下来我们就是要分析该函数的具体实现方式:
/*snd_soc_dapm_add_routes(dapm, mtk_audio_map, ARRAY_SIZE(mtk_audio_map));*/int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num){ int i, r, ret = 0; for (i = 0; i < num; i++) { r = snd_soc_dapm_add_route(dapm, route); if (r < 0) { ret = r; } route++; } return ret;}/*static const struct snd_soc_dapm_route mtk_audio_map[] = { {"VOICE_Mux_E", "Voice Mux", "SPEAKER PGA"},};*/
对于每个控件,我们需要定义一个和它对应的snd_kcontrol_new结构,这些snd_kcontrol_new结构会在声卡的初始化阶段,
通过snd_soc_add_codec_controls函数注册到系统中,用户空间就可以通过amixer或alsamixer等工具查看和设定这些控件的状态。
/* snd_soc_add_codec_controls(codec, mt6331_snd_controls, ARRAY_SIZE(mt6331_snd_controls)); snd_soc_add_codec_controls(codec, mt6331_UL_Codec_controls, ARRAY_SIZE(mt6331_UL_Codec_controls)); snd_soc_add_codec_controls(codec, mt6331_Voice_Switch, ARRAY_SIZE(mt6331_Voice_Switch)); snd_soc_add_codec_controls(codec, mt6331_pmic_Test_controls, ARRAY_SIZE(mt6331_pmic_Test_controls)); snd_soc_add_codec_controls(codec, Audio_snd_auxadc_controls, ARRAY_SIZE(Audio_snd_auxadc_controls));*/
该函数首先通过 snd_soc_cnew(创建新的control)将snd_ctl_new的成员组织到新分配的snd_kcontrol结构体成员中,
然后调用 snd_ctl_add 函数,将这些音频控件添加到声卡对象(struct snd_card)的控件列表中(card->controls),
同时为这个kcontrol分配一个唯一的id号。
int snd_soc_add_codec_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, unsigned int num_controls){ return snd_soc_add_component_controls(&codec->component, controls, num_controls);}int snd_soc_add_component_controls(struct snd_soc_component *component, const struct snd_kcontrol_new *controls, unsigned int num_controls){ struct snd_card *card = component->card->snd_card; return snd_soc_add_controls(card, component->dev, controls, num_controls, component->name_prefix, component);}static int snd_soc_add_controls(struct snd_card *card, struct device *dev, const struct snd_kcontrol_new *controls, int num_controls, const char *prefix, void *data){ int err, i; for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; err = snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix)); } return 0;}/*static const struct snd_kcontrol_new mt6331_snd_controls[] = { SOC_ENUM_EXT("Audio_Amp_R_Switch", Audio_DL_Enum[0], Audio_AmpR_Get, Audio_AmpR_Set),//耳机右声道控件开关 SOC_ENUM_EXT("Audio_Amp_L_Switch", Audio_DL_Enum[1], Audio_AmpL_Get, Audio_AmpL_Set),//耳机左声道控件开关 SOC_ENUM_EXT("Voice_Amp_Switch", Audio_DL_Enum[2], Voice_Amp_Get, Voice_Amp_Set),//听筒控件开关 SOC_ENUM_EXT("Speaker_Amp_Switch", Audio_DL_Enum[3], Speaker_Amp_Get, Speaker_Amp_Set),//喇叭控件开关 SOC_ENUM_EXT("Headset_Speaker_Amp_Switch", Audio_DL_Enum[4], Headset_Speaker_Amp_Get, Headset_Speaker_Amp_Set),//耳机喇叭控件开关 SOC_ENUM_EXT("Headset_PGAL_GAIN", Audio_DL_Enum[5], Headset_PGAL_Get, Headset_PGAL_Set), SOC_ENUM_EXT("Headset_PGAR_GAIN", Audio_DL_Enum[6], Headset_PGAR_Get, Headset_PGAR_Set), SOC_ENUM_EXT("Handset_PGA_GAIN", Audio_DL_Enum[7], Handset_PGA_Get, Handset_PGA_Set), SOC_ENUM_EXT("Lineout_PGAR_GAIN", Audio_DL_Enum[8], Lineout_PGAR_Get, Lineout_PGAR_Set), SOC_ENUM_EXT("Lineout_PGAL_GAIN", Audio_DL_Enum[9], Lineout_PGAL_Get, Lineout_PGAL_Set), SOC_ENUM_EXT("AUD_CLK_BUF_Switch", Audio_DL_Enum[10], Aud_Clk_Buf_Get, Aud_Clk_Buf_Set), SOC_ENUM_EXT("Ext_Speaker_Amp_Switch", Audio_DL_Enum[11], Ext_Speaker_Amp_Get, Ext_Speaker_Amp_Set),//外置PA控件开关 SOC_ENUM_EXT("Receiver_Speaker_Switch", Audio_DL_Enum[11], Receiver_Speaker_Switch_Get, Receiver_Speaker_Switch_Set),//听筒喇叭切换控件开关 SOC_ENUM_EXT("Analog_Switch", Audio_DL_Enum[12], Analog_Switch_Get, Analog_Switch_Set), SOC_SINGLE_EXT("Audio HP Impedance", SND_SOC_NOPM, 0, 512, 0, Audio_Hp_Impedance_Get, Audio_Hp_Impedance_Set), SOC_ENUM_EXT("PMIC_REG_CLEAR", Audio_DL_Enum[12], PMIC_REG_CLEAR_Get, PMIC_REG_CLEAR_Set),};static const struct snd_kcontrol_new mt6331_UL_Codec_controls[] = { SOC_ENUM_EXT("Audio_ADC_1_Switch", Audio_UL_Enum[0], Audio_ADC1_Get, Audio_ADC1_Set),//主麦克风控件开关 SOC_ENUM_EXT("Audio_ADC_2_Switch", Audio_UL_Enum[1], Audio_ADC2_Get, Audio_ADC2_Set),//耳机麦克风控件开关,和ADC1基本相同,只是adc通道不同 SOC_ENUM_EXT("Audio_ADC_3_Switch", Audio_UL_Enum[2], Audio_ADC3_Get, Audio_ADC3_Set), SOC_ENUM_EXT("Audio_ADC_4_Switch", Audio_UL_Enum[3], Audio_ADC4_Get, Audio_ADC4_Set), SOC_ENUM_EXT("Audio_Preamp1_Switch", Audio_UL_Enum[4], Audio_PreAmp1_Get, Audio_PreAmp1_Set),//前置放大器控件开关,前置放大器是指置于信源与放大器级之间的电路或电子设备, //是专为接受来自信源的微弱电压信号而设计的 SOC_ENUM_EXT("Audio_ADC_1_Sel", Audio_UL_Enum[5], Audio_ADC1_Sel_Get, Audio_ADC1_Sel_Set),//mic1差分输入控件开关 SOC_ENUM_EXT("Audio_ADC_2_Sel", Audio_UL_Enum[6], Audio_ADC2_Sel_Get, Audio_ADC2_Sel_Set),//mic2差分输入控件开关 SOC_ENUM_EXT("Audio_ADC_3_Sel", Audio_UL_Enum[7], Audio_ADC3_Sel_Get, Audio_ADC3_Sel_Set),//不支持 SOC_ENUM_EXT("Audio_ADC_4_Sel", Audio_UL_Enum[8], Audio_ADC4_Sel_Get, Audio_ADC4_Sel_Set),//不支持 SOC_ENUM_EXT("Audio_PGA1_Setting", Audio_UL_Enum[9], Audio_PGA1_Get, Audio_PGA1_Set),//mic左PGA控件开关,从可编程增益 SOC_ENUM_EXT("Audio_PGA2_Setting", Audio_UL_Enum[10], Audio_PGA2_Get, Audio_PGA2_Set),//mic右PGA控件开关 SOC_ENUM_EXT("Audio_PGA3_Setting", Audio_UL_Enum[11], Audio_PGA3_Get, Audio_PGA3_Set),//不支持 SOC_ENUM_EXT("Audio_PGA4_Setting", Audio_UL_Enum[12], Audio_PGA4_Get, Audio_PGA4_Set),//不支持 SOC_ENUM_EXT("Audio_MicSource1_Setting", Audio_UL_Enum[13], Audio_MicSource1_Get, Audio_MicSource1_Set),//采集音源mic控件设置,无论从phone mic还是从earphone mic传来的音源, //mt6737都只从ADC1进行采集 SOC_ENUM_EXT("Audio_MicSource2_Setting", Audio_UL_Enum[14], Audio_MicSource2_Get, Audio_MicSource2_Set),//不支持 SOC_ENUM_EXT("Audio_MicSource3_Setting", Audio_UL_Enum[15], Audio_MicSource3_Get, Audio_MicSource3_Set),//不支持 SOC_ENUM_EXT("Audio_MicSource4_Setting", Audio_UL_Enum[16], Audio_MicSource4_Get, Audio_MicSource4_Set),//不支持 SOC_ENUM_EXT("Audio_MIC1_Mode_Select", Audio_UL_Enum[17], Audio_Mic1_Mode_Select_Get, Audio_Mic1_Mode_Select_Set),//mic1模式设置控件开关 SOC_ENUM_EXT("Audio_MIC2_Mode_Select", Audio_UL_Enum[18], Audio_Mic2_Mode_Select_Get, Audio_Mic2_Mode_Select_Set),//mic2模式设置控件开关 SOC_ENUM_EXT("Audio_MIC3_Mode_Select", Audio_UL_Enum[19], Audio_Mic3_Mode_Select_Get, Audio_Mic3_Mode_Select_Set),//mic3模式设置控件开关 SOC_ENUM_EXT("Audio_MIC4_Mode_Select", Audio_UL_Enum[20], Audio_Mic4_Mode_Select_Get, Audio_Mic4_Mode_Select_Set),//mic4模式设置控件开关 SOC_ENUM_EXT("Audio_Mic_Power_Mode", Audio_UL_Enum[21], Audio_Adc_Power_Mode_Get, Audio_Adc_Power_Mode_Set),//mic adc供电模式设置控件开关 SOC_ENUM_EXT("Audio_Vow_ADC_Func_Switch", Audio_UL_Enum[22], Audio_Vow_ADC_Func_Switch_Get, Audio_Vow_ADC_Func_Switch_Set),//vow耳机控件开关 SOC_ENUM_EXT("Audio_Preamp2_Switch", Audio_UL_Enum[23], Audio_PreAmp2_Get, Audio_PreAmp2_Set),//mic前置差分放大器2控制开关};static const struct snd_kcontrol_new mt6331_Voice_Switch[] = {//没有实现};static const struct snd_kcontrol_new mt6331_pmic_Test_controls[] = {//pmic测试控件 SOC_ENUM_EXT("SineTable_DAC_HP", Pmic_Test_Enum[0], SineTable_DAC_HP_Get, SineTable_DAC_HP_Set), SOC_ENUM_EXT("DAC_LOOP_DAC_HS", Pmic_Test_Enum[1], ADC_LOOP_DAC_HS_Get, ADC_LOOP_DAC_HS_Set), SOC_ENUM_EXT("DAC_LOOP_DAC_HP", Pmic_Test_Enum[2], ADC_LOOP_DAC_HP_Get, ADC_LOOP_DAC_HP_Set), SOC_ENUM_EXT("Voice_Call_DAC_DAC_HS", Pmic_Test_Enum[3], Voice_Call_DAC_DAC_HS_Get, Voice_Call_DAC_DAC_HS_Set), SOC_ENUM_EXT("SineTable_UL2", Pmic_Test_Enum[4], SineTable_UL2_Get, SineTable_UL2_Set), SOC_ENUM_EXT("Pmic_Loopback", Pmic_Test_Enum[5], Pmic_Loopback_Get, Pmic_Loopback_Set),};static const struct snd_kcontrol_new Audio_snd_auxadc_controls[] = { SOC_SINGLE_EXT("Audio AUXADC Data", SND_SOC_NOPM, 0, 0x80000, 0, Audio_AuxAdcData_Get, Audio_AuxAdcData_Set),//audio adc数据控件};*/
static void mt6331_codec_init_reg(struct snd_soc_codec *codec){ audckbufEnable(true); Ana_Set_Reg(TOP_CLKSQ, 0x0, 0x0001); /* Disable CLKSQ 26MHz */ Ana_Set_Reg(AUDDEC_ANA_CON9, 0x1000, 0x1000); /* disable AUDGLB */ Ana_Set_Reg(TOP_CKPDN_CON0_SET, 0x7000, 0x7000); /* Turn off AUDNCP_CLKDIV engine clock,Turn off AUD 26M */ Ana_Set_Reg(AUDDEC_ANA_CON0, 0xe000, 0xe000); /* Disable HeadphoneL/HeadphoneR/voice short circuit protection */ Ana_Set_Reg(AUDDEC_ANA_CON3, 0x4228, 0xffff); /* [5] = 1, disable LO buffer left short circuit protection */ Ana_Set_Reg(AFE_PMIC_NEWIF_CFG2, 0x8000, 0x8000); /* Reverse the PMIC clock*/ Ana_Set_Reg(DRV_CON2, 0x00e0, 0x00f0); /* PAD_AUD_DAT_MISO driving */ audckbufEnable(false);}
void InitCodecDefault(void){ pr_warn("%s\n", __func__); //设置mic1音量最大值 mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP1] = 3; //设置mic2音量最大值 mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP2] = 3; mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP3] = 3; mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_MICAMP4] = 3; //耳机音量右声道输出最大值 mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = 8; mCodec_data->mAudio_Ana_Volume[AUDIO_ANALOG_VOLUME_HPOUTR] = 8; mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC1] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC2] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC3] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP; mCodec_data->mAudio_Ana_Mux[AUDIO_ANALOG_MUX_IN_MIC4] = AUDIO_ANALOG_AUDIOANALOG_INPUT_PREAMP;}
- Android音频驱动-ASOC之Codec
- linux驱动:音频驱动(五)ASoc之codec驱动
- linux驱动:音频驱动(六)ASoc之codec设备
- Linux音频驱动之ASoC架构中的Codec
- Android音频驱动-ASOC之Machine
- Android音频驱动-ASOC之Platform
- Android音频驱动-ASOC之CPU DAI
- Android音频驱动-ASOC之PCM Open
- Android音频驱动-ASOC之常用对象
- Android音频驱动-ASOC之PCM Prepare
- Android音频驱动-ASOC之PCM Write
- Android音频驱动-ASOC之Control Open
- Android音频驱动-ASOC之DAMP
- Android音频驱动-ASOC之Sound Card注册
- Android音频驱动-ASOC之PCM Device创建
- Android音频驱动-ASOC之Sound Card创建
- Android音频驱动-ASOC之主&从设备号
- Android音频驱动-ASOC之创建设备节点
- linux系统下启动jar
- java如何获取需要在页面树形展示的json数组
- flex布局兼容总结
- 通过 MarqueeFactory 来提供各种样式的跑马灯 View, 支持自定义跑马灯 ItemView
- laravel+vue项目跳转拦截器
- Android音频驱动-ASOC之Codec
- HDU 5536 Chip Factory 01trie
- STL各种容器的使用总结
- android webView 全屏播放网络视频
- 基础博弈论之——简单的博弈问题【hdu1525】【Euclid‘s Game】
- 常见添加剂list
- 来自这里http://www.imooc.com/qadetail/149581?t=198457
- MATLAB显示串口接收的rgb565图像
- java中Logger.getLogger(Test.class)