ALSA 驱动配置外部HP MIC SPK

程序总体结构

以sound/soc/pxa/corgi.c为例来分析

  • 为了描述声卡,定义snd_soc_card实例,填充dai_link成员。
  • 为了能在ALSA上层控制SPK,HP,MIC的开启关闭,定义kcontrol实例。
  • 为了能让ALSA自动控制SPK,HP,MIC的功耗,定义widget,route实例。
  • 在snd_soc_card--dai_link--init里,注册上面声明的kcontrol,widget,route实例。

下面以SPK的kcontrol,widget,route为例,分析三种数据结构的定义

kcontrol的实现

定义kcontrol数组,提供向上的参数和向下的实际控制函数 。

  • 向上的参数,用于上层amixer程序设置控件为不同的功能。
  • 向下的实际控制函数,用于底层驱动程序控制HP MIC SPK的开关。
static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", "Off"};
static const char *spk_function[] = {"On", "Off"};
static const struct soc_enum corgi_enum[] = {
    SOC_ENUM_SINGLE_EXT(5, jack_function),//控件参数1-4
    SOC_ENUM_SINGLE_EXT(2, spk_function),//控件参数0-1
};
static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
    SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
        corgi_set_jack),//get,set分别读取和设置硬件工作模式
    SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
        corgi_set_spk),
};

get,set函数的实现

static int corgi_get_spk(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_value *ucontrol)
{
    ucontrol->value.integer.value[0] = corgi_spk_func;  //全局变量为0-1表示ON OFF
    return 0;
}

static int corgi_set_spk(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_value *ucontrol)
{
    struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);

    if (corgi_spk_func == ucontrol->value.integer.value[0])
        return 0;

    corgi_spk_func = ucontrol->value.integer.value[0];//保存上层设置的参数
    corgi_ext_control(codec);//设置SPK为ON OFF模式
    return 1;
}
//corgi_ext_control函数的实现
static void corgi_ext_control(struct snd_soc_codec *codec)
{
    if (corgi_spk_func == CORGI_SPK_ON)
        snd_soc_dapm_enable_pin(dapm, "Ext Spk");  
        //通过enable widget,开启电源,widget的实现在后面描述
    else
        snd_soc_dapm_disable_pin(dapm, "Ext Spk");//通过disable widget,关闭电源

    /* signal a DAPM event */
    snd_soc_dapm_sync(dapm);
}

snd_soc_card->dai_link->init里,通过snd_soc_add_controls注册control。

widget的实现

//定义widget
/* corgi machine dapm widgets */
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),//定义widget名字,设置电源控制接口
};
//电源控制接口的实现
static int corgi_amp_event(struct snd_soc_dapm_widget *w,
    struct snd_kcontrol *k, int event)
{
    //通过GPIO开关SPK的前置放大器
    gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
    return 0;
}

snd_soc_card->dai_link->init里,通过snd_soc_dapm_new_controls注册widget。

route的实现

//定义route
/* Corgi machine audio map (connections to the codec pins) */
static const struct snd_soc_dapm_route audio_map[] = {
    /* speaker connected to LOUT, ROUT */
    {"Ext Spk", NULL, "ROUT"},//设置SPK直连codec的ROUT和LOUT
    {"Ext Spk", NULL, "LOUT"},
};

snd_soc_card->dai_link->init里,通过snd_soc_dapm_add_routes注册route。

从datesheet上,可以看到ROUT和LOUT是用来外接SPK的。


ALSA 驱动配置外部HP MIC SPK_第1张图片
image.png

从codec驱动里,可以看到ROUT,LOUT的widget定义。

static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LOUT"),
SND_SOC_DAPM_OUTPUT("LHPOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
};

文章上没有添加附件选项,将machine驱动,codec驱动和手册添加到了链接:
http://download.csdn.net/download/a903265446/10235150
一般产品开发,codec驱动和platform驱动由芯片厂商提供,只需要开发machine驱动。

本文由头条号“嵌入式FM106点1”发布,各种原创技术干货,欢迎关注。

你可能感兴趣的:(ALSA 驱动配置外部HP MIC SPK)