in host/meson-gx-mmc.c [1134:1308]
static int meson_mmc_probe(struct platform_device *pdev)
{
struct resource *res;
struct meson_host *host;
struct mmc_host *mmc;
int ret;
mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
host->mmc = mmc;
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
/* The G12A SDIO Controller needs an SRAM bounce buffer */
host->dram_access_quirk = device_property_read_bool(&pdev->dev,
"amlogic,dram-access-quirk");
/* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
if (ret)
goto free_host;
ret = mmc_of_parse(mmc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
goto free_host;
}
host->data = (struct meson_mmc_data *)
of_device_get_match_data(&pdev->dev);
if (!host->data) {
ret = -EINVAL;
goto free_host;
}
ret = device_reset_optional(&pdev->dev);
if (ret)
return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs)) {
ret = PTR_ERR(host->regs);
goto free_host;
}
host->irq = platform_get_irq(pdev, 0);
if (host->irq <= 0) {
ret = -EINVAL;
goto free_host;
}
host->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(host->pinctrl)) {
ret = PTR_ERR(host->pinctrl);
goto free_host;
}
host->pins_clk_gate = pinctrl_lookup_state(host->pinctrl,
"clk-gate");
if (IS_ERR(host->pins_clk_gate)) {
dev_warn(&pdev->dev,
"can't get clk-gate pinctrl, using clk_stop bit\n");
host->pins_clk_gate = NULL;
}
host->core_clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(host->core_clk)) {
ret = PTR_ERR(host->core_clk);
goto free_host;
}
ret = clk_prepare_enable(host->core_clk);
if (ret)
goto free_host;
ret = meson_mmc_clk_init(host);
if (ret)
goto err_core_clk;
/* set config to sane default */
meson_mmc_cfg_init(host);
/* Stop execution */
writel(0, host->regs + SD_EMMC_START);
/* clear, ack and enable interrupts */
writel(0, host->regs + SD_EMMC_IRQ_EN);
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
host->regs + SD_EMMC_STATUS);
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
host->regs + SD_EMMC_IRQ_EN);
ret = request_threaded_irq(host->irq, meson_mmc_irq,
meson_mmc_irq_thread, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
if (ret)
goto err_init_clk;
mmc->caps |= MMC_CAP_CMD23;
if (host->dram_access_quirk) {
/* Limit segments to 1 due to low available sram memory */
mmc->max_segs = 1;
/* Limit to the available sram memory */
mmc->max_blk_count = SD_EMMC_SRAM_DATA_BUF_LEN /
mmc->max_blk_size;
} else {
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
sizeof(struct sd_emmc_desc);
}
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
mmc->max_seg_size = mmc->max_req_size;
/*
* At the moment, we don't know how to reliably enable HS400.
* From the different datasheets, it is not even clear if this mode
* is officially supported by any of the SoCs
*/
mmc->caps2 &= ~MMC_CAP2_HS400;
if (host->dram_access_quirk) {
/*
* The MMC Controller embeds 1,5KiB of internal SRAM
* that can be used to be used as bounce buffer.
* In the case of the G12A SDIO controller, use these
* instead of the DDR memory
*/
host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
host->bounce_iomem_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
} else {
/* data bounce buffer */
host->bounce_buf_size = mmc->max_req_size;
host->bounce_buf =
dma_alloc_coherent(host->dev, host->bounce_buf_size,
&host->bounce_dma_addr, GFP_KERNEL);
if (host->bounce_buf == NULL) {
dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
ret = -ENOMEM;
goto err_free_irq;
}
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
&host->descs_dma_addr, GFP_KERNEL);
if (!host->descs) {
dev_err(host->dev, "Allocating descriptor DMA buffer failed\n");
ret = -ENOMEM;
goto err_bounce_buf;
}
mmc->ops = &meson_mmc_ops;
mmc_add_host(mmc);
return 0;
err_bounce_buf:
if (!host->dram_access_quirk)
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
err_free_irq:
free_irq(host->irq, host);
err_init_clk:
clk_disable_unprepare(host->mmc_clk);
err_core_clk:
clk_disable_unprepare(host->core_clk);
free_host:
mmc_free_host(mmc);
return ret;
}