emmc host的初始化和scan 这个host上连接的设备

来源:互联网 发布:淘宝外卖和美团哪种好 编辑:程序博客网 时间:2024/06/04 19:13
在driver/mmc/host下面的makefile中和dw相关的config如下:
obj-$(CONFIG_MMC_DW)        += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM)    += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_K3)        += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI)    += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP)    += dw_mmc-rockchip.o
我是打开了CONFIG_MMC_DW 和 CONFIG_MMC_DW_K3
所以dw的入口函数在dw_mmc-k3.c中
static struct platform_driver dw_mci_k3_pltfm_driver = {
    .probe        = dw_mci_k3_probe,
    .remove        = dw_mci_pltfm_remove,
    .driver        = {
        .name        = "dwmmc_k3",
        .of_match_table    = dw_mci_k3_match,
        .pm        = &dw_mci_k3_pmops,
    },
};

module_platform_driver(dw_mci_k3_pltfm_driver);
如果在dts中检测到
static const struct of_device_id dw_mci_k3_match[] = {
    { .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, },
    { .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, },
    {},
};

这两个字符串就调用dw_mci_k3_probe
static int dw_mci_k3_probe(struct platform_device *pdev)
{
    const struct dw_mci_drv_data *drv_data;
    const struct of_device_id *match;
//得到drv_data本例中就是k3_drv_data
    match = of_match_node(dw_mci_k3_match, pdev->dev.of_node);
    drv_data = match->data;
//调用dw_mci_pltfm_register
    return dw_mci_pltfm_register(pdev, drv_data);
}
int dw_mci_pltfm_register(struct platform_device *pdev,
              const struct dw_mci_drv_data *drv_data)
{
    struct dw_mci *host;
    struct resource    *regs;

    host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
    if (!host)
        return -ENOMEM;
//得到irq
    host->irq = platform_get_irq(pdev, 0);
    if (host->irq < 0)
        return host->irq;

    host->drv_data = drv_data;
    host->dev = &pdev->dev;
    host->irq_flags = 0;
    host->pdata = pdev->dev.platform_data;
//得到这个host的寄存器地址
    regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//对reg做ioremap ,这样在kernel中就可以访问这个寄存器地址了
    host->regs = devm_ioremap_resource(&pdev->dev, regs);
    if (IS_ERR(host->regs))
        return PTR_ERR(host->regs);

    /* Get registers' physical base address */
    host->phy_regs = regs->start;
//保存drv_data
    platform_set_drvdata(pdev, host);
//继续probe
    return dw_mci_probe(host);
}
在dw_mci_probe 中会从dts中parse其他变量例如:ciu/biu等
    host->biu_clk = devm_clk_get(host->dev, "biu");
    if (IS_ERR(host->biu_clk)) {
        dev_dbg(host->dev, "biu clock not available\n");
    } else {
        ret = clk_prepare_enable(host->biu_clk);
        if (ret) {
            dev_err(host->dev, "failed to enable biu clock\n");
            return ret;
        }
    }

但是最终要的是下面这段
    /* We need at least one slot to succeed */
    for (i = 0; i < host->num_slots; i++) {
        ret = dw_mci_init_slot(host, i);
        if (ret)
            dev_dbg(host->dev, "slot %d init failed\n", i);
        else
            init_slots++;
    }
在dw_mci_init_slot 中就调用mmc_alloc_host/mmc_add_host 向kernel 添加这个mmc host。
在mmc_alloc_host 中最重要的就是    INIT_DELAYED_WORK(&host->detect, mmc_rescan);,后面就可以通过mmc_rescan 来发现这个host上连接的设备,具体callstack如下:
[   11.777356] [<ffffffc00008a438>] dump_backtrace+0x0/0x164                    
[   11.782759] [<ffffffc00008a5b8>] show_stack+0x1c/0x28                        
[   11.787816] [<ffffffc000bbca58>] dump_stack+0x78/0x98                        
[   11.792870] [<ffffffc000bb9348>] panic+0xe8/0x244                            
[   11.797577] [<ffffffc00092c564>] mmc_add_card+0xc0/0x228                     
[   11.802894] [<ffffffc00092f71c>] mmc_attach_mmc+0xa8/0x18c                   
[   11.808382] [<ffffffc00092bb8c>] mmc_rescan+0x2a8/0x2f8                      
[   11.813612] [<ffffffc0000d4ef4>] process_one_work+0x154/0x3bc                
[   11.819362] [<ffffffc0000d52a4>] worker_thread+0x148/0x49c                   
[   11.824852] [<ffffffc0000db200>] kthread+0xe0/0xf8     

0 0