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;}
原创粉丝点击