diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/mx_sdhci.c | 153 | ||||
-rw-r--r-- | drivers/mmc/host/mx_sdhci.h | 14 | ||||
-rw-r--r-- | drivers/mmc/host/mxc_mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 68 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.c | 4 |
5 files changed, 198 insertions, 45 deletions
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index 5a68a8e02fe2..0557d4d337c1 100644 --- a/drivers/mmc/host/mx_sdhci.c +++ b/drivers/mmc/host/mx_sdhci.c @@ -142,32 +142,32 @@ EXPORT_SYMBOL(mxc_mmc_force_detect); static void sdhci_dumpregs(struct sdhci_host *host) { - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); - printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", readl(host->ioaddr + SDHCI_DMA_ADDRESS), readl(host->ioaddr + SDHCI_HOST_VERSION)); - printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", (readl(host->ioaddr + SDHCI_BLOCK_SIZE) & 0xFFFF), (readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16)); - printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", readl(host->ioaddr + SDHCI_ARGUMENT), readl(host->ioaddr + SDHCI_TRANSFER_MODE)); - printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", readl(host->ioaddr + SDHCI_PRESENT_STATE), readl(host->ioaddr + SDHCI_HOST_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Clock: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Clock: 0x%08x\n", readl(host->ioaddr + SDHCI_CLOCK_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Int stat: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int stat: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_ENABLE), readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Caps: 0x%08x\n", readl(host->ioaddr + SDHCI_CAPABILITIES)); - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ===========================================\n"); } @@ -506,6 +506,30 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) host->flags &= ~SDHCI_REQ_USE_DMA; } + if (cpu_is_mx25() && (data->blksz * data->blocks < 0x10)) { + host->flags &= ~SDHCI_REQ_USE_DMA; + DBG("Reverting to PIO in small data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } else if (cpu_is_mx25() && (host->flags & SDHCI_USE_DMA)) { + host->flags |= SDHCI_REQ_USE_DMA; + DBG("Reverting to DMA in large data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } + if (host->flags & SDHCI_REQ_USE_DMA) { int i; struct scatterlist *tsg; @@ -644,7 +668,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) WARN_ON(host->cmd); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; mask = SDHCI_CMD_INHIBIT; if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) @@ -695,7 +719,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mode |= SDHCI_TRNS_READ; else mode &= ~SDHCI_TRNS_READ; - if (host->flags & SDHCI_USE_DMA) + if (host->flags & SDHCI_REQ_USE_DMA) mode |= SDHCI_TRNS_DMA; if (host->flags & SDHCI_USE_EXTERNAL_DMA) DBG("Prepare data completely in %s transfer mode.\n", @@ -727,6 +751,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_DATA; mode |= SDHCI_MAKE_CMD(cmd->opcode, flags); + if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) { + /* Eanble the DDR mode */ + mode |= SDHCI_TRNS_DDR_EN; + } else + mode &= ~SDHCI_TRNS_DDR_EN; DBG("Complete sending cmd, transfer mode would be 0x%x.\n", mode); writel(mode, host->ioaddr + SDHCI_TRANSFER_MODE); } @@ -775,6 +804,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int clk_rate = 0; u32 clk; unsigned long timeout; + struct mmc_ios ios = host->mmc->ios; if (clock == 0) { goto out; @@ -784,17 +814,20 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->plat_data->clk_flg = 1; } } - if (clock == host->clock) + if (clock == host->clock && !(ios.bus_width & MMC_BUS_WIDTH_DDR)) return; clk_rate = clk_get_rate(host->clk); clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK; - if (!cpu_is_mx53()) + if (cpu_is_mx53() || cpu_is_mx50()) + writel(clk | SDHCI_CLOCK_SDCLKFS1, + host->ioaddr + SDHCI_CLOCK_CONTROL); + else writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); if (clock == host->min_clk) prescaler = 16; - else if (cpu_is_mx53()) + else if (cpu_is_mx53() || cpu_is_mx50()) prescaler = 1; else prescaler = 0; @@ -820,6 +853,86 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) DBG("prescaler = 0x%x, divider = 0x%x\n", prescaler, div); clk |= (prescaler << 8) | (div << 4); + /* Configure the DLL when DDR mode is enabled */ + if (ios.bus_width & MMC_BUS_WIDTH_DDR) { + /* Make sure that the PER, HLK, IPG are all enabled */ + writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) + | SDHCI_CLOCK_IPG_EN + | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_PER_EN, + host->ioaddr + SDHCI_CLOCK_CONTROL); + + /* Enable the DLL and delay chain */ + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_ENABLE, + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_REF_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL REF LOCK Timeout!\n"); + }; + DBG("dll stat: 0x%x\n", readl(host->ioaddr + SDHCI_DLL_STATUS)); + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_SLV_UP_INT | DLL_CTRL_REF_UP_INT + | DLL_CTRL_SLV_DLY_TAR, + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_SLV_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL SLV LOCK Timeout!\n"); + }; + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_SLV_FORCE_UPD, + host->ioaddr + SDHCI_DLL_CONTROL); + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + & (~DLL_CTRL_SLV_FORCE_UPD), + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_REF_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL REF LOCK Timeout!\n"); + }; + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_SLV_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL SLV LOCK Timeout!\n"); + }; + DBG("dll stat: 0x%x\n", readl(host->ioaddr + SDHCI_DLL_STATUS)); + + /* Let the PER, HLK, IPG to be auto-gate */ + writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) + & ~(SDHCI_CLOCK_IPG_EN | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_PER_EN), + host->ioaddr + SDHCI_CLOCK_CONTROL); + + } else if (readl(host->ioaddr + SDHCI_DLL_STATUS) & DLL_STS_SLV_LOCK) { + /* reset DLL CTRL */ + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) | DLL_CTRL_RESET, + host->ioaddr + SDHCI_DLL_CONTROL); + } + /* Configure the clock control register */ clk |= (readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & (~SDHCI_CLOCK_MASK)); @@ -830,7 +943,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->ioaddr + SDHCI_CLOCK_CONTROL); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; while (timeout > 0) { timeout--; udelay(20); @@ -933,8 +1046,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) u32 tmp; mxc_dma_device_t dev_id = 0; - DBG("%s: clock %u, bus %lu, power %u, vdd %u\n", DRIVER_NAME, - ios->clock, 1UL << ios->bus_width, ios->power_mode, ios->vdd); + DBG("%s: clock %u, bus %u, power %u, vdd %u\n", DRIVER_NAME, + ios->clock, ios->bus_width, ios->power_mode, ios->vdd); host = mmc_priv(mmc); @@ -1000,10 +1113,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmp = readl(host->ioaddr + SDHCI_HOST_CONTROL); - if (ios->bus_width == MMC_BUS_WIDTH_4) { + if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) { tmp &= ~SDHCI_CTRL_8BITBUS; tmp |= SDHCI_CTRL_4BITBUS; - } else if (ios->bus_width == MMC_BUS_WIDTH_8) { + } else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) { tmp &= ~SDHCI_CTRL_4BITBUS; tmp |= SDHCI_CTRL_8BITBUS; } else if (ios->bus_width == MMC_BUS_WIDTH_1) { diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h index 0bd79934952e..fa36dff0fd9a 100644 --- a/drivers/mmc/host/mx_sdhci.h +++ b/drivers/mmc/host/mx_sdhci.h @@ -2,7 +2,6 @@ * linux/drivers/mmc/host/mx_sdhci.h - Secure Digital Host * Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -28,6 +27,7 @@ #define SDHCI_TRNS_DMA 0x00000001 #define SDHCI_TRNS_BLK_CNT_EN 0x00000002 #define SDHCI_TRNS_ACMD12 0x00000004 +#define SDHCI_TRNS_DDR_EN 0x00000008 #define SDHCI_TRNS_READ 0x00000010 #define SDHCI_TRNS_MULTI 0x00000020 #define SDHCI_TRNS_DPSEL 0x00200000 @@ -95,6 +95,7 @@ #define SDHCI_CLOCK_PER_EN 0x00000004 #define SDHCI_CLOCK_HLK_EN 0x00000002 #define SDHCI_CLOCK_IPG_EN 0x00000001 +#define SDHCI_CLOCK_SDCLKFS1 0x00000100 #define SDHCI_CLOCK_MASK 0x0000FFFF #define SDHCI_TIMEOUT_CONTROL 0x2E @@ -188,6 +189,17 @@ #define SDHCI_ADMA_ADDRESS 0x58 /* 60-FB reserved */ +#define SDHCI_DLL_CONTROL 0x60 +#define DLL_CTRL_ENABLE 0x00000001 +#define DLL_CTRL_RESET 0x00000002 +#define DLL_CTRL_SLV_FORCE_UPD 0x00000004 +#define DLL_CTRL_SLV_DLY_TAR 0x00000000 +#define DLL_CTRL_SLV_UP_INT 0x00200000 +#define DLL_CTRL_REF_UP_INT 0x20000000 + +#define SDHCI_DLL_STATUS 0x64 +#define DLL_STS_SLV_LOCK 0x00000001 +#define DLL_STS_REF_LOCK 0x00000002 /* ADMA Addr Descriptor Attribute Filed */ enum { diff --git a/drivers/mmc/host/mxc_mmc.c b/drivers/mmc/host/mxc_mmc.c index 980dc98c9b5f..9cb492f40145 100644 --- a/drivers/mmc/host/mxc_mmc.c +++ b/drivers/mmc/host/mxc_mmc.c @@ -13,7 +13,7 @@ */ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -1232,7 +1232,7 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->f_max = mmc_plat->max_clk; mmc->max_req_size = 32 * 1024; mmc->max_seg_size = mmc->max_req_size; - mmc->max_blk_count = 65536; + mmc->max_blk_count = 32; spin_lock_init(&host->lock); host->mmc = mmc; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c60352247c49..b849e873613b 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -183,6 +183,12 @@ static void mxs_mmc_detect_poll(unsigned long arg) BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) +#define MXS_MMC_ERR_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ) + /* SSP DMA interrupt handler */ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) { @@ -198,19 +204,17 @@ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) /* STOP the dma transfer here. */ mxs_dma_cooked(host->dmach, NULL); } - host->status = - __raw_readl(host->ssp_base + HW_SSP_STATUS); - if (host->cmd) /* else it is a bogus interrupt */ - complete(&host->dma_done); + if ((irq == host->dmairq) || (c1 & MXS_MMC_ERR_BITS)) + if (host->cmd) { + host->status = + __raw_readl(host->ssp_base + HW_SSP_STATUS); + complete(&host->dma_done); + } - if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) { - __raw_writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, host->ssp_base + \ - HW_SSP_CTRL0_CLR); - __raw_writel(BM_SSP_CTRL1_SDIO_IRQ_EN, host->ssp_base + \ - HW_SSP_CTRL1_CLR); + if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); - } + return IRQ_HANDLED; } @@ -239,6 +243,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct mxs_dma_desc *dma_desc = host->dma_desc; + unsigned long flags; dma_desc->cmd.cmd.bits.command = NO_DMA_XFER; dma_desc->cmd.cmd.bits.irq = 1; @@ -255,7 +260,8 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) if (host->sdio_irq_en) { dma_desc->cmd.pio_words[0] |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN; + dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } init_completion(&host->dma_done); @@ -265,6 +271,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "%s start DMA.\n", __func__); if (mxs_dma_enable(host->dmach) < 0) dev_err(host->dev, "mmc_dma_enable failed\n"); + wait_for_completion(&host->dma_done); cmd->error = mxs_mmc_cmd_error(host->status); @@ -273,6 +280,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Send the ac command to the device */ @@ -284,6 +292,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; + unsigned long flags; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; @@ -305,7 +314,8 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } dma_desc->cmd.pio_words[0] = ssp_ctrl0; @@ -356,6 +366,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Copy data between sg list and dma buffer */ @@ -451,6 +462,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) u32 data_size = cmd->data->blksz * cmd->data->blocks; u32 log2_block_size; + unsigned long flags; ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; @@ -551,17 +563,25 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) } /* Configure the CMD0 */ ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); - } else - ssp_cmd0 = - BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | - BF(cmd->opcode, SSP_CMD0_CMD) | - BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); - + } else { + if ((1<<log2_block_size) != cmd->data->blksz) { + BUG_ON(cmd->data->blocks > 1); + ssp_cmd0 = + BF(0, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(0, SSP_BLOCK_SIZE_BLOCK_COUNT); + } else + ssp_cmd0 = + BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); + } if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } - if (cmd->opcode == 12) + if ((cmd->opcode == 12) || (cmd->opcode == 53)) ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); @@ -628,6 +648,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Transferred %u bytes\n", cmd->data->bytes_xfered); } + mxs_dma_disable(host->dmach); } /* Begin sedning a command to the card */ @@ -672,6 +693,13 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) dev_dbg(host->dev, "MMC request\n"); + if (!host->present) { + mrq->cmd->error = -ETIMEDOUT; + mmc_request_done(mmc, mrq); + return; + } + + BUG_ON(host->mrq != NULL); host->mrq = mrq; mxs_mmc_start_cmd(host, mrq->cmd); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e55ac792d68c..c8c0a7e4f0af 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -694,14 +694,14 @@ static int pxamci_remove(struct platform_device *pdev) if (mmc) { struct pxamci_host *host = mmc_priv(mmc); + mmc_remove_host(mmc); + if (host->vcc) regulator_put(host->vcc); if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); - mmc_remove_host(mmc); - pxamci_stop_clock(host); writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, |