在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] [] dump_backtrace+0x0/0x164
[ 11.782759] [] show_stack+0x1c/0x28
[ 11.787816] [] dump_stack+0x78/0x98
[ 11.792870] [] panic+0xe8/0x244
[ 11.797577] [] mmc_add_card+0xc0/0x228
[ 11.802894] [] mmc_attach_mmc+0xa8/0x18c
[ 11.808382] [] mmc_rescan+0x2a8/0x2f8
[ 11.813612] [] process_one_work+0x154/0x3bc
[ 11.819362] [] worker_thread+0x148/0x49c
[ 11.824852] [] kthread+0xe0/0xf8