基于px30平台RX809-1的codec声卡芯片的驱动分析

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);
        
        
        
        
        
        
        
        
        
        

 

你可能感兴趣的:(linux驱动)