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.
18 #include <linux/dma-mapping.h>
20 #include <linux/dma/mxs-dma.h>
25 #include <linux/mmc/host.h>
26 #include <linux/mmc/mmc.h>
27 #include <linux/mmc/sdio.h>
28 #include <linux/mmc/slot-gpio.h>
32 #include <linux/spi/mxs-spi.h>
34 #define DRIVER_NAME "mxs-mmc"
51 struct mmc_host *mmc; member
62 static int mxs_mmc_get_cd(struct mmc_host *mmc) in mxs_mmc_get_cd() argument
64 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_get_cd()
65 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_get_cd()
68 if (host->broken_cd) in mxs_mmc_get_cd()
69 return -ENOSYS; in mxs_mmc_get_cd()
71 ret = mmc_gpio_get_cd(mmc); in mxs_mmc_get_cd()
75 present = mmc->caps & MMC_CAP_NEEDS_POLL || in mxs_mmc_get_cd()
76 !(readl(ssp->base + HW_SSP_STATUS(ssp)) & in mxs_mmc_get_cd()
79 if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) in mxs_mmc_get_cd()
87 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_reset()
91 ret = stmp_reset_block(ssp->base); in mxs_mmc_reset()
109 ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_reset()
111 if (host->sdio_irq_en) { in mxs_mmc_reset()
116 writel(ctrl0, ssp->base + HW_SSP_CTRL0); in mxs_mmc_reset()
117 writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp)); in mxs_mmc_reset()
126 struct mmc_command *cmd = host->cmd; in mxs_mmc_request_done()
127 struct mmc_data *data = host->data; in mxs_mmc_request_done()
128 struct mmc_request *mrq = host->mrq; in mxs_mmc_request_done()
129 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_request_done()
133 cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); in mxs_mmc_request_done()
134 cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp)); in mxs_mmc_request_done()
135 cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp)); in mxs_mmc_request_done()
136 cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp)); in mxs_mmc_request_done()
138 cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); in mxs_mmc_request_done()
142 if (cmd == mrq->sbc) { in mxs_mmc_request_done()
144 mxs_mmc_start_cmd(host, mrq->cmd); in mxs_mmc_request_done()
147 dma_unmap_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_request_done()
148 data->sg_len, ssp->dma_dir); in mxs_mmc_request_done()
153 if (!data->error) in mxs_mmc_request_done()
154 data->bytes_xfered = data->blocks * data->blksz; in mxs_mmc_request_done()
156 data->bytes_xfered = 0; in mxs_mmc_request_done()
158 host->data = NULL; in mxs_mmc_request_done()
159 if (data->stop && (data->error || !mrq->sbc)) { in mxs_mmc_request_done()
160 mxs_mmc_start_cmd(host, mrq->stop); in mxs_mmc_request_done()
165 host->mrq = NULL; in mxs_mmc_request_done()
166 mmc_request_done(host->mmc, mrq); in mxs_mmc_request_done()
179 struct mmc_command *cmd = host->cmd; in mxs_mmc_irq_handler()
180 struct mmc_data *data = host->data; in mxs_mmc_irq_handler()
181 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_irq_handler()
184 spin_lock(&host->lock); in mxs_mmc_irq_handler()
186 stat = readl(ssp->base + HW_SSP_CTRL1(ssp)); in mxs_mmc_irq_handler()
188 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); in mxs_mmc_irq_handler()
190 spin_unlock(&host->lock); in mxs_mmc_irq_handler()
193 mmc_signal_sdio_irq(host->mmc); in mxs_mmc_irq_handler()
196 cmd->error = -ETIMEDOUT; in mxs_mmc_irq_handler()
198 cmd->error = -EIO; in mxs_mmc_irq_handler()
203 data->error = -ETIMEDOUT; in mxs_mmc_irq_handler()
205 data->error = -EILSEQ; in mxs_mmc_irq_handler()
208 data->error = -EIO; in mxs_mmc_irq_handler()
217 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_prep_dma()
219 struct mmc_data *data = host->data; in mxs_mmc_prep_dma()
225 dma_map_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_prep_dma()
226 data->sg_len, ssp->dma_dir); in mxs_mmc_prep_dma()
227 sgl = data->sg; in mxs_mmc_prep_dma()
228 sg_len = data->sg_len; in mxs_mmc_prep_dma()
231 sgl = (struct scatterlist *) ssp->ssp_pio_words; in mxs_mmc_prep_dma()
235 desc = dmaengine_prep_slave_sg(ssp->dmach, in mxs_mmc_prep_dma()
236 sgl, sg_len, ssp->slave_dirn, flags); in mxs_mmc_prep_dma()
238 desc->callback = mxs_mmc_dma_irq_callback; in mxs_mmc_prep_dma()
239 desc->callback_param = host; in mxs_mmc_prep_dma()
242 dma_unmap_sg(mmc_dev(host->mmc), data->sg, in mxs_mmc_prep_dma()
243 data->sg_len, ssp->dma_dir); in mxs_mmc_prep_dma()
251 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_bc()
252 struct mmc_command *cmd = host->cmd; in mxs_mmc_bc()
257 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC; in mxs_mmc_bc()
258 cmd1 = cmd->arg; in mxs_mmc_bc()
260 if (host->sdio_irq_en) { in mxs_mmc_bc()
265 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_bc()
266 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_bc()
267 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_bc()
268 ssp->dma_dir = DMA_NONE; in mxs_mmc_bc()
269 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_bc()
275 dma_async_issue_pending(ssp->dmach); in mxs_mmc_bc()
279 dev_warn(mmc_dev(host->mmc), in mxs_mmc_bc()
285 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_ac()
286 struct mmc_command *cmd = host->cmd; in mxs_mmc_ac()
299 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); in mxs_mmc_ac()
300 cmd1 = cmd->arg; in mxs_mmc_ac()
302 if (cmd->opcode == MMC_STOP_TRANSMISSION) in mxs_mmc_ac()
305 if (host->sdio_irq_en) { in mxs_mmc_ac()
310 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_ac()
311 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_ac()
312 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_ac()
313 ssp->dma_dir = DMA_NONE; in mxs_mmc_ac()
314 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_ac()
320 dma_async_issue_pending(ssp->dmach); in mxs_mmc_ac()
324 dev_warn(mmc_dev(host->mmc), in mxs_mmc_ac()
346 struct mmc_command *cmd = host->cmd; in mxs_mmc_adtc()
347 struct mmc_data *data = cmd->data; in mxs_mmc_adtc()
349 struct scatterlist *sgl = data->sg, *sg; in mxs_mmc_adtc()
350 unsigned int sg_len = data->sg_len; in mxs_mmc_adtc()
356 unsigned int blocks = data->blocks; in mxs_mmc_adtc()
358 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_adtc()
370 if (data->flags & MMC_DATA_WRITE) { in mxs_mmc_adtc()
380 ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | in mxs_mmc_adtc()
386 cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); in mxs_mmc_adtc()
389 log2_blksz = ilog2(data->blksz); in mxs_mmc_adtc()
392 * take special care of the case that data size from data->sg in mxs_mmc_adtc()
396 data_size += sg->length; in mxs_mmc_adtc()
398 if (data_size != data->blocks * data->blksz) in mxs_mmc_adtc()
405 BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); in mxs_mmc_adtc()
407 writel(data_size, ssp->base + HW_SSP_XFER_SIZE); in mxs_mmc_adtc()
409 BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), in mxs_mmc_adtc()
410 ssp->base + HW_SSP_BLOCK_SIZE); in mxs_mmc_adtc()
413 if (cmd->opcode == SD_IO_RW_EXTENDED) in mxs_mmc_adtc()
416 cmd1 = cmd->arg; in mxs_mmc_adtc()
418 if (host->sdio_irq_en) { in mxs_mmc_adtc()
424 timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns); in mxs_mmc_adtc()
425 val = readl(ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_adtc()
428 writel(val, ssp->base + HW_SSP_TIMING(ssp)); in mxs_mmc_adtc()
431 ssp->ssp_pio_words[0] = ctrl0; in mxs_mmc_adtc()
432 ssp->ssp_pio_words[1] = cmd0; in mxs_mmc_adtc()
433 ssp->ssp_pio_words[2] = cmd1; in mxs_mmc_adtc()
434 ssp->dma_dir = DMA_NONE; in mxs_mmc_adtc()
435 ssp->slave_dirn = DMA_TRANS_NONE; in mxs_mmc_adtc()
441 WARN_ON(host->data != NULL); in mxs_mmc_adtc()
442 host->data = data; in mxs_mmc_adtc()
443 ssp->dma_dir = dma_data_dir; in mxs_mmc_adtc()
444 ssp->slave_dirn = slave_dirn; in mxs_mmc_adtc()
450 dma_async_issue_pending(ssp->dmach); in mxs_mmc_adtc()
453 dev_warn(mmc_dev(host->mmc), in mxs_mmc_adtc()
460 host->cmd = cmd; in mxs_mmc_start_cmd()
476 dev_warn(mmc_dev(host->mmc), in mxs_mmc_start_cmd()
477 "%s: unknown MMC command\n", __func__); in mxs_mmc_start_cmd()
482 static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) in mxs_mmc_request() argument
484 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_request()
486 WARN_ON(host->mrq != NULL); in mxs_mmc_request()
487 host->mrq = mrq; in mxs_mmc_request()
489 if (mrq->sbc) in mxs_mmc_request()
490 mxs_mmc_start_cmd(host, mrq->sbc); in mxs_mmc_request()
492 mxs_mmc_start_cmd(host, mrq->cmd); in mxs_mmc_request()
495 static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) in mxs_mmc_set_ios() argument
497 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_set_ios()
499 if (ios->bus_width == MMC_BUS_WIDTH_8) in mxs_mmc_set_ios()
500 host->bus_width = 2; in mxs_mmc_set_ios()
501 else if (ios->bus_width == MMC_BUS_WIDTH_4) in mxs_mmc_set_ios()
502 host->bus_width = 1; in mxs_mmc_set_ios()
504 host->bus_width = 0; in mxs_mmc_set_ios()
506 if (ios->clock) in mxs_mmc_set_ios()
507 mxs_ssp_set_clk_rate(&host->ssp, ios->clock); in mxs_mmc_set_ios()
510 static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) in mxs_mmc_enable_sdio_irq() argument
512 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_enable_sdio_irq()
513 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_enable_sdio_irq()
516 spin_lock_irqsave(&host->lock, flags); in mxs_mmc_enable_sdio_irq()
518 host->sdio_irq_en = enable; in mxs_mmc_enable_sdio_irq()
522 ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); in mxs_mmc_enable_sdio_irq()
524 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); in mxs_mmc_enable_sdio_irq()
527 ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); in mxs_mmc_enable_sdio_irq()
529 ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR); in mxs_mmc_enable_sdio_irq()
532 spin_unlock_irqrestore(&host->lock, flags); in mxs_mmc_enable_sdio_irq()
534 if (enable && readl(ssp->base + HW_SSP_STATUS(ssp)) & in mxs_mmc_enable_sdio_irq()
536 mmc_signal_sdio_irq(host->mmc); in mxs_mmc_enable_sdio_irq()
550 .name = "imx23-mmc",
553 .name = "imx28-mmc",
562 { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
563 { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
571 of_match_device(mxs_mmc_dt_ids, &pdev->dev); in mxs_mmc_probe()
572 struct device_node *np = pdev->dev.of_node; in mxs_mmc_probe()
574 struct mmc_host *mmc; in mxs_mmc_probe() local
583 mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); in mxs_mmc_probe()
584 if (!mmc) in mxs_mmc_probe()
585 return -ENOMEM; in mxs_mmc_probe()
587 host = mmc_priv(mmc); in mxs_mmc_probe()
588 ssp = &host->ssp; in mxs_mmc_probe()
589 ssp->dev = &pdev->dev; in mxs_mmc_probe()
590 ssp->base = devm_platform_ioremap_resource(pdev, 0); in mxs_mmc_probe()
591 if (IS_ERR(ssp->base)) { in mxs_mmc_probe()
592 ret = PTR_ERR(ssp->base); in mxs_mmc_probe()
596 ssp->devid = (enum mxs_ssp_id) of_id->data; in mxs_mmc_probe()
598 host->mmc = mmc; in mxs_mmc_probe()
599 host->sdio_irq_en = 0; in mxs_mmc_probe()
601 reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); in mxs_mmc_probe()
605 dev_err(&pdev->dev, in mxs_mmc_probe()
611 ssp->clk = devm_clk_get(&pdev->dev, NULL); in mxs_mmc_probe()
612 if (IS_ERR(ssp->clk)) { in mxs_mmc_probe()
613 ret = PTR_ERR(ssp->clk); in mxs_mmc_probe()
616 ret = clk_prepare_enable(ssp->clk); in mxs_mmc_probe()
622 dev_err(&pdev->dev, "Failed to reset mmc: %d\n", ret); in mxs_mmc_probe()
626 ssp->dmach = dma_request_chan(&pdev->dev, "rx-tx"); in mxs_mmc_probe()
627 if (IS_ERR(ssp->dmach)) { in mxs_mmc_probe()
628 dev_err(mmc_dev(host->mmc), in mxs_mmc_probe()
630 ret = PTR_ERR(ssp->dmach); in mxs_mmc_probe()
634 /* set mmc core parameters */ in mxs_mmc_probe()
635 mmc->ops = &mxs_mmc_ops; in mxs_mmc_probe()
636 mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | in mxs_mmc_probe()
639 host->broken_cd = of_property_read_bool(np, "broken-cd"); in mxs_mmc_probe()
641 mmc->f_min = 400000; in mxs_mmc_probe()
642 mmc->f_max = 288000000; in mxs_mmc_probe()
644 ret = mmc_of_parse(mmc); in mxs_mmc_probe()
648 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; in mxs_mmc_probe()
650 mmc->max_segs = 52; in mxs_mmc_probe()
651 mmc->max_blk_size = 1 << 0xf; in mxs_mmc_probe()
652 mmc->max_blk_count = (ssp_is_old(ssp)) ? 0xff : 0xffffff; in mxs_mmc_probe()
653 mmc->max_req_size = (ssp_is_old(ssp)) ? 0xffff : 0xffffffff; in mxs_mmc_probe()
654 mmc->max_seg_size = dma_get_max_seg_size(ssp->dmach->device->dev); in mxs_mmc_probe()
656 platform_set_drvdata(pdev, mmc); in mxs_mmc_probe()
658 spin_lock_init(&host->lock); in mxs_mmc_probe()
660 ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, in mxs_mmc_probe()
661 dev_name(&pdev->dev), host); in mxs_mmc_probe()
665 ret = mmc_add_host(mmc); in mxs_mmc_probe()
669 dev_info(mmc_dev(host->mmc), "initialized\n"); in mxs_mmc_probe()
674 dma_release_channel(ssp->dmach); in mxs_mmc_probe()
676 clk_disable_unprepare(ssp->clk); in mxs_mmc_probe()
678 mmc_free_host(mmc); in mxs_mmc_probe()
684 struct mmc_host *mmc = platform_get_drvdata(pdev); in mxs_mmc_remove() local
685 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_remove()
686 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_remove()
688 mmc_remove_host(mmc); in mxs_mmc_remove()
690 if (ssp->dmach) in mxs_mmc_remove()
691 dma_release_channel(ssp->dmach); in mxs_mmc_remove()
693 clk_disable_unprepare(ssp->clk); in mxs_mmc_remove()
695 mmc_free_host(mmc); in mxs_mmc_remove()
703 struct mmc_host *mmc = dev_get_drvdata(dev); in mxs_mmc_suspend() local
704 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_suspend()
705 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_suspend()
707 clk_disable_unprepare(ssp->clk); in mxs_mmc_suspend()
713 struct mmc_host *mmc = dev_get_drvdata(dev); in mxs_mmc_resume() local
714 struct mxs_mmc_host *host = mmc_priv(mmc); in mxs_mmc_resume()
715 struct mxs_ssp *ssp = &host->ssp; in mxs_mmc_resume()
717 return clk_prepare_enable(ssp->clk); in mxs_mmc_resume()
737 MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");