static int mxcmci_probe()

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