1:platform
rockchip_i2s.c: 将platform中的component放入dai链表,component->dai_drv指向rockchip_i2s_dai
rockchip_i2s_probe
1.1:/* clk init */
i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");
ret = clk_prepare_enable(i2s->hclk);
1.2:/* i2s regmap init */
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &rockchip_i2s_regmap_config);
1.3:/* dma init*/
i2s->playback_dma_data.addr = res->start + I2S_TXDR;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = 8;
i2s->capture_dma_data.addr = res->start + I2S_RXDR;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = 8;
1.4:/* snd_soc_dai_driver register*/
soc_dai = devm_kzalloc(&pdev->dev, sizeof(*soc_dai), GFP_KERNEL);
memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai));
ret = devm_snd_soc_register_component(&pdev->dev, &rockchip_i2s_component, soc_dai, 1);
struct snd_soc_component_driver component->dai_drv = dai_drv; //dai_drv = snd_soc_dai_driver = rockchip_i2s_dai
struct snd_soc_dai *dai;
dai->component = component;
dai->driver = &dai_drv[i];
list_add(&dai->list, &component->dai_list);
附1:
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
.hw_params = rockchip_i2s_hw_params,
.set_sysclk = rockchip_i2s_set_sysclk,
.set_fmt = rockchip_i2s_set_fmt,
.trigger = rockchip_i2s_trigger,
};
static struct snd_soc_dai_driver rockchip_i2s_dai = {
.probe = rockchip_i2s_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE),
},
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE),
},
.ops = &rockchip_i2s_dai_ops,
.symmetric_rates = 1,
};
2:codec
rk817_codec.c:将codec->component放入dai链表,codec->component->dai_drv指向rk817_dai
rk817_platform_probe
2.1:/* parse device tree */
rk817_codec_data = devm_kzalloc(&pdev->dev, sizeof(struct rk817_codec_priv), GFP_KERNEL);
platform_set_drvdata(pdev, rk817_codec_data);
ret = rk817_codec_parse_dt_property(&pdev->dev, rk817_codec_data);
2.2:/* i2c regmap init ,cpntrol interface */
rk817_codec_data->regmap = devm_regmap_init_i2c(rk817->i2c, &rk817_codec_regmap_config);
2.3:/* codec register */
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_rk817, rk817_dai, ARRAY_SIZE(rk817_dai));
struct snd_soc_codec *codec;
ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
codec->component>dai_drv = snd_soc_dai_driver = rk817_dai
dai->component = component;
dai->driver = &dai_drv[i];
list_add(&dai->list, &component->dai_list);
list_add(&codec->list, &codec_list);
附2:
static struct snd_soc_codec_driver soc_codec_dev_rk817 = {
.probe = rk817_probe,
.remove = rk817_remove,
.get_regmap = rk817_get_regmap,
.suspend = rk817_suspend,
.resume = rk817_resume,
};
static struct snd_soc_dai_ops rk817_dai_ops = {
.hw_params = rk817_hw_params,
.set_fmt = rk817_set_dai_fmt,
.set_sysclk = rk817_set_dai_sysclk,
.digital_mute = rk817_digital_mute,
};
static struct snd_soc_dai_driver rk817_dai[] = {
{
.name = "rk817-hifi",
.id = RK817_HIFI,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 8,
.rates = RK817_PLAYBACK_RATES,
.formats = RK817_FORMATS,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 8,
.rates = RK817_CAPTURE_RATES,
.formats = RK817_FORMATS,
},
.ops = &rk817_dai_ops,
},
........
};
3:simple-card.c:绑定CPU DAI和CODEC DAI
asoc_simple_card_probe
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
3.1:/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*dai_link) * num_links, GFP_KERNEL);
3.2:/* Init snd_soc_card */
priv->snd_card.owner = THIS_MODULE;
priv->snd_card.dev = dev;
dai_link = priv->dai_link;
priv->snd_card.dai_link = dai_link;
priv->snd_card.num_links = num_links;
priv->gpio_hp_det = -ENOENT;
priv->gpio_mic_det = -ENOENT;
priv->codec_hp_det = false
3.3:/* Get room for the other properties */
priv->dai_props = devm_kzalloc(dev, sizeof(*priv->dai_props) * num_links, GFP_KERNEL);
3.4:/* parse device tree */
ret = asoc_simple_card_parse_of(np, priv);
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, "simple-audio-card,widgets");
ret = snd_soc_of_parse_audio_routing(&priv->snd_card, "simple-audio-card,routing");
ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val);
ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
cpu = of_get_child_by_name(node, prop); //解析cpu dai
codec = of_get_child_by_name(node, prop); //解析codec dai
ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,&dai_link->cpu_of_node,&dai_link->cpu_dai_name,&cpu_args);
ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,&dai_link->codec_of_node,&dai_link->codec_dai_name, NULL);
dai_link->name = dai_link->stream_name = name;
dai_link->ops = &asoc_simple_card_ops; //ops为snd_soc_ops static struct snd_soc_ops asoc_simple_card_ops = {
.startup = asoc_simple_card_startup,
.shutdown = asoc_simple_card_shutdown,
.hw_params = asoc_simple_card_hw_params,
};
dai_link->init = asoc_simple_card_dai_init;
snd_soc_card_set_drvdata(&priv->snd_card, priv);
3.5:/* snd_soc_card register */
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
ret = snd_soc_register_card(card);
card->rtd = devm_kzalloc(card->dev,sizeof(struct snd_soc_pcm_runtime)*(card->num_links + card->num_aux_devs), GFP_KERNEL);
card->rtd[i].card = card;
card->rtd[i].dai_link = &card->dai_link[i];
ret = snd_soc_instantiate_card(card);
3.5.1:/* bind DAIs */
ret = soc_bind_dai_link(card, i);
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); //从dai链表中根据name找到cpu dai
codec_dais[i] = snd_soc_find_dai(&codecs[i]); //从dai链表中根据name找到codec dai
rtd->codec_dai = codec_dais[0];
3.5.2:/* initialize the register cache for each available codec */
ret = snd_soc_init_codec_cache(codec);
3.5.3:/* card bind complete so register a sound card */
ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card);
3.5.3:/* probe all components used by DAI links on this card */
ret = soc_probe_link_components(card, i, order); //调用snd_soc_codec_driver中的probe函数,即rk817_probe
1.6:/* probe all DAI links on this card */
ret = soc_probe_link_dais(card, i, order); //依次调用cpu dai和codec dai的probe函数,即rockchip_i2s_dai_probe,codec dai drive中没有
ret = snd_card_register(card->snd_card);