• ALSA driver---DAPM


    https://alsa-project.org/main/index.php/DAPM

    https://www.kernel.org/doc/html/v4.11/sound/soc/dapm.html

    There are 4 power domains within DAPM:

    1. Codec domain – VREF, VMID (core codec and audio power). Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc.
    2. Platform/Machine domain – physically connected inputs and outputs. Is platform/machine and user action specific, is configured by the machine driver and responds to asynchronous events. e.g when HP are inserted
    3. Path domain – audio subsystem signal paths. Automatically set when mixer and mux settings are changed by the user. e.g. alsamixer, amixer.
    4. Stream domain – DAC's and ADC's. Enabled and disabled when stream playback/capture is started and stopped respectively. e.g. aplay, arecord.

    Codec/DSP Widget Interconnections

    Widgets are connected to each other within the codec, platform and machine by audio paths (called interconnections). Each interconnection must be defined in order to create a map of all audio paths between widgets.

    This is easiest with a diagram of the codec or DSP (and schematic of the machine audio system), as it requires joining widgets together via their audio signal paths.

    Map Hardware to Widget (TLV320AIC23)

    capture signal path:

    LLININ->Line Input->Catpture source ->ADC

    MICIN->Mic Input->Catpute source->ADC

    playback signal path:

    DAC->Ouptput Mixer->LOUT/LHPOUT/ROUT/RHPOUT

    LLININ->Line Input->Output Mixer->LOUT

    MICIN->Mic Input ->Output Mixer->LOUT/LHPOUT/ROUT/RHPOUT

    DAPM Widgets:

    sound/soc/codecs/tlv320aic23.c

    static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
        SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
        SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
                 &tlv320aic23_rec_src_mux_controls),
        SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
                   &tlv320aic23_output_mixer_controls[0],
                   ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
        SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
        SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
    
        SND_SOC_DAPM_OUTPUT("LHPOUT"),
        SND_SOC_DAPM_OUTPUT("RHPOUT"),
        SND_SOC_DAPM_OUTPUT("LOUT"),
        SND_SOC_DAPM_OUTPUT("ROUT"),
    
        SND_SOC_DAPM_INPUT("LLINEIN"),
        SND_SOC_DAPM_INPUT("RLINEIN"),
    
        SND_SOC_DAPM_INPUT("MICIN"),
    };

    DAPM routes:

    static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
        /* Output Mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "Playback Switch", "DAC"},
        {"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
    
        /* Outputs */
        {"RHPOUT", NULL, "Output Mixer"},
        {"LHPOUT", NULL, "Output Mixer"},
        {"LOUT", NULL, "Output Mixer"},
        {"ROUT", NULL, "Output Mixer"},
    
        /* Inputs */
        {"Line Input", "NULL", "LLINEIN"},
        {"Line Input", "NULL", "RLINEIN"},
    
        {"Mic Input", "NULL", "MICIN"},
    
        /* input mux */
        {"Capture Source", "Line", "Line Input"},
        {"Capture Source", "Mic", "Mic Input"},
        {"ADC", NULL, "Capture Source"},
    
    };

    Each input in this example has a kcontrol associated with it (defined in example above) and is connected to the output mixer via its kcontrol name. We can now connect the destination widget (wrt audio signal) with its source widgets.

    /* PGA Mixer controls for Line and Mic switch */
    static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
        SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
        SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
        SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
    };

    So we have :-

    • Destination Widget <=== Path Name <=== Source Widget, or
    • Sink, Path, Source, or
    • Output Mixer is connected to the MIC Input via the Mic Sidetone Switch.

    When there is no path name connecting widgets (e.g. a direct connection) we pass NULL for the path name.

    SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1)
    #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) 
    {    .id = snd_soc_dapm_dac, .name = wname, .sname = stname, 
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
    #define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) 
        .reg = wreg, .mask = 1, .shift = wshift, 
        .on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0

    name:DAC

    stream name:Playback

    Register:TLV320AIC23_PWR

    shift:3

    invert:1

    if invert is 1, it means that it will power on the DAC if set "TLV320AIC23_PWR" bit 3 as 0, .

    if invert is 0, it means that it will power on widget if set register shift bit as 1.

    Interconnections are created with a call to:-

    snd_soc_dapm_connect_input(codec, sink, path, source);
    

    Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and interconnections have been registered with the core. This causes the core to scan the codec and machine so that the internal DAPM state matches the physical state of the machine.

    tlv320aic23 codec driver & dai driver:

    static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
        .probe = tlv320aic23_codec_probe,
        .resume = tlv320aic23_resume,
        .set_bias_level = tlv320aic23_set_bias_level,
        .suspend_bias_off = true,
    
        .controls = tlv320aic23_snd_controls,
        .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
        .dapm_widgets = tlv320aic23_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
        .dapm_routes = tlv320aic23_intercon,
        .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
    };
    static struct snd_soc_dai_driver tlv320aic23_dai = {
        .name = "tlv320aic23-hifi",
        .playback = {
                 .stream_name = "Playback",
                 .channels_min = 2,
                 .channels_max = 2,
                 .rates = AIC23_RATES,
                 .formats = AIC23_FORMATS,},
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = AIC23_RATES,
                .formats = AIC23_FORMATS,},
        .ops = &tlv320aic23_dai_ops,
    };

    Machine Widget Interconnections

    Machine widget interconnections are created in the same way as codec ones and directly connect the codec pins to machine level widgets.

    e.g. connects the speaker out codec pins to the internal speaker.

    /* ext speaker connected to codec pins LOUT2, ROUT2  */
    {"Ext Spk", NULL , "ROUT2"},
    {"Ext Spk", NULL , "LOUT2"},
    

    This allows the DAPM to power on and off pins that are connected (and in use) and pins that are NC respectively.

     sound/soc/omap/am3517evm.c

    /* am3517evm machine dapm widgets */
    static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Line Out", NULL),
        SND_SOC_DAPM_LINE("Line In", NULL),
        SND_SOC_DAPM_MIC("Mic In", NULL),
    };
    
    static const struct snd_soc_dapm_route audio_map[] = {
        /* Line Out connected to LLOUT, RLOUT */
        {"Line Out", NULL, "LOUT"},
        {"Line Out", NULL, "ROUT"},
    
        {"LLINEIN", NULL, "Line In"},
        {"RLINEIN", NULL, "Line In"},
    
        {"MICIN", NULL, "Mic In"},
    };
    
    /* Digital audio interface glue - connects codec <--> CPU */
    static struct snd_soc_dai_link am3517evm_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
        .cpu_dai_name = "omap-mcbsp.1",
        .codec_dai_name = "tlv320aic23-hifi",
        .platform_name = "omap-mcbsp.1",
        .codec_name = "tlv320aic23-codec.2-001a",
        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
               SND_SOC_DAIFMT_CBM_CFM,
        .ops = &am3517evm_ops,
    };
    
    /* Audio machine driver */
    static struct snd_soc_card snd_soc_am3517evm = {
        .name = "am3517evm",
        .owner = THIS_MODULE,
        .dai_link = &am3517evm_dai,
        .num_links = 1,
    
        .dapm_widgets = tlv320aic23_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
    };
  • 相关阅读:
    javascript 笔记
    i18n,国际化翻译,excel与js互转
    nginx 一个端口布署多个单页应用(history路由模式)。
    html, js,css应用文件路径规则
    vue响应式原理,去掉优化,只看核心
    js 大量数据优化,通用方法
    nginx 常用的location rewrite proxy_pass
    javascript,排列组合
    zk分布式任务管理
    springboot+mybatis+dubbo+aop日志终结篇
  • 原文地址:https://www.cnblogs.com/fellow1988/p/12552253.html
Copyright © 2020-2023  润新知