2. 注册platform

文章详细分析了基于RockchipRV1126芯片的I2STDM接口在设备树中的配置,以及对应的驱动代码流程。从dts配置到内核的alsa子系统注册,包括devm_snd_soc_register_component和rockchip_pcm_platform_register函数,阐述了组件和DAI的注册过程,涉及DMA通道的请求和配置。
摘要由CSDN通过智能技术生成

这里先分析platform

对应的dts内容如下

    i2s0_8ch: i2s@ff800000 {
        compatible = "rockchip,rv1126-i2s-tdm";
        reg = <0xff800000 0x1000>;
        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&cru MCLK_I2S0_TX>, <&cru MCLK_I2S0_RX>, <&cru HCLK_I2S0>;
        clock-names = "mclk_tx", "mclk_rx", "hclk";
        dmas = <&dmac 20>, <&dmac 19>;
        dma-names = "tx", "rx";
        resets = <&cru SRST_I2S0_TX_M>, <&cru SRST_I2S0_RX_M>;
        reset-names = "tx-m", "rx-m";
        rockchip,cru = <&cru>;
        rockchip,grf = <&grf>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0m0_sclk_tx
                 &i2s0m0_sclk_rx
                 &i2s0m0_lrck_tx
                 &i2s0m0_lrck_rx
                 &i2s0m0_sdi0
                 &i2s0m0_sdo0
                 &i2s0m0_sdo1_sdi3
                 &i2s0m0_sdo2_sdi2
                 &i2s0m0_sdo3_sdi1>;
        status = "disabled";
    }; 
    
    &i2s0_8ch {
        status = "okay";
        #sound-dai-cells = <0>;
        rockchip,clk-trcm = <0>;
        rockchip,i2s-rx-route = <0 1 2 3>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0m0_lrck_rx
                &i2s0m0_sclk_rx
                &i2s0m0_sdi0>;
        rockchip,capture-only;
    }; 

对应的驱动代码位置

kernel/sound/soc/rockchip/rockchip_i2s_tdm.c

这里只关注alsa相关的代码

static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
{
    ...

    ret = devm_snd_soc_register_component(&pdev->dev,
                          &rockchip_i2s_tdm_component,
                          soc_dai, 1);

    ...

    ret = rockchip_pcm_platform_register(&pdev->dev);
    if (ret) {
        dev_err(&pdev->dev, "Could not register PCM\n");
        return ret;
    }

    ...
}

rockchip_i2s_tdm_probe()->devm_snd_soc_register_component()

 

int devm_snd_soc_register_component(struct device *dev,
             const struct snd_soc_component_driver *cmpnt_drv,
             struct snd_soc_dai_driver *dai_drv, int num_dai)
{
    struct device **ptr;
    int ret;

    ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
    if (!ptr)
        return -ENOMEM;

    ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
    if (ret == 0) {
        *ptr = dev;
        devres_add(dev, ptr);
    } else {
        devres_free(ptr);
    }   

    return ret;
}

int snd_soc_register_component(struct device *dev,
            const struct snd_soc_component_driver *component_driver,
            struct snd_soc_dai_driver *dai_drv,
            int num_dai)
{
    struct snd_soc_component *component;

    component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
    if (!component)
        return -ENOMEM;

    return snd_soc_add_component(dev, component, component_driver,
                     dai_drv, num_dai);
}

int snd_soc_add_component(struct device *dev,
            struct snd_soc_component *component,
            const struct snd_soc_component_driver *component_driver,
            struct snd_soc_dai_driver *dai_drv,
            int num_dai)
{
    int ret;
    int i;

    /* 初始化componment 
     * 关联dev和component_driver
     */
    ret = snd_soc_component_initialize(component, component_driver, dev);
    if (ret)
        goto err_free;

    if (component_driver->endianness) {
        for (i = 0; i < num_dai; i++) {
            convert_endianness_formats(&dai_drv[i].playback);
            convert_endianness_formats(&dai_drv[i].capture);
        }
    }

    /* 1. 创建dai
     * 2. 关联component dev dai_drv
     * 3. 将dai通过list挂载到component的dai_list
     * 4. 更新component->num_dai
     */
    ret = snd_soc_register_dais(component, dai_drv, num_dai);
    if (ret < 0) {
        dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
        goto err_cleanup;
    }

    /* 将component通过list挂载到 component_list (全局) 上*/
    snd_soc_component_add(component);

    return 0;

err_cleanup:
    snd_soc_component_cleanup(component);
err_free:
    return ret;
}

 rockchip_i2s_tdm_probe()->rockchip_pcm_platform_register()

int rockchip_pcm_platform_register(struct device *dev)
{
    return devm_snd_dmaengine_pcm_register(dev, &rk_dmaengine_pcm_config,
        SND_DMAENGINE_PCM_FLAG_COMPAT);
}

int devm_snd_dmaengine_pcm_register(struct device *dev,
    const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
    struct device **ptr;
    int ret;

    ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL);
    if (!ptr)
        return -ENOMEM;

    ret = snd_dmaengine_pcm_register(dev, config, flags);
    if (ret == 0) {
        *ptr = dev;
        devres_add(dev, ptr);
    } else {
        devres_free(ptr);
    }   

    return ret;
}

int snd_dmaengine_pcm_register(struct device *dev,
    const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
    struct dmaengine_pcm *pcm;
    int ret;

    pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
    if (!pcm)
        return -ENOMEM;

#ifdef CONFIG_DEBUG_FS
    pcm->component.debugfs_prefix = "dma";
#endif
    pcm->config = config;
    pcm->flags = flags;

    /* dma相关
     * 这里会关联到dma 获取dts中rx tx channel
     * channel存放在pcm->chan[]数组
     */
    ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
    if (ret)
        goto err_free_dma;

    if (config && config->process)
        ret = snd_soc_add_component(dev, &pcm->component,
                        &dmaengine_pcm_component_process,
                        NULL, 0); 
    else
        /* 增加一个新的component 主要用于dma相关
         * 同样component通过list挂载到 component_list (全局) 上
         */
        ret = snd_soc_add_component(dev, &pcm->component,
                        &dmaengine_pcm_component, NULL, 0); 
    if (ret)
        goto err_free_dma;

    return 0;

err_free_dma:
    dmaengine_pcm_release_chan(pcm);
    kfree(pcm);
    return ret;
}

 

 以上代码可以得到这样一张链接关系图,都只是挂载到链表,并没有实际的注册动作

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dianlong_lee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值