diff options
Diffstat (limited to 'drivers/mmc/host/moxart-mmc.c')
| -rw-r--r-- | drivers/mmc/host/moxart-mmc.c | 148 |
1 files changed, 71 insertions, 77 deletions
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index a0670e9cd012..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,10 +254,14 @@ 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; - long dma_time; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *dma_chan; @@ -292,10 +296,10 @@ 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); - dma_time = 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, @@ -339,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; } @@ -382,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); @@ -395,7 +393,6 @@ static void moxart_prepare_data(struct moxart_host *host) static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct moxart_host *host = mmc_priv(mmc); - long pio_time; unsigned long flags; u32 status; @@ -415,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); @@ -431,8 +428,8 @@ static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); /* PIO transfers start from interrupt. */ - pio_time = wait_for_completion_interruptible_timeout( - &host->pio_complete, host->timeout); + wait_for_completion_interruptible_timeout(&host->pio_complete, + host->timeout); spin_lock_irqsave(&host->lock, flags); } @@ -465,9 +462,8 @@ static irqreturn_t moxart_irq(int irq, void *devid) { struct moxart_host *host = (struct moxart_host *)devid; u32 status; - unsigned long flags; - spin_lock_irqsave(&host->lock, flags); + spin_lock(&host->lock); status = readl(host->base + REG_STATUS); if (status & CARD_CHANGE) { @@ -484,7 +480,7 @@ static irqreturn_t moxart_irq(int irq, void *devid) if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq) moxart_transfer_pio(host); - spin_unlock_irqrestore(&host->lock, flags); + spin_unlock(&host->lock); return IRQ_HANDLED; } @@ -527,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; @@ -565,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; @@ -608,8 +593,8 @@ static int moxart_probe(struct platform_device *pdev) host->timeout = msecs_to_jiffies(1000); host->sysclk = clk_get_rate(clk); host->fifo_width = readl(host->base + REG_FEATURE) << 2; - host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx"); - host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx"); + host->dma_chan_tx = dma_request_chan(dev, "tx"); + host->dma_chan_rx = dma_request_chan(dev, "rx"); spin_lock_init(&host->lock); @@ -617,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 || @@ -624,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; @@ -643,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); @@ -670,39 +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_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); + mmc_remove_host(mmc); - if (mmc) { - if (!IS_ERR(host->dma_chan_tx)) - dma_release_channel(host->dma_chan_tx); - if (!IS_ERR(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; + 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); } static const struct of_device_id moxart_mmc_match[] = { @@ -714,9 +707,10 @@ 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, .of_match_table = moxart_mmc_match, }, }; |
