diff options
Diffstat (limited to 'drivers/mmc/host/moxart-mmc.c')
| -rw-r--r-- | drivers/mmc/host/moxart-mmc.c | 115 |
1 files changed, 56 insertions, 59 deletions
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index bde298887579..3dd8f232052f 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -111,8 +111,8 @@ #define CLK_DIV_MASK 0x7f /* REG_BUS_WIDTH */ -#define BUS_WIDTH_8 BIT(2) -#define BUS_WIDTH_4 BIT(1) +#define BUS_WIDTH_4_SUPPORT BIT(3) +#define BUS_WIDTH_4 BIT(2) #define BUS_WIDTH_1 BIT(0) #define MMC_VDD_360 23 @@ -254,6 +254,11 @@ static void moxart_dma_complete(void *param) complete(&host->dma_complete); } +static bool moxart_use_dma(struct moxart_host *host) +{ + return (host->data_len > host->fifo_width) && host->have_dma; +} + static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) { u32 len, dir_slave; @@ -291,11 +296,11 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) dma_async_issue_pending(dma_chan); } - data->bytes_xfered += host->data_remain; - wait_for_completion_interruptible_timeout(&host->dma_complete, host->timeout); + data->bytes_xfered = host->data_len; + dma_unmap_sg(dma_chan->device->dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); @@ -338,13 +343,7 @@ static void moxart_transfer_pio(struct moxart_host *host) return; } for (len = 0; len < remain && len < host->fifo_width;) { - /* SCR data must be read in big endian. */ - if (data->mrq->cmd->opcode == SD_APP_SEND_SCR) - *sgp = ioread32be(host->base + - REG_DATA_WINDOW); - else - *sgp = ioread32(host->base + - REG_DATA_WINDOW); + *sgp = ioread32(host->base + REG_DATA_WINDOW); sgp++; len += 4; } @@ -381,7 +380,7 @@ static void moxart_prepare_data(struct moxart_host *host) if (data->flags & MMC_DATA_WRITE) datactrl |= DCR_DATA_WRITE; - if ((host->data_len > host->fifo_width) && host->have_dma) + if (moxart_use_dma(host)) datactrl |= DCR_DMA_EN; writel(DCR_DATA_FIFO_RESET, host->base + REG_DATA_CONTROL); @@ -413,7 +412,7 @@ static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq) moxart_send_command(host, host->mrq->cmd); if (mrq->cmd->data) { - if ((host->data_len > host->fifo_width) && host->have_dma) { + if (moxart_use_dma(host)) { writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK); @@ -524,9 +523,6 @@ static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_BUS_WIDTH_4: writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH); break; - case MMC_BUS_WIDTH_8: - writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH); - break; default: writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH); break; @@ -562,41 +558,33 @@ static int moxart_probe(struct platform_device *pdev) int irq, ret; u32 i; - mmc = mmc_alloc_host(sizeof(struct moxart_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) { - dev_err(dev, "mmc_alloc_host failed\n"); - ret = -ENOMEM; - goto out; + dev_err(dev, "devm_mmc_alloc_host failed\n"); + return -ENOMEM; } ret = of_address_to_resource(node, 0, &res_mmc); - if (ret) { - dev_err(dev, "of_address_to_resource failed\n"); - goto out; - } + if (ret) + return dev_err_probe(dev, ret, + "of_address_to_resource failed\n"); irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) { - dev_err(dev, "irq_of_parse_and_map failed\n"); - ret = -EINVAL; - goto out; - } + if (irq <= 0) + return dev_err_probe(dev, -EINVAL, + "irq_of_parse_and_map failed\n"); clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto out; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); reg_mmc = devm_ioremap_resource(dev, &res_mmc); - if (IS_ERR(reg_mmc)) { - ret = PTR_ERR(reg_mmc); - goto out; - } + if (IS_ERR(reg_mmc)) + return PTR_ERR(reg_mmc); ret = mmc_of_parse(mmc); if (ret) - goto out; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -614,6 +602,9 @@ static int moxart_probe(struct platform_device *pdev) mmc->f_max = DIV_ROUND_CLOSEST(host->sysclk, 2); mmc->f_min = DIV_ROUND_CLOSEST(host->sysclk, CLK_DIV_MASK * 2); mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */ + mmc->max_blk_size = 2048; /* Max. block length in REG_DATA_CONTROL */ + mmc->max_req_size = DATA_LEN_MASK; /* bits 0-23 in REG_DATA_LENGTH */ + mmc->max_blk_count = mmc->max_req_size / 512; if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER || @@ -621,13 +612,24 @@ static int moxart_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto out; } + if (!IS_ERR(host->dma_chan_tx)) { + dma_release_channel(host->dma_chan_tx); + host->dma_chan_tx = NULL; + } + if (!IS_ERR(host->dma_chan_rx)) { + dma_release_channel(host->dma_chan_rx); + host->dma_chan_rx = NULL; + } dev_dbg(dev, "PIO mode transfer enabled\n"); host->have_dma = false; + + mmc->max_seg_size = mmc->max_req_size; } else { dev_dbg(dev, "DMA channels found (%p,%p)\n", host->dma_chan_tx, host->dma_chan_rx); host->have_dma = true; + memset(&cfg, 0, sizeof(cfg)); cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -640,18 +642,14 @@ static int moxart_probe(struct platform_device *pdev) cfg.src_addr = host->reg_phys + REG_DATA_WINDOW; cfg.dst_addr = 0; dmaengine_slave_config(host->dma_chan_rx, &cfg); + + mmc->max_seg_size = min3(mmc->max_req_size, + dma_get_max_seg_size(host->dma_chan_rx->device->dev), + dma_get_max_seg_size(host->dma_chan_tx->device->dev)); } - switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) { - case 1: + if (readl(host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT) mmc->caps |= MMC_CAP_4_BIT_DATA; - break; - case 2: - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; - break; - default: - break; - } writel(0, host->base + REG_INTERRUPT_MASK); @@ -667,38 +665,37 @@ static int moxart_probe(struct platform_device *pdev) goto out; dev_set_drvdata(dev, mmc); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto out; dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width); return 0; out: - if (mmc) - mmc_free_host(mmc); + if (!IS_ERR_OR_NULL(host->dma_chan_tx)) + dma_release_channel(host->dma_chan_tx); + if (!IS_ERR_OR_NULL(host->dma_chan_rx)) + dma_release_channel(host->dma_chan_rx); return ret; } -static int moxart_remove(struct platform_device *pdev) +static void moxart_remove(struct platform_device *pdev) { struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); struct moxart_host *host = mmc_priv(mmc); - dev_set_drvdata(&pdev->dev, NULL); - - if (!IS_ERR(host->dma_chan_tx)) + if (!IS_ERR_OR_NULL(host->dma_chan_tx)) dma_release_channel(host->dma_chan_tx); - if (!IS_ERR(host->dma_chan_rx)) + if (!IS_ERR_OR_NULL(host->dma_chan_rx)) dma_release_channel(host->dma_chan_rx); mmc_remove_host(mmc); - mmc_free_host(mmc); writel(0, host->base + REG_INTERRUPT_MASK); writel(0, host->base + REG_POWER_CONTROL); writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, host->base + REG_CLOCK_CONTROL); - - return 0; } static const struct of_device_id moxart_mmc_match[] = { @@ -710,7 +707,7 @@ MODULE_DEVICE_TABLE(of, moxart_mmc_match); static struct platform_driver moxart_mmc_driver = { .probe = moxart_probe, - .remove = moxart_remove, + .remove = moxart_remove, .driver = { .name = "mmc-moxart", .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
