高通Auido中ASOC的machine驱动

ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的代码,再次引用上一节的内容:Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。

ASoC的一切都从Machine驱动开始,包括声卡的注册,绑定Platform和Codec驱动等等;

1. 注册Platform driver:

ASoC把声卡注册为Platform Device:

  1 static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
  2 {
  3     struct snd_soc_card *card;
  4     struct msm8916_asoc_mach_data *pdata = NULL;
  5     struct pinctrl *pinctrl;
  6     const char *card_dev_id = "qcom,msm-snd-card-id";
  7     const char *codec_type = "qcom,msm-codec-type";
  8     const char *hs_micbias_type = "qcom,msm-hs-micbias-type";
  9     const char *ext_pa = "qcom,msm-ext-pa";
 10     const char *mclk = "qcom,msm-mclk-freq";
 11     const char *spk_ext_pa = "qcom,msm-spk-ext-pa";
 12     const char *ptr = NULL;
 13     const char *type = NULL;
 14     const char *ext_pa_str = NULL;
 15     int num_strings;
 16     int ret, id, i;
 17
 18     pr_err("‘msm8x16_asoc_machine_probe ......");
 19     pdata = devm_kzalloc(&pdev->dev,
 20             sizeof(struct msm8916_asoc_mach_data), GFP_KERNEL);
 21     if (!pdata) {
 22         dev_err(&pdev->dev, "Can‘t allocate msm8x16_asoc_mach_data\n");
 23         ret = -ENOMEM;
 24         goto err1;
 25     }
 26
 27     pdata->vaddr_gpio_mux_spkr_ctl =
 28         ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4);
 29     if (!pdata->vaddr_gpio_mux_spkr_ctl) {
 30         pr_err("%s ioremap failure for addr %x",
 31                 __func__, LPASS_CSR_GP_IO_MUX_SPKR_CTL);
 32         ret = -ENOMEM;
 33         goto err;
 34     }
 35     pdata->vaddr_gpio_mux_mic_ctl =
 36         ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4);
 37     if (!pdata->vaddr_gpio_mux_mic_ctl) {
 38         pr_err("%s ioremap failure for addr %x",
 39                 __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL);
 40         ret = -ENOMEM;
 41         goto err;
 42     }
 43
 44     pdata->vaddr_gpio_mux_pcm_ctl =
 45         ioremap(LPASS_CSR_GP_LPAIF_PRI_PCM_PRI_MODE_MUXSEL, 4);
 46     if (!pdata->vaddr_gpio_mux_pcm_ctl) {
 47         pr_err("%s ioremap failure for addr %x",
 48                 __func__,
 49             LPASS_CSR_GP_LPAIF_PRI_PCM_PRI_MODE_MUXSEL);
 50         ret = -ENOMEM;
 51         goto err;
 52     }
 53     ret = of_property_read_u32(pdev->dev.of_node, card_dev_id, &id);
 54     if (ret) {
 55         dev_err(&pdev->dev,
 56             "%s: missing %s in dt node\n", __func__, card_dev_id);
 57         goto err;
 58     }
 59
 60     pdev->id = id;
 61     if (!pdev->dev.of_node) {
 62         dev_err(&pdev->dev, "No platform supplied from device tree\n");
 63         ret = -EINVAL;
 64         goto err;
 65     }
 66
 67     ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
 68     if (ret) {
 69         dev_err(&pdev->dev,
 70             "%s: missing %s in dt node\n", __func__, mclk);
 71         id = DEFAULT_MCLK_RATE;
 72     }
 73     pdata->mclk_freq = id;
 74
 75     pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node,
 76                 spk_ext_pa, 0);
 77     if (pdata->spk_ext_pa_gpio < 0) {
 78         dev_dbg(&pdev->dev,
 79             "%s: missing %s in dt node\n", __func__, spk_ext_pa);
 80     } else {
 81         if (gpio_is_valid(pdata->spk_ext_pa_gpio)) {
 82             ret = gpio_request(pdata->spk_ext_pa_gpio, "spk_ext_pa_gpio");
 83             if(ret) {
 84                 pr_err("spk ext pa gpio request failed");
 85                 goto err;
 86             }
 87
 88             ret = gpio_direction_output(pdata->spk_ext_pa_gpio, 1);
 89             if(ret) {
 90                 pr_err("set_direction for spk ext pa gpio failed\n");
 91                 goto err;
 92             }
 93         } else {
 94                 pr_err("%s: Invaild external_speaker gpio: %d", __func__, pdata->spk_ext_pa_gpio);
 95                 ret = -EINVAL;
 96                 goto err;
 97             }
 98
 99     }
100
101     ret = of_property_read_string(pdev->dev.of_node, codec_type, &ptr);
102     if (ret) {
103         dev_err(&pdev->dev,
104             "%s: missing %s in dt node\n", __func__, codec_type);
105         goto err;
106     }
107     if (pdev->id >= MAX_SND_CARDS) {
108         dev_err(&pdev->dev, "Sound Card parsed is wrong, id=%d\n",
109                 pdev->id);
110         ret = -EINVAL;
111         goto err;
112     }
113     if (!strcmp(ptr, "external")) {
114         dev_info(&pdev->dev, "external codec is configured\n");
115         pdata->codec_type = 1;
116             /*Populate external codec TLMM configs*/
117         ret = populate_ext_snd_card_dt_data(pdev);
118         if (ret < 0) {
119             dev_err(&pdev->dev, "error finding the DT\n"
120                 "params ret=%d\n", ret);
121             goto err;
122         }
123         card = populate_ext_snd_card_dailinks(pdev);
124         if (!card) {
125             dev_err(&pdev->dev, "%s: Card uninitialized\n",
126                 __func__);
127             ret = -EPROBE_DEFER;
128             goto err;
129         }
130     } else {
131         card = populate_ext_snd_card_dailinks(pdev);
132         if (!card) {
133             dev_err(&pdev->dev, "%s: Card uninitialized\n",
134                 __func__);
135             ret = -EPROBE_DEFER;
136             goto err;
137         }
138         dev_info(&pdev->dev, "default codec configured\n");
139         pdata->codec_type = 0;
140         num_strings = of_property_count_strings(pdev->dev.of_node,
141                 ext_pa);
142         if (num_strings < 0) {
143             dev_err(&pdev->dev,
144             "%s: missing %s in dt node or length is incorrect\n",
145                     __func__, ext_pa);
146             goto err;
147         }
148         for (i = 0; i < num_strings; i++) {
149             ret = of_property_read_string_index(pdev->dev.of_node,
150                     ext_pa, i, &ext_pa_str);
151             if (ret) {
152                 dev_err(&pdev->dev,
153                     "%s:of read string %s i %d error %d\n",
154                         __func__, ext_pa, i, ret);
155                 goto err;
156             }
157             if (!strcmp(ext_pa_str, "primary"))
158                 pdata->ext_pa = (pdata->ext_pa | PRI_MI2S_ID);
159             else if (!strcmp(ext_pa_str, "secondary"))
160                 pdata->ext_pa = (pdata->ext_pa | SEC_MI2S_ID);
161             else if (!strcmp(ext_pa_str, "tertiary"))
162                 pdata->ext_pa = (pdata->ext_pa | TER_MI2S_ID);
163             else if (!strcmp(ext_pa_str, "quaternary"))
164                 pdata->ext_pa = (pdata->ext_pa | QUAT_MI2S_ID);
165         }
166         pr_debug("%s: ext_pa = %d\n", __func__, pdata->ext_pa);
167         pinctrl = devm_pinctrl_get(&pdev->dev);
168         if (IS_ERR(pinctrl)) {
169             pr_err("%s: Unable to get pinctrl handle\n",
170                     __func__);
171             return -EINVAL;
172         }
173         pinctrl_info.pinctrl = pinctrl;
174         ret = get_cdc_gpio_lines(pinctrl, pdata->ext_pa);
175         if (ret < 0) {
176             pr_err("%s: failed to ger the codec gpio‘s %d\n",
177                     __func__, ret);
178             goto err;
179         }
180     }
181
182     ret = of_property_read_string(pdev->dev.of_node,
183         hs_micbias_type, &type);
184     if (ret) {
185         dev_err(&pdev->dev, "%s: missing %s in dt node\n",
186             __func__, hs_micbias_type);
187         goto err;
188     }
189     if (!strcmp(type, "external")) {
190         dev_dbg(&pdev->dev, "Headset is using external micbias\n");
191         mbhc_cfg.hs_ext_micbias = true;
192     } else {
193         dev_dbg(&pdev->dev, "Headset is using internal micbias\n");
194         mbhc_cfg.hs_ext_micbias = false;
195     }
196
197     /* initialize the mclk */
198     pdata->digital_cdc_clk.i2s_cfg_minor_version =
199                     AFE_API_VERSION_I2S_CONFIG;
200     pdata->digital_cdc_clk.clk_val = pdata->mclk_freq;
201     pdata->digital_cdc_clk.clk_root = 5;
202     pdata->digital_cdc_clk.reserved = 0;
203     /* initialize the digital codec core clk */
204     pdata->digital_cdc_core_clk.clk_set_minor_version =
205             AFE_API_VERSION_I2S_CONFIG;
206     pdata->digital_cdc_core_clk.clk_id =
207             Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE;
208     pdata->digital_cdc_core_clk.clk_freq_in_hz =
209             pdata->mclk_freq;
210     pdata->digital_cdc_core_clk.clk_attri =
211             Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
212     pdata->digital_cdc_core_clk.clk_root =
213             Q6AFE_LPASS_CLK_ROOT_DEFAULT;
214     pdata->digital_cdc_core_clk.enable = 1;
215     /* Initialize loopback mode to false */
216     pdata->lb_mode = false;
217
218     msm8x16_setup_hs_jack(pdev, pdata);
219     msm8x16_dt_parse_cap_info(pdev, pdata);
220
221     card->dev = &pdev->dev;
222     platform_set_drvdata(pdev, card);
223     snd_soc_card_set_drvdata(card, pdata);
224     ret = snd_soc_of_parse_card_name(card, "qcom,model");
225     if (ret)
226         goto err;
227     /* initialize timer */
228     INIT_DELAYED_WORK(&pdata->disable_mclk_work, disable_mclk);
229     mutex_init(&pdata->cdc_mclk_mutex);
230     atomic_set(&pdata->mclk_rsc_ref, 0);
231     atomic_set(&pdata->mclk_enabled, false);
232     atomic_set(&quat_mi2s_clk_ref, 0);
233     atomic_set(&auxpcm_mi2s_clk_ref, 0);
234
235     ret = snd_soc_of_parse_audio_routing(card,
236             "qcom,audio-routing");
237     if (ret)
238         goto err;
239
240     ret = msm8x16_populate_dai_link_component_of_node(card);
241     if (ret) {
242         ret = -EPROBE_DEFER;
243         goto err;
244     }
245
246     ret = snd_soc_register_card(card);
247     if (ret) {
248         dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
249             ret);
250         goto err;
251     }
252
253     ret = core_get_adsp_ver();
254     if (ret < 0) {
255         ret = -EPROBE_DEFER;
256         dev_info(&pdev->dev, "%s: Get adsp version failed (%d)\n",
257                 __func__, ret);
258         goto err;
259     }
260
261     return 0;
262 err:
263     if (pdata->vaddr_gpio_mux_spkr_ctl)
264         iounmap(pdata->vaddr_gpio_mux_spkr_ctl);
265     if (pdata->vaddr_gpio_mux_mic_ctl)
266         iounmap(pdata->vaddr_gpio_mux_mic_ctl);
267     if (pdata->vaddr_gpio_mux_pcm_ctl)
268         iounmap(pdata->vaddr_gpio_mux_pcm_ctl);
269     if(gpio_is_valid(pdata->spk_ext_pa_gpio))
270         gpio_free(pdata->spk_ext_pa_gpio);
271     devm_kfree(&pdev->dev, pdata);
272 err1:
273     return ret;
274 }

probe函数

DTS:

 1 sound {
 2         compatible = "qcom,msm8x16-audio-codec";
 3         qcom,model = "msm8x16-skui-snd-card";
 4         qcom,msm-snd-card-id = <0>;
 5         qcom,msm-ext-pa = "secondary";//"primary";
 6         qcom,msm-codec-type = "internal";
 7         qcom,msm-mbhc-hphl-swh = <0>;
 8         qcom,msm-mbhc-gnd-swh = <1>;
 9         qcom,msm-hs-micbias-type = "internal";
10         qcom,audio-routing =
11             "RX_BIAS", "MCLK",
12             "SPK_RX_BIAS", "MCLK",
13             "INT_LDO_H", "MCLK",
14             "MIC BIAS Internal1", "Handset Mic",
15             "MIC BIAS Internal2", "Headset Mic",
16             "MIC BIAS Internal1", "Secondary Mic",
17             "AMIC1", "MIC BIAS Internal1",
18             "AMIC2", "MIC BIAS Internal2",
19             "AMIC3", "MIC BIAS Internal1";
20         pinctrl-names = "cdc_lines_act",
21                 "cdc_lines_sus",
22                 "cdc_lines_sec_ext_act",
23                 "cdc_lines_sec_ext_sus";
24         pinctrl-0 = <&cdc_pdm_lines_act>;
25         pinctrl-1 = <&cdc_pdm_lines_sus>;
26         pinctrl-2 = <&cdc_pdm_lines_act &cdc_ext_pa_act &cdc_ext_pa_ws_act>;
27         pinctrl-3 = <&cdc_pdm_lines_sus &cdc_ext_pa_sus &cdc_ext_pa_ws_sus>;
28     };

通过与DTS匹配,开始分析:

(1)、获取card的id:

1 ret = of_property_read_u32(pdev->dev.of_node, card_dev_id, &id);

(2)、设置card的名字:

1 pdev->id = id;
2 dev_set_name(&pdev->dev, "%s.%d", "msm-snd-card", id);

(3)、设置codec的类型为external还是internal的:

1 ret = of_property_read_string(pdev->dev.of_node, codec_type, &ptr);
2     if (ret) {
3         dev_err(&pdev->dev,
4             "%s: missing %s in dt node\n", __func__, codec_type);
5         goto err;
6     }

(4)、根据external还是internal的card,进入相应的处理函数中:

假设进入internal card:

1 card = &bear_cards[pdev->id];
2 bear_cards[pdev->id].name = dev_name(&pdev->dev);

在这里,bear_cards是一个snd_soc_card的结构体,由设备树又可知,id=0:

 1 static struct snd_soc_card bear_cards[MAX_SND_CARDS] = {
 2     /* snd_soc_card_msm8x16 */
 3     {
 4         .name        = "msm8x16-snd-card",
 5         .dai_link    = msm8x16_dai,
 6         .num_links    = ARRAY_SIZE(msm8x16_dai),
 7     },
 8     {
 9         .name        = "msm8x16-tapan-snd-card",
10         .dai_link    = msm8x16_9306_dai_links,
11         .num_links    = ARRAY_SIZE(msm8x16_9306_dai_links),
12     },
13     {
14         .name        = "msm8x16-tapan9302-snd-card",
15         .dai_link    = msm8x16_9302_dai_links,
16         .num_links    = ARRAY_SIZE(msm8x16_9302_dai_links),
17     },
18 };

所以用到的只有msm8x16_dai;

  1 /* Digital audio interface glue - connects codec <---> CPU */
  2 static struct snd_soc_dai_link msm8x16_dai[] = {
  3     /* FrontEnd DAI Links */
  4     {/* hw:x,0 */
  5         .name = "MSM8X16 Media1",
  6         .stream_name = "MultiMedia1",
  7         .cpu_dai_name    = "MultiMedia1",
  8         .platform_name  = "msm-pcm-dsp.0",
  9         .dynamic = 1,
 10         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 11             SND_SOC_DPCM_TRIGGER_POST},
 12         .codec_dai_name = "snd-soc-dummy-dai",
 13         .codec_name = "snd-soc-dummy",
 14         .ignore_suspend = 1,
 15         /* this dainlink has playback support */
 16         .ignore_pmdown_time = 1,
 17         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
 18     },
 19     {/* hw:x,1 */
 20         .name = "MSM8X16 Media2",
 21         .stream_name = "MultiMedia2",
 22         .cpu_dai_name   = "MultiMedia2",
 23         .platform_name  = "msm-pcm-dsp.0",
 24         .dynamic = 1,
 25         .codec_dai_name = "snd-soc-dummy-dai",
 26         .codec_name = "snd-soc-dummy",
 27         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 28             SND_SOC_DPCM_TRIGGER_POST},
 29         .ignore_suspend = 1,
 30         /* this dainlink has playback support */
 31         .ignore_pmdown_time = 1,
 32         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
 33     },
 34     {/* hw:x,2 */
 35         .name = "Circuit-Switch Voice",
 36         .stream_name = "CS-Voice",
 37         .cpu_dai_name   = "CS-VOICE",
 38         .platform_name  = "msm-pcm-voice",
 39         .dynamic = 1,
 40         .codec_dai_name = "snd-soc-dummy-dai",
 41         .codec_name = "snd-soc-dummy",
 42         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 43             SND_SOC_DPCM_TRIGGER_POST},
 44         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 45         .ignore_suspend = 1,
 46         /* this dainlink has playback support */
 47         .ignore_pmdown_time = 1,
 48         .be_id = MSM_FRONTEND_DAI_CS_VOICE,
 49     },
 50     {/* hw:x,3 */
 51         .name = "MSM VoIP",
 52         .stream_name = "VoIP",
 53         .cpu_dai_name    = "VoIP",
 54         .platform_name  = "msm-voip-dsp",
 55         .dynamic = 1,
 56         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 57             SND_SOC_DPCM_TRIGGER_POST},
 58         .codec_dai_name = "snd-soc-dummy-dai",
 59         .codec_name = "snd-soc-dummy",
 60         .ignore_suspend = 1,
 61         /* this dainlink has playback support */
 62         .ignore_pmdown_time = 1,
 63         .be_id = MSM_FRONTEND_DAI_VOIP,
 64     },
 65     {/* hw:x,4 */
 66         .name = "MSM8X16 LPA",
 67         .stream_name = "LPA",
 68         .cpu_dai_name    = "MultiMedia3",
 69         .platform_name  = "msm-pcm-lpa",
 70         .dynamic = 1,
 71         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 72             SND_SOC_DPCM_TRIGGER_POST},
 73         .codec_dai_name = "snd-soc-dummy-dai",
 74         .codec_name = "snd-soc-dummy",
 75         .ignore_suspend = 1,
 76         /* this dainlink has playback support */
 77         .ignore_pmdown_time = 1,
 78         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
 79     },
 80     /* Hostless PCM purpose */
 81     {/* hw:x,5 */
 82         .name = "Primary MI2S_RX Hostless",
 83         .stream_name = "Primary MI2S_RX Hostless",
 84         .cpu_dai_name = "PRI_MI2S_RX_HOSTLESS",
 85         .platform_name    = "msm-pcm-hostless",
 86         .dynamic = 1,
 87         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
 88                 SND_SOC_DPCM_TRIGGER_POST},
 89         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 90         .ignore_suspend = 1,
 91         .ignore_pmdown_time = 1,
 92          /* This dainlink has MI2S support */
 93         .codec_dai_name = "snd-soc-dummy-dai",
 94         .codec_name = "snd-soc-dummy",
 95     },
 96     {/* hw:x,6 */
 97         .name = "INT_FM Hostless",
 98         .stream_name = "INT_FM Hostless",
 99         .cpu_dai_name    = "INT_FM_HOSTLESS",
100         .platform_name  = "msm-pcm-hostless",
101         .dynamic = 1,
102         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
103             SND_SOC_DPCM_TRIGGER_POST},
104         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
105         .ignore_suspend = 1,
106         /* this dainlink has playback support */
107         .ignore_pmdown_time = 1,
108         .codec_dai_name = "snd-soc-dummy-dai",
109         .codec_name = "snd-soc-dummy",
110     },
111     {/* hw:x,7 */
112         .name = "MSM AFE-PCM RX",
113         .stream_name = "AFE-PROXY RX",
114         .cpu_dai_name = "msm-dai-q6-dev.241",
115         .codec_name = "msm-stub-codec.1",
116         .codec_dai_name = "msm-stub-rx",
117         .platform_name  = "msm-pcm-afe",
118         .ignore_suspend = 1,
119         /* this dainlink has playback support */
120         .ignore_pmdown_time = 1,
121     },
122     {/* hw:x,8 */
123         .name = "MSM AFE-PCM TX",
124         .stream_name = "AFE-PROXY TX",
125         .cpu_dai_name = "msm-dai-q6-dev.240",
126         .codec_name = "msm-stub-codec.1",
127         .codec_dai_name = "msm-stub-tx",
128         .platform_name  = "msm-pcm-afe",
129         .ignore_suspend = 1,
130     },
131     {/* hw:x,9 */
132         .name = "MSM8X16 Compr",
133         .stream_name = "COMPR",
134         .cpu_dai_name    = "MultiMedia4",
135         .platform_name  = "msm-compress-dsp",
136         .dynamic = 1,
137         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
138              SND_SOC_DPCM_TRIGGER_POST},
139         .codec_dai_name = "snd-soc-dummy-dai",
140         .codec_name = "snd-soc-dummy",
141         .ignore_suspend = 1,
142         .ignore_pmdown_time = 1,
143          /* this dainlink has playback support */
144         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
145     },
146     {/* hw:x,10 */
147         .name = "AUXPCM Hostless",
148         .stream_name = "AUXPCM Hostless",
149         .cpu_dai_name   = "AUXPCM_HOSTLESS",
150         .platform_name  = "msm-pcm-hostless",
151         .dynamic = 1,
152         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
153             SND_SOC_DPCM_TRIGGER_POST},
154         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
155         .ignore_suspend = 1,
156         /* this dainlink has playback support */
157         .ignore_pmdown_time = 1,
158         .codec_dai_name = "snd-soc-dummy-dai",
159         .codec_name = "snd-soc-dummy",
160     },
161     {/* hw:x,11 */
162         .name = "Tertiary MI2S_TX Hostless",
163         .stream_name = "Tertiary MI2S_TX Hostless",
164         .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
165         .platform_name  = "msm-pcm-hostless",
166         .dynamic = 1,
167         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
168                 SND_SOC_DPCM_TRIGGER_POST},
169         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
170         .ignore_suspend = 1,
171         .ignore_pmdown_time = 1, /* dai link has playback support */
172         .codec_dai_name = "snd-soc-dummy-dai",
173         .codec_name = "snd-soc-dummy",
174     },
175     {/* hw:x,12 */
176         .name = "MSM8x16 LowLatency",
177         .stream_name = "MultiMedia5",
178         .cpu_dai_name   = "MultiMedia5",
179         .platform_name  = "msm-pcm-dsp.1",
180         .dynamic = 1,
181         .codec_dai_name = "snd-soc-dummy-dai",
182         .codec_name = "snd-soc-dummy",
183         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
184                 SND_SOC_DPCM_TRIGGER_POST},
185         .ignore_suspend = 1,
186         /* this dainlink has playback support */
187         .ignore_pmdown_time = 1,
188         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
189     },
190     {/* hw:x,13 */
191         .name = "Voice2",
192         .stream_name = "Voice2",
193         .cpu_dai_name   = "Voice2",
194         .platform_name  = "msm-pcm-voice",
195         .dynamic = 1,
196         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
197                 SND_SOC_DPCM_TRIGGER_POST},
198         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
199         .ignore_suspend = 1,
200         /* this dainlink has playback support */
201         .ignore_pmdown_time = 1,
202         .codec_dai_name = "snd-soc-dummy-dai",
203         .codec_name = "snd-soc-dummy",
204     },
205     {/* hw:x,14 */
206         .name = "MSM8x16 Media9",
207         .stream_name = "MultiMedia9",
208         .cpu_dai_name   = "MultiMedia9",
209         .platform_name  = "msm-pcm-dsp.0",
210         .dynamic = 1,
211         .codec_dai_name = "snd-soc-dummy-dai",
212         .codec_name = "snd-soc-dummy",
213         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
214                 SND_SOC_DPCM_TRIGGER_POST},
215         .ignore_suspend = 1,
216         /* This dailink has playback support */
217         .ignore_pmdown_time = 1,
218         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
219     },
220     { /* hw:x,15 */
221         .name = "VoLTE",
222         .stream_name = "VoLTE",
223         .cpu_dai_name   = "VoLTE",
224         .platform_name  = "msm-pcm-voice",
225         .dynamic = 1,
226         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
227                 SND_SOC_DPCM_TRIGGER_POST},
228         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
229         .ignore_suspend = 1,
230         /* this dainlink has playback support */
231         .ignore_pmdown_time = 1,
232         .codec_dai_name = "snd-soc-dummy-dai",
233         .codec_name = "snd-soc-dummy",
234         .be_id = MSM_FRONTEND_DAI_VOLTE,
235     },
236     { /* hw:x,16 */
237         .name = "VoWLAN",
238         .stream_name = "VoWLAN",
239         .cpu_dai_name   = "VoWLAN",
240         .platform_name  = "msm-pcm-voice",
241         .dynamic = 1,
242         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
243                 SND_SOC_DPCM_TRIGGER_POST},
244         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
245         .ignore_suspend = 1,
246         .ignore_pmdown_time = 1,
247         .codec_dai_name = "snd-soc-dummy-dai",
248         .codec_name = "snd-soc-dummy",
249         .be_id = MSM_FRONTEND_DAI_VOWLAN,
250     },
251     {/* hw:x,17 */
252         .name = "INT_HFP_BT Hostless",
253         .stream_name = "INT_HFP_BT Hostless",
254         .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
255         .platform_name  = "msm-pcm-hostless",
256         .dynamic = 1,
257         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
258                 SND_SOC_DPCM_TRIGGER_POST},
259         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
260         .ignore_suspend = 1,
261         /* this dai link has playback support */
262         .ignore_pmdown_time = 1,
263         .codec_dai_name = "snd-soc-dummy-dai",
264         .codec_name = "snd-soc-dummy",
265     },
266     {/* hw:x,18 */
267         .name = "MSM8916 HFP TX",
268         .stream_name = "MultiMedia6",
269         .cpu_dai_name = "MultiMedia6",
270         .platform_name  = "msm-pcm-loopback",
271         .dynamic = 1,
272         .codec_dai_name = "snd-soc-dummy-dai",
273         .codec_name = "snd-soc-dummy",
274         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
275                 SND_SOC_DPCM_TRIGGER_POST},
276         .ignore_suspend = 1,
277         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
278         /* this dai link has playback support */
279         .ignore_pmdown_time = 1,
280         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
281     },
282     /* LSM FE */
283     {/* hw:x,19 */
284         .name = "Listen 1 Audio Service",
285         .stream_name = "Listen 1 Audio Service",
286         .cpu_dai_name = "LSM1",
287         .platform_name = "msm-lsm-client",
288         .dynamic = 1,
289         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
290                 SND_SOC_DPCM_TRIGGER_POST },
291         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
292         .ignore_suspend = 1,
293         .ignore_pmdown_time = 1,
294         .codec_dai_name = "snd-soc-dummy-dai",
295         .codec_name = "snd-soc-dummy",
296         .be_id = MSM_FRONTEND_DAI_LSM1,
297     },
298     {/* hw:x,20 */
299         .name = "Listen 2 Audio Service",
300         .stream_name = "Listen 2 Audio Service",
301         .cpu_dai_name = "LSM2",
302         .platform_name = "msm-lsm-client",
303         .dynamic = 1,
304         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
305                 SND_SOC_DPCM_TRIGGER_POST },
306         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
307         .ignore_suspend = 1,
308         .ignore_pmdown_time = 1,
309         .codec_dai_name = "snd-soc-dummy-dai",
310         .codec_name = "snd-soc-dummy",
311         .be_id = MSM_FRONTEND_DAI_LSM2,
312     },
313     {/* hw:x,21 */
314         .name = "Listen 3 Audio Service",
315         .stream_name = "Listen 3 Audio Service",
316         .cpu_dai_name = "LSM3",
317         .platform_name = "msm-lsm-client",
318         .dynamic = 1,
319         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
320                 SND_SOC_DPCM_TRIGGER_POST },
321         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
322         .ignore_suspend = 1,
323         .ignore_pmdown_time = 1,
324         .codec_dai_name = "snd-soc-dummy-dai",
325         .codec_name = "snd-soc-dummy",
326         .be_id = MSM_FRONTEND_DAI_LSM3,
327     },
328     {/* hw:x,22 */
329         .name = "Listen 4 Audio Service",
330         .stream_name = "Listen 4 Audio Service",
331         .cpu_dai_name = "LSM4",
332         .platform_name = "msm-lsm-client",
333         .dynamic = 1,
334         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
335                 SND_SOC_DPCM_TRIGGER_POST },
336         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
337         .ignore_suspend = 1,
338         .ignore_pmdown_time = 1,
339         .codec_dai_name = "snd-soc-dummy-dai",
340         .codec_name = "snd-soc-dummy",
341         .be_id = MSM_FRONTEND_DAI_LSM4,
342     },
343     {/* hw:x,23 */
344         .name = "Listen 5 Audio Service",
345         .stream_name = "Listen 5 Audio Service",
346         .cpu_dai_name = "LSM5",
347         .platform_name = "msm-lsm-client",
348         .dynamic = 1,
349         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
350                 SND_SOC_DPCM_TRIGGER_POST },
351         .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
352         .ignore_suspend = 1,
353         .ignore_pmdown_time = 1,
354         .codec_dai_name = "snd-soc-dummy-dai",
355         .codec_name = "snd-soc-dummy",
356         .be_id = MSM_FRONTEND_DAI_LSM5,
357     },
358     {/* hw:x,24 */
359         .name = "MSM8916 ULL",
360         .stream_name = "MultiMedia7",
361         .cpu_dai_name   = "MultiMedia7",
362         .platform_name  = "msm-pcm-dsp.1",
363         .dynamic = 1,
364         .codec_dai_name = "snd-soc-dummy-dai",
365         .codec_name = "snd-soc-dummy",
366         .trigger = {SND_SOC_DPCM_TRIGGER_POST,
367                 SND_SOC_DPCM_TRIGGER_POST},
368         .ignore_suspend = 1,
369         /* this dainlink has playback support */
370         .ignore_pmdown_time = 1,
371         .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
372     },
373     /* Backend I2S DAI Links */
374     {
375         .name = LPASS_BE_PRI_MI2S_RX,
376         .stream_name = "Primary MI2S Playback",
377         .cpu_dai_name = "msm-dai-q6-mi2s.0",
378         .platform_name = "msm-pcm-routing",
379         .codec_name     = MSM8X16_CODEC_NAME,
380         .codec_dai_name = "msm8x16_wcd_i2s_rx1",
381         .no_pcm = 1,
382         .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
383         .init = &msm_audrx_init,
384         .be_hw_params_fixup = msm_pri_rx_be_hw_params_fixup,
385         .ops = &msm8x16_mi2s_be_ops,
386         .ignore_suspend = 1,
387     },
388     {
389         .name = LPASS_BE_SEC_MI2S_RX,
390         .stream_name = "Secondary MI2S Playback",
391         .cpu_dai_name = "msm-dai-q6-mi2s.1",
392         .platform_name = "msm-pcm-routing",
393         .codec_name = "msm-stub-codec.1",
394         .codec_dai_name = "msm-stub-rx",
395         .no_pcm = 1,
396         .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
397         .be_hw_params_fixup = msm_be_hw_params_fixup,
398         .ops = &msm8x16_sec_mi2s_be_ops,
399         .ignore_suspend = 1,
400     },
401     {
402         .name = LPASS_BE_TERT_MI2S_TX,
403         .stream_name = "Tertiary MI2S Capture",
404         .cpu_dai_name = "msm-dai-q6-mi2s.2",
405         .platform_name = "msm-pcm-routing",
406         .codec_name     = MSM8X16_CODEC_NAME,
407         .codec_dai_name = "msm8x16_wcd_i2s_tx1",
408         .no_pcm = 1,
409         .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
410         .be_hw_params_fixup = msm_tx_be_hw_params_fixup,
411         .ops = &msm8x16_mi2s_be_ops,
412         .ignore_suspend = 1,
413     },
414     {
415         .name = LPASS_BE_INT_BT_SCO_RX,
416         .stream_name = "Internal BT-SCO Playback",
417         .cpu_dai_name = "msm-dai-q6-dev.12288",
418         .platform_name = "msm-pcm-routing",
419         .codec_name = "msm-stub-codec.1",
420         .codec_dai_name    = "msm-stub-rx",
421         .no_pcm = 1,
422         .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
423         .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
424         /* this dainlink has playback support */
425         .ignore_pmdown_time = 1,
426         .ignore_suspend = 1,
427     },
428     {
429         .name = LPASS_BE_INT_BT_SCO_TX,
430         .stream_name = "Internal BT-SCO Capture",
431         .cpu_dai_name = "msm-dai-q6-dev.12289",
432         .platform_name = "msm-pcm-routing",
433         .codec_name = "msm-stub-codec.1",
434         .codec_dai_name    = "msm-stub-tx",
435         .no_pcm = 1,
436         .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
437         .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
438         .ignore_suspend = 1,
439     },
440     {
441         .name = LPASS_BE_INT_FM_RX,
442         .stream_name = "Internal FM Playback",
443         .cpu_dai_name = "msm-dai-q6-dev.12292",
444         .platform_name = "msm-pcm-routing",
445         .codec_name = "msm-stub-codec.1",
446         .codec_dai_name = "msm-stub-rx",
447         .no_pcm = 1,
448         .be_id = MSM_BACKEND_DAI_INT_FM_RX,
449         .be_hw_params_fixup = msm_be_hw_params_fixup,
450         /* this dainlink has playback support */
451         .ignore_pmdown_time = 1,
452         .ignore_suspend = 1,
453     },
454     {
455         .name = LPASS_BE_INT_FM_TX,
456         .stream_name = "Internal FM Capture",
457         .cpu_dai_name = "msm-dai-q6-dev.12293",
458         .platform_name = "msm-pcm-routing",
459         .codec_name = "msm-stub-codec.1",
460         .codec_dai_name = "msm-stub-tx",
461         .no_pcm = 1,
462         .be_id = MSM_BACKEND_DAI_INT_FM_TX,
463         .be_hw_params_fixup = msm_be_hw_params_fixup,
464         .ignore_suspend = 1,
465     },
466     {
467         .name = LPASS_BE_AFE_PCM_RX,
468         .stream_name = "AFE Playback",
469         .cpu_dai_name = "msm-dai-q6-dev.224",
470         .platform_name = "msm-pcm-routing",
471         .codec_name = "msm-stub-codec.1",
472         .codec_dai_name = "msm-stub-rx",
473         .no_pcm = 1,
474         .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
475         .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
476         /* this dainlink has playback support */
477         .ignore_pmdown_time = 1,
478         .ignore_suspend = 1,
479     },
480     {
481         .name = LPASS_BE_AFE_PCM_TX,
482         .stream_name = "AFE Capture",
483         .cpu_dai_name = "msm-dai-q6-dev.225",
484         .platform_name = "msm-pcm-routing",
485         .codec_name = "msm-stub-codec.1",
486         .codec_dai_name = "msm-stub-tx",
487         .no_pcm = 1,
488         .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
489         .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
490         .ignore_suspend = 1,
491     },
492     /* Incall Record Uplink BACK END DAI Link */
493     {
494         .name = LPASS_BE_INCALL_RECORD_TX,
495         .stream_name = "Voice Uplink Capture",
496         .cpu_dai_name = "msm-dai-q6-dev.32772",
497         .platform_name = "msm-pcm-routing",
498         .codec_name     = "msm-stub-codec.1",
499         .codec_dai_name = "msm-stub-tx",
500         .no_pcm = 1,
501         .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
502         .be_hw_params_fixup = msm_be_hw_params_fixup,
503         .ignore_suspend = 1,
504     },
505     /* Incall Record Downlink BACK END DAI Link */
506     {
507         .name = LPASS_BE_INCALL_RECORD_RX,
508         .stream_name = "Voice Downlink Capture",
509         .cpu_dai_name = "msm-dai-q6-dev.32771",
510         .platform_name = "msm-pcm-routing",
511         .codec_name     = "msm-stub-codec.1",
512         .codec_dai_name = "msm-stub-tx",
513         .no_pcm = 1,
514         .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
515         .be_hw_params_fixup = msm_be_hw_params_fixup,
516         .ignore_suspend = 1,
517     },
518     /* Incall Music BACK END DAI Link */
519     {
520         .name = LPASS_BE_VOICE_PLAYBACK_TX,
521         .stream_name = "Voice Farend Playback",
522         .cpu_dai_name = "msm-dai-q6-dev.32773",
523         .platform_name = "msm-pcm-routing",
524         .codec_name     = "msm-stub-codec.1",
525         .codec_dai_name = "msm-stub-rx",
526         .no_pcm = 1,
527         .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
528         .be_hw_params_fixup = msm_be_hw_params_fixup,
529         .ignore_suspend = 1,
530     },
531     /* Incall Music 2 BACK END DAI Link */
532     {
533         .name = LPASS_BE_VOICE2_PLAYBACK_TX,
534         .stream_name = "Voice2 Farend Playback",
535         .cpu_dai_name = "msm-dai-q6-dev.32770",
536         .platform_name = "msm-pcm-routing",
537         .codec_name     = "msm-stub-codec.1",
538         .codec_dai_name = "msm-stub-rx",
539         .no_pcm = 1,
540         .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
541         .be_hw_params_fixup = msm_be_hw_params_fixup,
542         .ignore_suspend = 1,
543     },
544 };

snd_dai_link msm8x16_dai

其中,snd_soc_dai_link中,指定了Platform、Codec、codec_dai、cpu_dai的名字,稍后Machine驱动将会利用这些名字去匹配已经在系统中注册的platform,codec,dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的,这样看来,Machine驱动的设备初始化代码无非就是选择合适Platform和Codec以及dai,用他们填充以上几个数据结构,然后注册Platform设备即可。

当然还要实现连接Platform和Codec的dai_link对应的ops实现;

msm8x16_sec_mi2s_be_ops的结构体是一个函数指针结构体,里面注册了相应的回调函数:

1 static struct snd_soc_ops msm8x16_mi2s_be_ops = {
2     .startup = msm_mi2s_snd_startup,
3     .hw_params = msm_mi2s_snd_hw_params,
4     .shutdown = msm_mi2s_snd_shutdown,
5 };

在高通平台中,这primary_mi2s这一路i2s,都是留给内部codec用的,所以,这路的dai_link上的codec_name和codec_dai_name,就是对应着内部codec的信息:

 1 /* Backend I2S DAI Links */
 2 {
 3         .name = LPASS_BE_PRI_MI2S_RX,
 4         .stream_name = "Primary MI2S Playback",
 5         .cpu_dai_name = "msm-dai-q6-mi2s.0",
 6         .platform_name = "msm-pcm-routing",
 7         .codec_name     = MSM8X16_CODEC_NAME,
 8         .codec_dai_name = "msm8x16_wcd_i2s_rx1",
 9         .no_pcm = 1,
10         .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
11         .init = &msm_audrx_init,
12         .be_hw_params_fixup = msm_pri_rx_be_hw_params_fixup,
13         .ops = &msm8x16_mi2s_be_ops,
14         .ignore_suspend = 1,
15 },

从msm8x16_wcd_i2s_rx1我们便可以找到高通平台默认的msm8x16-wcd.c,在该文件中,注册了snd_soc_codec_driver:

(5)、注册相应的驱动:

如何匹配?

那这里就要谈论一个问题,在初始化的时候,如何凭借dai_link中的codec信息找到对应的codec,答案是codec_name。但注意,这里并不是通过这个名字直接寻找的,例如8916平台。

这下就来到重要的函数:

1 ret = snd_soc_register_card(card);
2 if (ret) {
3         dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
4             ret);
5         goto err;
6 }

 1 /**
 2  * snd_soc_register_card - Register a card with the ASoC core
 3  *
 4  * @card: Card to register
 5  *
 6  */
 7 int snd_soc_register_card(struct snd_soc_card *card)
 8 {
 9     int i, ret;
10
11     if (!card->name || !card->dev)
12         return -EINVAL;
13
14     for (i = 0; i < card->num_links; i++) {
15         struct snd_soc_dai_link *link = &card->dai_link[i];
16
17         /*
18          * Codec must be specified by 1 of name or OF node,
19          * not both or neither.
20          */
21         if (!!link->codec_name == !!link->codec_of_node) {
22             dev_err(card->dev, "ASoC: Neither/both codec"
23                 " name/of_node are set for %s\n", link->name);
24             return -EINVAL;
25         }
26         /* Codec DAI name must be specified */
27         if (!link->codec_dai_name) {
28             dev_err(card->dev, "ASoC: codec_dai_name not"
29                 " set for %s\n", link->name);
30             return -EINVAL;
31         }
32
33         /*
34          * Platform may be specified by either name or OF node, but
35          * can be left unspecified, and a dummy platform will be used.
36          */
37         if (link->platform_name && link->platform_of_node) {
38             dev_err(card->dev, "ASoC: Both platform name/of_node"
39                 " are set for %s\n", link->name);
40             return -EINVAL;
41         }
42
43         /*
44          * CPU device may be specified by either name or OF node, but
45          * can be left unspecified, and will be matched based on DAI
46          * name alone..
47          */
48         if (link->cpu_name && link->cpu_of_node) {
49             dev_err(card->dev, "ASoC: Neither/both "
50                 "cpu name/of_node are set for %s\n",link->name);
51             return -EINVAL;
52         }
53         /*
54          * At least one of CPU DAI name or CPU device name/node must be
55          * specified
56          */
57         if (!link->cpu_dai_name &&
58             !(link->cpu_name || link->cpu_of_node)) {
59             dev_err(card->dev, "ASoC: Neither cpu_dai_name nor "
60                 "cpu_name/of_node are set for %s\n", link->name);
61             return -EINVAL;
62         }
63     }
64
65     dev_set_drvdata(card->dev, card);
66
67     snd_soc_initialize_card_lists(card);
68
69     soc_init_card_debugfs(card);
70
71     card->rtd = devm_kzalloc(card->dev,
72                  sizeof(struct snd_soc_pcm_runtime) *
73                  (card->num_links + card->num_aux_devs),
74                  GFP_KERNEL);
75     if (card->rtd == NULL)
76         return -ENOMEM;
77     card->num_rtd = 0;
78     card->rtd_aux = &card->rtd[card->num_links];
79
80     for (i = 0; i < card->num_links; i++)
81         card->rtd[i].dai_link = &card->dai_link[i];
82
83     INIT_LIST_HEAD(&card->list);
84     INIT_LIST_HEAD(&card->dapm_dirty);
85     card->instantiated = 0;
86     mutex_init(&card->mutex);
87     mutex_init(&card->dapm_mutex);
88     mutex_init(&card->dapm_power_mutex);
89     ret = snd_soc_instantiate_card(card);
90     if (ret != 0)
91         soc_cleanup_card_debugfs(card);
92
93     return ret;
94 }

snd_soc_register_card

将link指针遍历msm8x16_dai结构体数组的每一个成员:

1 for (i = 0; i < card->num_links; i++) {
2     struct snd_soc_dai_link *link = &card->dai_link[i];

这里定义了codec_name,名字为msm8x16_wcd_codec,所以不执行if的内容:

1 if (!!link->codec_name == !!link->codec_of_node) {
2             dev_err(card->dev, "ASoC: Neither/both codec"
3                 " name/of_node are set for %s\n", link->name);
4             return -EINVAL;
5 }

同理,下面的函数也是一样:

 1 /* Codec DAI name must be specified */
 2         if (!link->codec_dai_name) {
 3             dev_err(card->dev, "ASoC: codec_dai_name not"
 4                 " set for %s\n", link->name);
 5             return -EINVAL;
 6         }
 7
 8         /*
 9          * Platform may be specified by either name or OF node, but
10          * can be left unspecified, and a dummy platform will be used.
11          */
12         if (link->platform_name && link->platform_of_node) {
13             dev_err(card->dev, "ASoC: Both platform name/of_node"
14                 " are set for %s\n", link->name);
15             return -EINVAL;
16         }
17
18         /*
19          * CPU device may be specified by either name or OF node, but
20          * can be left unspecified, and will be matched based on DAI
21          * name alone..
22          */
23         if (link->cpu_name && link->cpu_of_node) {
24             dev_err(card->dev, "ASoC: Neither/both "
25                 "cpu name/of_node are set for %s\n",link->name);
26             return -EINVAL;
27         }
28         /*
29          * At least one of CPU DAI name or CPU device name/node must be
30          * specified
31          */
32         if (!link->cpu_dai_name &&
33             !(link->cpu_name || link->cpu_of_node)) {
34             dev_err(card->dev, "ASoC: Neither cpu_dai_name nor "
35                 "cpu_name/of_node are set for %s\n", link->name);
36             return -EINVAL;
37         }

继续向下看:

 1        //设置声卡设备驱动信息
 2        dev_set_drvdata(card->dev,card);
 3        //初始化声卡设备列表
 4        snd_soc_initialize_card_lists(card);
 5
 6        soc_init_card_debugfs(card);
 7        //为声卡中的snd_soc_pcm_runtime数据结构分配内存空间
 8        card->rtd= devm_kzalloc(card->dev,
 9                              sizeof(struct snd_soc_pcm_runtime) *
10                              (card->num_links + card->num_aux_devs),
11                              GFP_KERNEL);
12        if(card->rtd == NULL)
13               return-ENOMEM;
14        card->num_rtd= 0;
15        card->rtd_aux= &card->rtd[card->num_links];
16
17        for(i = 0; i < card->num_links; i++)
18               card->rtd[i].dai_link= &card->dai_link[i];
19
20        INIT_LIST_HEAD(&card->list);
21        INIT_LIST_HEAD(&card->dapm_dirty);
22        card->instantiated= 0;          //表明声卡还没有被初始化
23        mutex_init(&card->mutex);
24        mutex_init(&card->dapm_mutex);
25        //初始化声卡
26        ret= snd_soc_instantiate_card(card);
27        if(ret != 0)
28               soc_cleanup_card_debugfs(card);

在snd_soc_instantiate_card函数中:

  1 static int snd_soc_instantiate_card(struct snd_soc_card *card)
  2 {
  3     struct snd_soc_codec *codec;
  4     struct snd_soc_codec_conf *codec_conf;
  5     enum snd_soc_compress_type compress_type;
  6     struct snd_soc_dai_link *dai_link;
  7     int ret, i, order, dai_fmt;
  8
  9     mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 10
 11     /* bind DAIs */
 12     for (i = 0; i < card->num_links; i++) {
 13         ret = soc_bind_dai_link(card, i);
 14         if (ret != 0)
 15             goto base_error;
 16     }
 17
 18     /* check aux_devs too */
 19     for (i = 0; i < card->num_aux_devs; i++) {
 20         ret = soc_check_aux_dev(card, i);
 21         if (ret != 0)
 22             goto base_error;
 23     }
 24
 25     /* initialize the register cache for each available codec */
 26     list_for_each_entry(codec, &codec_list, list) {
 27         if (codec->cache_init)
 28             continue;
 29         /* by default we don‘t override the compress_type */
 30         compress_type = 0;
 31         /* check to see if we need to override the compress_type */
 32         for (i = 0; i < card->num_configs; ++i) {
 33             codec_conf = &card->codec_conf[i];
 34             if (!strcmp(codec->name, codec_conf->dev_name)) {
 35                 compress_type = codec_conf->compress_type;
 36                 if (compress_type && compress_type
 37                     != codec->compress_type)
 38                     break;
 39             }
 40         }
 41         ret = snd_soc_init_codec_cache(codec, compress_type);
 42         if (ret < 0)
 43             goto base_error;
 44     }
 45
 46     /* card bind complete so register a sound card */
 47     ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 48             card->owner, 0, &card->snd_card);
 49     if (ret < 0) {
 50         dev_err(card->dev, "ASoC: can‘t create sound card for"
 51             " card %s: %d\n", card->name, ret);
 52         goto base_error;
 53     }
 54     card->snd_card->dev = card->dev;
 55
 56     card->dapm.bias_level = SND_SOC_BIAS_OFF;
 57     card->dapm.dev = card->dev;
 58     card->dapm.card = card;
 59     list_add(&card->dapm.list, &card->dapm_list);
 60
 61 #ifdef CONFIG_DEBUG_FS
 62     snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
 63 #endif
 64
 65 #ifdef CONFIG_PM_SLEEP
 66     /* deferred resume work */
 67     INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 68 #endif
 69
 70     if (card->dapm_widgets)
 71         snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
 72                       card->num_dapm_widgets);
 73
 74     /* initialise the sound card only once */
 75     if (card->probe) {
 76         ret = card->probe(card);
 77         if (ret < 0)
 78             goto card_probe_error;
 79     }
 80
 81     /* probe all components used by DAI links on this card */
 82     for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 83             order++) {
 84         for (i = 0; i < card->num_links; i++) {
 85             ret = soc_probe_link_components(card, i, order);
 86             if (ret < 0) {
 87                 dev_err(card->dev,
 88                     "ASoC: failed to instantiate card %d\n",
 89                     ret);
 90                 goto probe_dai_err;
 91             }
 92         }
 93     }
 94
 95     /* probe all DAI links on this card */
 96     for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 97             order++) {
 98         for (i = 0; i < card->num_links; i++) {
 99             ret = soc_probe_link_dais(card, i, order);
100             if (ret < 0) {
101                 dev_err(card->dev,
102                     "ASoC: failed to instantiate card %d\n",
103                     ret);
104                 goto probe_dai_err;
105             }
106         }
107     }
108
109     for (i = 0; i < card->num_aux_devs; i++) {
110         ret = soc_probe_aux_dev(card, i);
111         if (ret < 0) {
112             dev_err(card->dev,
113                 "ASoC: failed to add auxiliary devices %d\n",
114                 ret);
115             goto probe_aux_dev_err;
116         }
117     }
118
119     snd_soc_dapm_link_dai_widgets(card);
120
121     if (card->controls)
122         snd_soc_add_card_controls(card, card->controls, card->num_controls);
123
124     if (card->dapm_routes)
125         snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
126                     card->num_dapm_routes);
127
128     snd_soc_dapm_new_widgets(&card->dapm);
129
130     for (i = 0; i < card->num_links; i++) {
131         dai_link = &card->dai_link[i];
132         dai_fmt = dai_link->dai_fmt;
133
134         if (dai_fmt) {
135             ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
136                           dai_fmt);
137             if (ret != 0 && ret != -ENOTSUPP)
138                 dev_warn(card->rtd[i].codec_dai->dev,
139                      "ASoC: Failed to set DAI format: %d\n",
140                      ret);
141         }
142
143         /* If this is a regular CPU link there will be a platform */
144         if (dai_fmt &&
145             (dai_link->platform_name || dai_link->platform_of_node)) {
146             ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
147                           dai_fmt);
148             if (ret != 0 && ret != -ENOTSUPP)
149                 dev_warn(card->rtd[i].cpu_dai->dev,
150                      "ASoC: Failed to set DAI format: %d\n",
151                      ret);
152         } else if (dai_fmt) {
153             /* Flip the polarity for the "CPU" end */
154             dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
155             switch (dai_link->dai_fmt &
156                 SND_SOC_DAIFMT_MASTER_MASK) {
157             case SND_SOC_DAIFMT_CBM_CFM:
158                 dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
159                 break;
160             case SND_SOC_DAIFMT_CBM_CFS:
161                 dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
162                 break;
163             case SND_SOC_DAIFMT_CBS_CFM:
164                 dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
165                 break;
166             case SND_SOC_DAIFMT_CBS_CFS:
167                 dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
168                 break;
169             }
170
171             ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
172                           dai_fmt);
173             if (ret != 0 && ret != -ENOTSUPP)
174                 dev_warn(card->rtd[i].cpu_dai->dev,
175                      "ASoC: Failed to set DAI format: %d\n",
176                      ret);
177         }
178     }
179
180     snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
181          "%s", card->name);
182     snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
183          "%s", card->long_name ? card->long_name : card->name);
184     snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
185          "%s", card->driver_name ? card->driver_name : card->name);
186     for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
187         switch (card->snd_card->driver[i]) {
188         case ‘_‘:
189         case ‘-‘:
190         case ‘\0‘:
191             break;
192         default:
193             if (!isalnum(card->snd_card->driver[i]))
194                 card->snd_card->driver[i] = ‘_‘;
195             break;
196         }
197     }
198
199     if (card->late_probe) {
200         ret = card->late_probe(card);
201         if (ret < 0) {
202             dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n",
203                 card->name, ret);
204             goto probe_aux_dev_err;
205         }
206     }
207
208     snd_soc_dapm_new_widgets(&card->dapm);
209
210     if (card->fully_routed)
211         list_for_each_entry(codec, &card->codec_dev_list, card_list)
212             snd_soc_dapm_auto_nc_codec_pins(codec);
213
214     ret = snd_card_register(card->snd_card);
215     if (ret < 0) {
216         dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
217                 ret);
218         goto probe_aux_dev_err;
219     }
220
221 #ifdef CONFIG_SND_SOC_AC97_BUS
222     /* register any AC97 codecs */
223     for (i = 0; i < card->num_rtd; i++) {
224         ret = soc_register_ac97_dai_link(&card->rtd[i]);
225         if (ret < 0) {
226             dev_err(card->dev, "ASoC: failed to register AC97:"
227                 " %d\n", ret);
228             while (--i >= 0)
229                 soc_unregister_ac97_dai_link(card->rtd[i].codec);
230             goto probe_aux_dev_err;
231         }
232     }
233 #endif
234
235     card->instantiated = 1;
236     snd_soc_dapm_sync(&card->dapm);
237     mutex_unlock(&card->mutex);
238
239     return 0;
240
241 probe_aux_dev_err:
242     for (i = 0; i < card->num_aux_devs; i++)
243         soc_remove_aux_dev(card, i);
244
245 probe_dai_err:
246     soc_remove_dai_links(card);
247
248 card_probe_error:
249     if (card->remove)
250         card->remove(card);
251
252     snd_card_free(card->snd_card);
253
254 base_error:
255     mutex_unlock(&card->mutex);
256
257     return ret;
258 }

snd_soc_instantiate_card

1 /*bind DAIs */
2  for(i = 0; i < card->num_links; i++) {
3         //逐一绑定声卡的各类DAI链接,下面会详细介绍该函数
4         ret= soc_bind_dai_link(card, i);
5         if(ret != 0)
6              gotobase_error;
7  }
 1 /* initialize the register cache for each available codec */
 2 //遍历CODEC列表中的所有CODEC
 3 list_for_each_entry(codec, &codec_list, list) {
 4     //CODEC缓存是否已初始化
 5     if (codec->cache_init)
 6         continue;
 7     /* by default we don‘t override the compress_type */
 8     //设置压缩类型
 9     compress_type = 0;
10     /* check to see if we need to override the compress_type */
11     for (i = 0; i < card->num_configs; ++i) {
12         codec_conf = &card->codec_conf[i];
13         if (!strcmp(codec->name, codec_conf->dev_name)) {
14             compress_type = codec_conf->compress_type;
15             if (compress_type && compress_type
16                 != codec->compress_type)
17                 break;
18         }
19     }
20     /*初始化CODEC缓存,该函数最终调用sound/soc/soc-cache.c文件内的snd_soc_flat_cache_init函数,为缓存(reg_cache)开辟内存空间,并把codec->cache_init置为1*/
21     ret = snd_soc_init_codec_cache(codec, compress_type);
22     if (ret < 0)
23         goto base_error;
24 }
1 //创建声卡
2 ret= snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
3              card->owner,0, &card->snd_card);

继续看soc_bind_dai_link函数,通过msm8x16-wcd.c中probe的of_device_id就可以知道:

554         pm8916_tombak_dig: [email protected]{
555             compatible = "qcom,wcd-spmi";
556             reg = <0xf000 0x100>;
557             interrupt-parent = <&spmi_bus>;
558             interrupts = <0x1 0xf0 0x0>,
559                      <0x1 0xf0 0x1>,
560                      <0x1 0xf0 0x2>,
561                      <0x1 0xf0 0x3>,
562                      <0x1 0xf0 0x4>,
563                      <0x1 0xf0 0x5>,
564                      <0x1 0xf0 0x6>,
565                      <0x1 0xf0 0x7>;
566             interrupt-names = "spk_cnp_int",
567                       "spk_clip_int",
568                       "spk_ocp_int",
569                       "ins_rem_det1",
570                       "but_rel_det",
571                       "but_press_det",
572                       "ins_rem_det",
573                       "mbhc_int";

而这个node节点正式codec驱动的设备树节点。在soc_bind_dai_link()函数中,会做出如下处理:

 1 /*注册codec的时候,会将所有注册的codec链接到codec_list中*/
 2     list_for_each_entry(codec, &codec_list, list) {
 3         if (dai_link->codec_of_node) {
 4             /*根据设备数节点句柄进行匹配*/
 5             if (codec->dev->of_node != dai_link->codec_of_node)
 6                 continue;
 7         } else {
 8             /*如果句柄为空,根据,codec_name进行匹配,在这里不会走这里,其实codec_name是 wcd-spmi-core.1*/
 9             if (strcmp(codec->name, dai_link->codec_name))
10                 continue;
11         }
12
13         rtd->codec = codec;
14
15         /*找到codec之后,根据codec_dai的名字找到对应的codec_dai*/
16         list_for_each_entry(codec_dai, &dai_list, list) {
17             if (codec->dev == codec_dai->dev &&
18                 !strcmp(codec_dai->name,
19                     dai_link->codec_dai_name)) {
20
21                 rtd->codec_dai = codec_dai;
22             }
23         }
24     }

所以,我们可以根据dai_link中的codec_dai的名字或者codec名字来找到对应的codec驱动。

另外,当播放音频的时候需要打开一个外部pa,所以probe函数中有一部分是external pa的初始化:

(6)、获取external pa:(也就是放大器):

 1   for (i = 0; i < num_strings; i++) {
 2             ret = of_property_read_string_index(pdev->dev.of_node,
 3                     ext_pa, i, &ext_pa_str);
 4             if (ret) {
 5                 dev_err(&pdev->dev, "%s:of read string %s i %d error %d\n",
 6                         __func__, ext_pa, i, ret);
 7                 goto err;
 8             }
 9             if (!strcmp(ext_pa_str, "primary"))
10                 pdata->ext_pa = (pdata->ext_pa | PRI_MI2S_ID);
11             else if (!strcmp(ext_pa_str, "secondary"))
12                 pdata->ext_pa = (pdata->ext_pa | SEC_MI2S_ID);
13             else if (!strcmp(ext_pa_str, "tertiary"))
14                 pdata->ext_pa = (pdata->ext_pa | TER_MI2S_ID);
15             else if (!strcmp(ext_pa_str, "quaternary"))
16                 pdata->ext_pa = (pdata->ext_pa | QUAT_MI2S_ID);
17         }
18         pr_err("%s: ext_pa = %d\n", __func__, pdata->ext_pa);
1 pinctrl_info.pinctrl = pinctrl;
2 ret = get_cdc_gpio_lines(pinctrl, pdata->ext_pa);    //获取gpio状态
3 if (ret < 0) {
4         pr_err("%s: failed to ger the codec gpio‘s %d\n",
5                     __func__, ret);
6         goto err;
7 }

可以根据高通手册来看,所以设备树上的配置为secondary:

1 qcom,msm-ext-pa = "secondary";//"primary";

2. 相应的资料:

其实以上便是linux3.10以上的audio内核machine架构,网上搜索相应资料便可找到;贴上借鉴的资料:

http://blog.csdn.net/zhaocj/article/details/20533369

网上大牛的架构:

http://www.cnblogs.com/linhaostudy/p/8169383.html

原文地址:https://www.cnblogs.com/linhaostudy/p/8419231.html

时间: 2024-10-10 11:33:08

高通Auido中ASOC的machine驱动的相关文章

高通发力中低端处理器市场 联发科需要慌吗?

        别看现在智能手机市场打的这么火热,其实背后的芯片厂商竞争之激烈并不亚于小米和魅族.华为.乐视之间的撕X大战.高通和联发科绝对是一对生死冤家,此前高通将联发科打的满地找牙,后来却被联发科在中低端市场逆袭,二者之间的恩怨绝不是一朝一夕就构建起来的. 虽然此前高通凭借骁龙410等中低端处理器,抢走部分市场,但中低端手机依然是联发科在称王称霸.为了打击对手,并消除骁龙810发热带来的负面影响,同时扩大影响力,高通近日发布两款中低端处理器.作为老对手,联发科会发慌吗?  高通发狠 中低端芯

【转】高通平台android 环境配置编译及开发经验总结

原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流程分析 qcril 流程分析,设置sim卡锁 python scons 语法学习 Python 语言之 scons 工具流程分析: 1.2 搭建高通平台环境开发环境 高通and

高通android开发摘要

一部分是开源的.能够从codeaurora.org上下载,另一部分是高通产权的.须要从高通的站点上下载. 将高通产权的代码放到:vendor/qcom/proprietary 1. 设置bms一些參数 @msm-pm8226.dtsi中     pm8226_bms: qcom,bms{        qcom,low-soc-calculate-soc-threshold = <15>; //觉得是低电压的soc(15%)        qcom,low-soc-calculate-soc-

联发科VS高通,谁是最强土豪“芯”?

今年是iPhone诞生的第七个年头,网络上涌现了大量"七年之痒"的感概,加之权威数据显示,智能手机增长速度连续第七个季度下滑,让一些悲观主义者预言:智能手机已经步入PC式的黄昏时代.但笔者认为,智能手机非但没有近黄昏,反倒是刚刚掀开自己的"大时代".其实,iPhone于2007年横空出世时,富士康的流水线上仍然如火如荼地组装着诺基亚N82,从最帅CEO到最美女工们,全部统一地坚信:Nokia是世界上最好的手机,经久不衰,无可取代,前途无量,而这款精美的智能机几乎没有

高通的无限网卡Atheros ar9485 linux中启动

本人是asus a550cc的笔记本,驱动安装好了以后,无论如何启动不了wifi 参考http://ubuntuforums.org/showthread.php?t=2181558 在终端中输入以下命令可以解决 坑人啊 echo "options asus_nb_wmi wapf=4" | sudo tee /etc/modprobe.d/asus_nb_wmi.conf 高通的无限网卡Atheros ar9485 linux中启动

高通camera学习笔记五(actuator驱动参数解析)

1.概述 actuator驱动信息文件是指vendor目录下的$ActuatorName_actuator.h文件(如gigaset_actuator.h).此信息文件就是一个actuator_driver_ctrl_t结构体.包括actuator_params与actuator_tuned_params两部分,即driver与tunning两部分.文档以目前最主流的VCM为例进行参数的介绍. 2.driver部分信息——actuator_params act_type: actuator类型,

ALSA声卡驱动的DAPM-基于高通平台

最近使用tinymix 调试相应的音频通道,但是一直不知道音频通道的原理是什么.所以百度了一下,百度结果是与DPAM有关. 一.DAPM简介: DAPM是Dynamic Audio Power Management的缩写,直译过来就是动态音频电源管理的意思,DAPM是为了使基于linux的移动设备上的音频子系统,在任何时候都工作在最小功耗状态下.DAPM对用户空间的应用程序来说是透明的,所有与电源相关的开关都在ASoc core中完成.用户空间的应用程序无需对代码做出修改,也无需重新编译,DAP

高通LCD的pwm背光驱动

发生异常的现象: msm8953 lcd在快速亮灭的情况下背光概率性休眠不灭:测量高通pwm,发现正常的时候pwm的管脚LCM_BL_PWM为低电平,失败的时候为高电平: 根据原理图: mpp是什么? mpp是基于电源pmic的管脚,也叫做多功能管脚:MPP的全称是Multi Purpose Pin:可以做电源.gpio.ADC.PWM.SINK等功能. 背光的控制方式: LCD控制IC支持动态背光控制功能(CABC)通过解析图像的直方图动态改变输出PWM的占空比从而动态调节LCD的背光,在不改

AI驱动行业变革 高通让终端人工智能随处可见

目前,人工智能面临工作负载及移动互联环境带来的挑战.要在日常生活中实现终端人工智能,对终端产品的功耗和热效率有着更高的要求.因此在5G时代对于智能手机终端也需要进行新的设计和调整. 人工智能.5G并肩发展 高通持续引领行业发展 高通愿景是让终端人工智能随处可见.为解决当前人工智能面临的各项挑战,为用户带来更好的人工智能体验,高通推出了人工智能引擎"AIE".高通人工智能引擎AI Engine能够加速终端人工智能用户体验在部分骁龙移动平台上的实现.近日,人工智能创新论坛上,高通骁龙700