数字mic系列,注册machine
dts配置如下
digital_mic: digital-mic {status = "okay";compatible = "simple-audio-card";simple-audio-card,format = "i2s";simple-audio-card,mclk-fs = <256>;simple-audio-card,name = "digital-mic";simple-audio-card,cpu {sound-dai = <&i2s0_8ch>;};simple-audio-card,codec {sound-dai = <&dummy_codec>;};};
驱动代码位置 sound/soc/generic/simple-card.c
static int asoc_simple_card_probe(struct platform_device *pdev)
{struct simple_card_data *priv;struct snd_soc_dai_link *dai_link;struct simple_dai_props *dai_props;struct device *dev = &pdev->dev;struct device_node *np = dev->of_node;struct snd_soc_card *card;int num, ret;/* Get the number of DAI links */if (np && of_get_child_by_name(np, PREFIX "dai-link"))num = of_get_child_count(np);else/* 对于dai-link*/num = 1;/* Allocate the private data and the DAI link array */priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);if (!priv)return -ENOMEM;dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);if (!dai_props || !dai_link)return -ENOMEM;priv->dai_props = dai_props;priv->dai_link = dai_link;/* Init snd_soc_card */card = simple_priv_to_card(priv);card->owner = THIS_MODULE;card->dev = dev;card->dai_link = priv->dai_link;card->num_links = num;card->probe = asoc_simple_soc_card_probe;if (np && of_device_is_available(np)) {ret = asoc_simple_card_parse_of(priv);if (ret < 0) {if (ret != -EPROBE_DEFER)dev_err(dev, "parse error %d\n", ret);goto err;}} else {...}snd_soc_card_set_drvdata(card, priv);
asoc_simple_card_probe() -> asoc_simple_is_available()
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{struct device *dev = simple_priv_to_dev(priv);struct snd_soc_card *card = simple_priv_to_card(priv);struct device_node *dai_link;struct device_node *node = dev->of_node;int ret;if (!node)return -EINVAL;/* 这里会匹配 simple-audio-card,dai-link 子节点 */dai_link = of_get_child_by_name(node, PREFIX "dai-link");/* 解析 simple-audio-card,widgets 属性 */ret = asoc_simple_card_of_parse_widgets(card, PREFIX);if (ret < 0)goto card_parse_end;/* 解析 simple-audio-card,routing 属性 */ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);if (ret < 0)goto card_parse_end;/* Factor to mclk, used in hw_params() *//* 解析 simple-audio-card,mclk-fs 属性 */of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);/* Single/Muti DAI link(s) & New style of DT node *//* 不支持 跳过 */if (dai_link) {struct device_node *np = NULL;int i = 0;for_each_child_of_node(node, np) {dev_dbg(dev, "\tlink %d:\n", i);ret = asoc_simple_card_dai_link_of(np, priv,i, false);if (ret < 0) {of_node_put(np);goto card_parse_end;}i++;}} else {/* For single DAI link & old style of DT node */ret = asoc_simple_card_dai_link_of(node, priv, 0, true);if (ret < 0)goto card_parse_end;}/* label属性没有 * card->dai_link->name*/ret = asoc_simple_card_parse_card_name(card, PREFIX);if (ret < 0)goto card_parse_end;/* 没有aux-devs */ret = asoc_simple_card_parse_aux_devs(node, priv);card_parse_end:of_node_put(dai_link);return ret;
}
asoc_simple_card_probe() -> asoc_simple_is_available() -> asoc_simple_card_dai_link_of()
static int asoc_simple_card_dai_link_of(struct device_node *node,struct simple_card_data *priv,int idx,bool is_top_level_node)
{struct device *dev = simple_priv_to_dev(priv);struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;struct device_node *cpu = NULL;struct device_node *plat = NULL;struct device_node *codec = NULL;char prop[128];char *prefix = ""; int ret, single_cpu;/* For single DAI link & old style of DT node */if (is_top_level_node)prefix = PREFIX;snprintf(prop, sizeof(prop), "%scpu", prefix);/* simple-audio-card,cpu 节点 */cpu = of_get_child_by_name(node, prop);if (!cpu) {ret = -EINVAL;dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);goto dai_link_of_err;} snprintf(prop, sizeof(prop), "%splat", prefix);/* simple-audio-card,plat 节点 ,可以没有 */plat = of_get_child_by_name(node, prop);snprintf(prop, sizeof(prop), "%scodec", prefix);/* simple-audio-card,codec 节点 */codec = of_get_child_by_name(node, prop);if (!codec) {ret = -EINVAL;dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);goto dai_link_of_err;} /* 获取dai_fmt 主要通过machine和codec进行判断 */ret = asoc_simple_card_parse_daifmt(dev, node, codec,prefix, &dai_link->dai_fmt);if (ret < 0)goto dai_link_of_err;of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);/* 这里会找到platform* dai_link->cpu_of_node 会填充platform节点*/ret = asoc_simple_card_parse_cpu(cpu, dai_link,DAI, CELL, &single_cpu);if (ret < 0)goto dai_link_of_err;/* dai_link->codec_of_node 会填充codec节点 */ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);if (ret < 0)goto dai_link_of_err;/* 没有platform code */ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);if (ret < 0)goto dai_link_of_err;/* 不支持 */ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);if (ret < 0)goto dai_link_of_err;/* 不支持 */ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);if (ret < 0)goto dai_link_of_err;/* platform clk节点 * 查找顺序* 1. platform (simple-audio-card,cpu)节点的 clock * 2. platform (simple-audio-card,cpu)节点的 system-clock-frequency* 3. dai_link->cpu_of_node (i2s0_8ch) 节点的 clock* 这里是不是会到rcu ? 且只拿第一个时钟*/ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);if (ret < 0)goto dai_link_of_err;/* codec clk节点 * 查找顺序* 1. codec (simple-audio-card,codec)节点的 clock * 2. codec (simple-audio-card,codec)节点的 system-clock-frequency* 3. dai_link->codec_of_node (dummy_codec) 节点的 clock*/ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);if (ret < 0)goto dai_link_of_err;/* 没有platform_of_node * platform_of_node = cpu_of_node */ret = asoc_simple_card_canonicalize_dailink(dai_link);if (ret < 0)goto dai_link_of_err;/* "ff800000.i2s-tdm-dummy_codec"* dai_link->name & dai_link->stream_name */ret = asoc_simple_card_set_dailink_name(dev, dai_link,"%s-%s",dai_link->cpu_dai_name,dai_link->codec_dai_name);if (ret < 0)goto dai_link_of_err;dai_link->ops = &asoc_simple_card_ops;dai_link->init = asoc_simple_card_dai_init;/* dai_link->cpu_dai_name = NULL */asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);dai_link_of_err:of_node_put(cpu);of_node_put(codec);return ret;
}