Lines Matching +full:mmc +full:-

1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver
7 * Copyright 2009-2011 Freescale Semiconductor, Inc.
17 #include <linux/dma-mapping.h>
19 #include <linux/dma/mxs-dma.h>
24 #include <linux/mmc/host.h>
25 #include <linux/mmc/mmc.h>
26 #include <linux/mmc/sdio.h>
27 #include <linux/mmc/slot-gpio.h>
31 #include <linux/spi/mxs-spi.h>
33 #define DRIVER_NAME "mxs-mmc"
50 struct mmc_host *mmc; member
61 static int mxs_mmc_get_cd(struct mmc_host *mmc) in mxs_mmc_get_cd() argument
63 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_get_cd()
64 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_get_cd()
67 if (host->broken_cd) in mxs_mmc_get_cd()
68 return -ENOSYS; in mxs_mmc_get_cd()
70 ret = mmc_gpio_get_cd(mmc); in mxs_mmc_get_cd()
74 present = mmc->caps & MMC_CAP_NEEDS_POLL || in mxs_mmc_get_cd()
75 !(readl(ssp->base + HW_SSP_STATUS(ssp)) & in mxs_mmc_get_cd()
78 if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) in mxs_mmc_get_cd()
86 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_reset()
90 ret = stmp_reset_block(ssp->base); in mxs_mmc_reset()
108 ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_reset()
110 if (host->sdio_irq_en) { in mxs_mmc_reset()
115 writel(ctrl0, ssp->base + HW_SSP_CTRL0); in mxs_mmc_reset()
116 writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp)); in mxs_mmc_reset()
125 struct mmc_command *cmd = host->cmd; in mxs_mmc_request_done()
126 struct mmc_data *data = host->data; in mxs_mmc_request_done()
127 struct mmc_request *mrq = host->mrq; in mxs_mmc_request_done()
128 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_request_done()
132 cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); in mxs_mmc_request_done()
133 cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp)); in mxs_mmc_request_done()
134 cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp)); in mxs_mmc_request_done()
135 cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp)); in mxs_mmc_request_done()
137 cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); in mxs_mmc_request_done()
141 if (cmd == mrq->sbc) { in mxs_mmc_request_done()
143 mxs_mmc_start_cmd(host, mrq->cmd); in mxs_mmc_request_done()
146 dma_unmap_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_request_done()
147 data->sg_len, ssp->dma_dir); in mxs_mmc_request_done()
152 if (!data->error) in mxs_mmc_request_done()
153 data->bytes_xfered = data->blocks * data->blksz; in mxs_mmc_request_done()
155 data->bytes_xfered = 0; in mxs_mmc_request_done()
157 host->data = NULL; in mxs_mmc_request_done()
158 if (data->stop && (data->error || !mrq->sbc)) { in mxs_mmc_request_done()
159 mxs_mmc_start_cmd(host, mrq->stop); in mxs_mmc_request_done()
164 host->mrq = NULL; in mxs_mmc_request_done()
165 mmc_request_done(host->mmc, mrq); in mxs_mmc_request_done()
178 struct mmc_command *cmd = host->cmd; in mxs_mmc_irq_handler()
179 struct mmc_data *data = host->data; in mxs_mmc_irq_handler()
180 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_irq_handler()
183 spin_lock(&host->lock); in mxs_mmc_irq_handler()
185 stat = readl(ssp->base + HW_SSP_CTRL1(ssp)); in mxs_mmc_irq_handler()
187 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); in mxs_mmc_irq_handler()
189 spin_unlock(&host->lock); in mxs_mmc_irq_handler()
192 mmc_signal_sdio_irq(host->mmc); in mxs_mmc_irq_handler()
195 cmd->error = -ETIMEDOUT; in mxs_mmc_irq_handler()
197 cmd->error = -EIO; in mxs_mmc_irq_handler()
202 data->error = -ETIMEDOUT; in mxs_mmc_irq_handler()
204 data->error = -EILSEQ; in mxs_mmc_irq_handler()
207 data->error = -EIO; in mxs_mmc_irq_handler()
216 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_prep_dma()
218 struct mmc_data *data = host->data; in mxs_mmc_prep_dma()
224 dma_map_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_prep_dma()
225 data->sg_len, ssp->dma_dir); in mxs_mmc_prep_dma()
226 sgl = data->sg; in mxs_mmc_prep_dma()
227 sg_len = data->sg_len; in mxs_mmc_prep_dma()
230 sgl = (struct scatterlist *) ssp->ssp_pio_words; in mxs_mmc_prep_dma()
234 desc = dmaengine_prep_slave_sg(ssp->dmach, in mxs_mmc_prep_dma()
235 sgl, sg_len, ssp->slave_dirn, flags); in mxs_mmc_prep_dma()
237 desc->callback = mxs_mmc_dma_irq_callback; in mxs_mmc_prep_dma()
238 desc->callback_param = host; in mxs_mmc_prep_dma()
241 dma_unmap_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_prep_dma()
242 data->sg_len, ssp->dma_dir); in mxs_mmc_prep_dma()
250 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_bc()
251 struct mmc_command *cmd = host->cmd; in mxs_mmc_bc()
256 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC; in mxs_mmc_bc()
257 cmd1 = cmd->arg; in mxs_mmc_bc()
259 if (host->sdio_irq_en) { in mxs_mmc_bc()
264 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_bc()
265 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_bc()
266 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_bc()
267 ssp->dma_dir = DMA_NONE; in mxs_mmc_bc()
268 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_bc()
274 dma_async_issue_pending(ssp->dmach); in mxs_mmc_bc()
278 dev_warn(mmc_dev(host->mmc), in mxs_mmc_bc()
284 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_ac()
285 struct mmc_command *cmd = host->cmd; in mxs_mmc_ac()
298 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); in mxs_mmc_ac()
299 cmd1 = cmd->arg; in mxs_mmc_ac()
301 if (cmd->opcode == MMC_STOP_TRANSMISSION) in mxs_mmc_ac()
304 if (host->sdio_irq_en) { in mxs_mmc_ac()
309 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_ac()
310 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_ac()
311 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_ac()
312 ssp->dma_dir = DMA_NONE; in mxs_mmc_ac()
313 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_ac()
319 dma_async_issue_pending(ssp->dmach); in mxs_mmc_ac()
323 dev_warn(mmc_dev(host->mmc), in mxs_mmc_ac()
345 struct mmc_command *cmd = host->cmd; in mxs_mmc_adtc()
346 struct mmc_data *data = cmd->data; in mxs_mmc_adtc()
348 struct scatterlist *sgl = data->sg, *sg; in mxs_mmc_adtc()
349 unsigned int sg_len = data->sg_len; in mxs_mmc_adtc()
355 unsigned int blocks = data->blocks; in mxs_mmc_adtc()
357 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_adtc()
369 if (data->flags & MMC_DATA_WRITE) { in mxs_mmc_adtc()
379 ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | in mxs_mmc_adtc()
385 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); in mxs_mmc_adtc()
388 log2_blksz = ilog2(data->blksz); in mxs_mmc_adtc()
391 * take special care of the case that data size from data->sg in mxs_mmc_adtc()
395 data_size += sg->length; in mxs_mmc_adtc()
397 if (data_size != data->blocks * data->blksz) in mxs_mmc_adtc()
404 BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); in mxs_mmc_adtc()
406 writel(data_size, ssp->base + HW_SSP_XFER_SIZE); in mxs_mmc_adtc()
408 BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), in mxs_mmc_adtc()
409 ssp->base + HW_SSP_BLOCK_SIZE); in mxs_mmc_adtc()
412 if (cmd->opcode == SD_IO_RW_EXTENDED) in mxs_mmc_adtc()
415 cmd1 = cmd->arg; in mxs_mmc_adtc()
417 if (host->sdio_irq_en) { in mxs_mmc_adtc()
423 timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns); in mxs_mmc_adtc()
424 val = readl(ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_adtc()
427 writel(val, ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_adtc()
430 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_adtc()
431 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_adtc()
432 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_adtc()
433 ssp->dma_dir = DMA_NONE; in mxs_mmc_adtc()
434 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_adtc()
440 WARN_ON(host->data != NULL); in mxs_mmc_adtc()
441 host->data = data; in mxs_mmc_adtc()
442 ssp->dma_dir = dma_data_dir; in mxs_mmc_adtc()
443 ssp->slave_dirn = slave_dirn; in mxs_mmc_adtc()
449 dma_async_issue_pending(ssp->dmach); in mxs_mmc_adtc()
452 dev_warn(mmc_dev(host->mmc), in mxs_mmc_adtc()
459 host->cmd = cmd; in mxs_mmc_start_cmd()
475 dev_warn(mmc_dev(host->mmc), in mxs_mmc_start_cmd()
476 "%s: unknown MMC command\n", __func__); in mxs_mmc_start_cmd()
481 static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) in mxs_mmc_request() argument
483 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_request()
485 WARN_ON(host->mrq != NULL); in mxs_mmc_request()
486 host->mrq = mrq; in mxs_mmc_request()
488 if (mrq->sbc) in mxs_mmc_request()
489 mxs_mmc_start_cmd(host, mrq->sbc); in mxs_mmc_request()
491 mxs_mmc_start_cmd(host, mrq->cmd); in mxs_mmc_request()
494 static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) in mxs_mmc_set_ios() argument
496 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_set_ios()
498 if (ios->bus_width == MMC_BUS_WIDTH_8) in mxs_mmc_set_ios()
499 host->bus_width = 2; in mxs_mmc_set_ios()
500 else if (ios->bus_width == MMC_BUS_WIDTH_4) in mxs_mmc_set_ios()
501 host->bus_width = 1; in mxs_mmc_set_ios()
503 host->bus_width = 0; in mxs_mmc_set_ios()
505 if (ios->clock) in mxs_mmc_set_ios()
506 mxs_ssp_set_clk_rate(&host->ssp, ios->clock); in mxs_mmc_set_ios()
509 static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) in mxs_mmc_enable_sdio_irq() argument
511 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_enable_sdio_irq()
512 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_enable_sdio_irq()
515 spin_lock_irqsave(&host->lock, flags); in mxs_mmc_enable_sdio_irq()
517 host->sdio_irq_en = enable; in mxs_mmc_enable_sdio_irq()
521 ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); in mxs_mmc_enable_sdio_irq()
523 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); in mxs_mmc_enable_sdio_irq()
526 ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); in mxs_mmc_enable_sdio_irq()
528 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); in mxs_mmc_enable_sdio_irq()
531 spin_unlock_irqrestore(&host->lock, flags); in mxs_mmc_enable_sdio_irq()
533 if (enable && readl(ssp->base + HW_SSP_STATUS(ssp)) & in mxs_mmc_enable_sdio_irq()
535 mmc_signal_sdio_irq(host->mmc); in mxs_mmc_enable_sdio_irq()
548 { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
549 { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
561 struct device_node *np = pdev->dev.of_node; in mxs_mmc_probe()
563 struct mmc_host *mmc; in mxs_mmc_probe() local
572 mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); in mxs_mmc_probe()
573 if (!mmc) in mxs_mmc_probe()
574 return -ENOMEM; in mxs_mmc_probe()
576 host = mmc_priv(mmc); in mxs_mmc_probe()
577 ssp = &host->ssp; in mxs_mmc_probe()
578 ssp->dev = &pdev->dev; in mxs_mmc_probe()
579 ssp->base = devm_platform_ioremap_resource(pdev, 0); in mxs_mmc_probe()
580 if (IS_ERR(ssp->base)) { in mxs_mmc_probe()
581 ret = PTR_ERR(ssp->base); in mxs_mmc_probe()
585 ssp->devid = (enum mxs_ssp_id)of_device_get_match_data(&pdev->dev); in mxs_mmc_probe()
587 host->mmc = mmc; in mxs_mmc_probe()
588 host->sdio_irq_en = 0; in mxs_mmc_probe()
590 reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); in mxs_mmc_probe()
594 dev_err(&pdev->dev, in mxs_mmc_probe()
599 ret = devm_add_action_or_reset(&pdev->dev, mxs_mmc_regulator_disable, in mxs_mmc_probe()
605 ssp->clk = devm_clk_get(&pdev->dev, NULL); in mxs_mmc_probe()
606 if (IS_ERR(ssp->clk)) { in mxs_mmc_probe()
607 ret = PTR_ERR(ssp->clk); in mxs_mmc_probe()
610 ret = clk_prepare_enable(ssp->clk); in mxs_mmc_probe()
616 dev_err(&pdev->dev, "Failed to reset mmc: %d\n", ret); in mxs_mmc_probe()
620 ssp->dmach = dma_request_chan(&pdev->dev, "rx-tx"); in mxs_mmc_probe()
621 if (IS_ERR(ssp->dmach)) { in mxs_mmc_probe()
622 dev_err(mmc_dev(host->mmc), in mxs_mmc_probe()
624 ret = PTR_ERR(ssp->dmach); in mxs_mmc_probe()
628 /* set mmc core parameters */ in mxs_mmc_probe()
629 mmc->ops = &mxs_mmc_ops; in mxs_mmc_probe()
630 mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | in mxs_mmc_probe()
633 host->broken_cd = of_property_read_bool(np, "broken-cd"); in mxs_mmc_probe()
635 mmc->f_min = 400000; in mxs_mmc_probe()
636 mmc->f_max = 288000000; in mxs_mmc_probe()
638 ret = mmc_of_parse(mmc); in mxs_mmc_probe()
642 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; in mxs_mmc_probe()
644 mmc->max_segs = 52; in mxs_mmc_probe()
645 mmc->max_blk_size = 1 << 0xf; in mxs_mmc_probe()
646 mmc->max_blk_count = (ssp_is_old(ssp)) ? 0xff : 0xffffff; in mxs_mmc_probe()
647 mmc->max_req_size = (ssp_is_old(ssp)) ? 0xffff : 0xffffffff; in mxs_mmc_probe()
648 mmc->max_seg_size = dma_get_max_seg_size(ssp->dmach->device->dev); in mxs_mmc_probe()
650 platform_set_drvdata(pdev, mmc); in mxs_mmc_probe()
652 spin_lock_init(&host->lock); in mxs_mmc_probe()
654 ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, in mxs_mmc_probe()
655 dev_name(&pdev->dev), host); in mxs_mmc_probe()
659 ret = mmc_add_host(mmc); in mxs_mmc_probe()
663 dev_info(mmc_dev(host->mmc), "initialized\n"); in mxs_mmc_probe()
668 dma_release_channel(ssp->dmach); in mxs_mmc_probe()
670 clk_disable_unprepare(ssp->clk); in mxs_mmc_probe()
672 mmc_free_host(mmc); in mxs_mmc_probe()
678 struct mmc_host *mmc = platform_get_drvdata(pdev); in mxs_mmc_remove() local
679 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_remove()
680 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_remove()
682 mmc_remove_host(mmc); in mxs_mmc_remove()
684 if (ssp->dmach) in mxs_mmc_remove()
685 dma_release_channel(ssp->dmach); in mxs_mmc_remove()
687 clk_disable_unprepare(ssp->clk); in mxs_mmc_remove()
689 mmc_free_host(mmc); in mxs_mmc_remove()
695 struct mmc_host *mmc = dev_get_drvdata(dev); in mxs_mmc_suspend() local
696 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_suspend()
697 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_suspend()
699 clk_disable_unprepare(ssp->clk); in mxs_mmc_suspend()
705 struct mmc_host *mmc = dev_get_drvdata(dev); in mxs_mmc_resume() local
706 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_resume()
707 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_resume()
709 return clk_prepare_enable(ssp->clk); in mxs_mmc_resume()
728 MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");