4. 注册machine

数字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进行判断 
     * 对于当前dts配置来说, dai_fmt = SND_SOC_DAIFMT_I2S
     */
    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节点
     * 其中宏定义如下
     * #define DAI	"sound-dai"
     * #define CELL	"#sound-dai-cells"
     * #define PREFIX	"simple-audio-card,"
     * 注意这里查找dai_name的时候
     * 优先从dai->driver->name
     * 如果没有则使用节点的名字
     * 如果没有找到cpu的节点,则会返回-EPROBE_DEFER
     */
    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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值