in host/mxcmmc.c [980:1163]
static int mxcmci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct mxcmci_host *host;
struct resource *res;
int ret = 0, irq;
bool dat3_card_detect = false;
dma_cap_mask_t mask;
struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
pr_info("i.MX/MPC512x SDHC driver\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out_free;
}
host->phys_base = res->start;
ret = mmc_of_parse(mmc);
if (ret)
goto out_free;
mmc->ops = &mxcmci_ops;
/* For devicetree parsing, the bus width is read from devicetree */
if (pdata)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
else
mmc->caps |= MMC_CAP_SDIO_IRQ;
/* MMC core transfer sizes tunable parameters */
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev);
/* adjust max_segs after devtype detection */
if (!is_mpc512x_mmc(host))
mmc->max_segs = 64;
host->mmc = mmc;
host->pdata = pdata;
spin_lock_init(&host->lock);
if (pdata)
dat3_card_detect = pdata->dat3_card_detect;
else if (mmc_card_is_removable(mmc)
&& !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc);
if (ret)
goto out_free;
if (!mmc->ocr_avail) {
if (pdata && pdata->ocr_avail)
mmc->ocr_avail = pdata->ocr_avail;
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
}
if (dat3_card_detect)
host->default_irq_mask =
INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
else
host->default_irq_mask = 0;
host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(host->clk_ipg)) {
ret = PTR_ERR(host->clk_ipg);
goto out_free;
}
host->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(host->clk_per)) {
ret = PTR_ERR(host->clk_per);
goto out_free;
}
ret = clk_prepare_enable(host->clk_per);
if (ret)
goto out_free;
ret = clk_prepare_enable(host->clk_ipg);
if (ret)
goto out_clk_per_put;
mxcmci_softreset(host);
host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO);
if (host->rev_no != 0x400) {
ret = -ENODEV;
dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
host->rev_no);
goto out_clk_put;
}
mmc->f_min = clk_get_rate(host->clk_per) >> 16;
mmc->f_max = clk_get_rate(host->clk_per) >> 1;
/* recommended in data sheet */
mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO);
mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR);
if (!host->pdata) {
host->dma = dma_request_chan(&pdev->dev, "rx-tx");
if (IS_ERR(host->dma)) {
if (PTR_ERR(host->dma) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_clk_put;
}
/* Ignore errors to fall back to PIO mode */
host->dma = NULL;
}
} else {
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res) {
host->dmareq = res->start;
host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
host->dma_data.priority = DMA_PRIO_LOW;
host->dma_data.dma_request = host->dmareq;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma = dma_request_channel(mask, filter, host);
}
}
if (host->dma)
mmc->max_seg_size = dma_get_max_seg_size(
host->dma->device->dev);
else
dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n");
INIT_WORK(&host->datawork, mxcmci_datawork);
ret = devm_request_irq(&pdev->dev, irq, mxcmci_irq, 0,
dev_name(&pdev->dev), host);
if (ret)
goto out_free_dma;
platform_set_drvdata(pdev, mmc);
if (host->pdata && host->pdata->init) {
ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq,
host->mmc);
if (ret)
goto out_free_dma;
}
timer_setup(&host->watchdog, mxcmci_watchdog, 0);
mmc_add_host(mmc);
return 0;
out_free_dma:
if (host->dma)
dma_release_channel(host->dma);
out_clk_put:
clk_disable_unprepare(host->clk_ipg);
out_clk_per_put:
clk_disable_unprepare(host->clk_per);
out_free:
mmc_free_host(mmc);
return ret;
}