Merge tag 'mmc-merge-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball: "Core: - Add DT properties for card detection (broken-cd, cd-gpios, non-removable) - Don't poll non-removable devices - Fixup/rework eMMC sleep mode/"power off notify" feature - Support eMMC background operations (BKOPS). To set the one-time programmable fuse that enables bkops on an eMMC that doesn't already have it set, you can use the "mmc bkops enable" command in: git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git Drivers: - atmel-mci, dw_mmc, pxa-mci, dove, s3c, spear: Add device tree support - bfin_sdh: Add support for the controller in bf60x - dw_mmc: Support Samsung Exynos SoCs - eSDHC: Add ADMA support - sdhci: Support testing a cd-gpio (from slot-gpio) instead of presence bit - sdhci-pltfm: Support broken-cd DT property - tegra: Convert to only supporting DT (mach-tegra has gone DT-only)" * tag 'mmc-merge-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (67 commits) mmc: core: Fixup broken suspend and eMMC4.5 power off notify mmc: sdhci-spear: Add clk_{un}prepare() support mmc: sdhci-spear: add device tree bindings mmc: sdhci-s3c: Add clk_(enable/disable) in runtime suspend/resume mmc: core: Replace MMC_CAP2_BROKEN_VOLTAGE with test for fixed regulator mmc: sdhci-pxav3: Use sdhci_get_of_property for parsing DT quirks mmc: dt: Support "broken-cd" property in sdhci-pltfm mmc: sdhci-s3c: fix the wrong number of max bus clocks mmc: sh-mmcif: avoid oops on spurious interrupts mmc: sh-mmcif: properly handle MMC_WRITE_MULTIPLE_BLOCK completion IRQ mmc: sdhci-s3c: Fix crash on module insertion for second time mmc: sdhci-s3c: Enable only required bus clock mmc: Revert "mmc: dw_mmc: Add check for IDMAC configuration" mmc: mxcmmc: fix bug that may block a data transfer forever mmc: omap_hsmmc: Pass on the suspend failure to the PM core mmc: atmel-mci: AP700x PDC is not connected to MCI mmc: atmel-mci: DMA can be used with other controllers mmc: mmci: use clk_prepare_enable and clk_disable_unprepare mmc: sdhci-s3c: Add device tree support mmc: dw_mmc: add support for exynos specific implementation of dw-mshc ...
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define DRIVER_NAME "mxc-mmc"
|
||||
#define MXCMCI_TIMEOUT_MS 10000
|
||||
|
||||
#define MMC_REG_STR_STP_CLK 0x00
|
||||
#define MMC_REG_STATUS 0x04
|
||||
@@ -150,6 +151,8 @@ struct mxcmci_host {
|
||||
int dmareq;
|
||||
struct dma_slave_config dma_slave_config;
|
||||
struct imx_dma_data dma_data;
|
||||
|
||||
struct timer_list watchdog;
|
||||
};
|
||||
|
||||
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
|
||||
@@ -271,9 +274,32 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
||||
dmaengine_submit(host->desc);
|
||||
dma_async_issue_pending(host->dma);
|
||||
|
||||
mod_timer(&host->watchdog, jiffies + msecs_to_jiffies(MXCMCI_TIMEOUT_MS));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat);
|
||||
static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat);
|
||||
|
||||
static void mxcmci_dma_callback(void *data)
|
||||
{
|
||||
struct mxcmci_host *host = data;
|
||||
u32 stat;
|
||||
|
||||
del_timer(&host->watchdog);
|
||||
|
||||
stat = readl(host->base + MMC_REG_STATUS);
|
||||
writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
|
||||
|
||||
if (stat & STATUS_READ_OP_DONE)
|
||||
writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
|
||||
|
||||
mxcmci_data_done(host, stat);
|
||||
}
|
||||
|
||||
static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
|
||||
unsigned int cmdat)
|
||||
{
|
||||
@@ -305,8 +331,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
|
||||
|
||||
int_cntr = INT_END_CMD_RES_EN;
|
||||
|
||||
if (mxcmci_use_dma(host))
|
||||
int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
|
||||
if (mxcmci_use_dma(host)) {
|
||||
if (host->dma_dir == DMA_FROM_DEVICE) {
|
||||
host->desc->callback = mxcmci_dma_callback;
|
||||
host->desc->callback_param = host;
|
||||
} else {
|
||||
int_cntr |= INT_WRITE_OP_DONE_EN;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
if (host->use_sdio)
|
||||
@@ -345,11 +377,9 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
|
||||
struct mmc_data *data = host->data;
|
||||
int data_error;
|
||||
|
||||
if (mxcmci_use_dma(host)) {
|
||||
dmaengine_terminate_all(host->dma);
|
||||
if (mxcmci_use_dma(host))
|
||||
dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
|
||||
host->dma_dir);
|
||||
}
|
||||
|
||||
if (stat & STATUS_ERR_MASK) {
|
||||
dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
|
||||
@@ -624,8 +654,10 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
|
||||
mxcmci_cmd_done(host, stat);
|
||||
|
||||
if (mxcmci_use_dma(host) &&
|
||||
(stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
|
||||
(stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
|
||||
del_timer(&host->watchdog);
|
||||
mxcmci_data_done(host, stat);
|
||||
}
|
||||
|
||||
if (host->default_irq_mask &&
|
||||
(stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
|
||||
@@ -836,6 +868,34 @@ static bool filter(struct dma_chan *chan, void *param)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mxcmci_watchdog(unsigned long data)
|
||||
{
|
||||
struct mmc_host *mmc = (struct mmc_host *)data;
|
||||
struct mxcmci_host *host = mmc_priv(mmc);
|
||||
struct mmc_request *req = host->req;
|
||||
unsigned int stat = readl(host->base + MMC_REG_STATUS);
|
||||
|
||||
if (host->dma_dir == DMA_FROM_DEVICE) {
|
||||
dmaengine_terminate_all(host->dma);
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"%s: read time out (status = 0x%08x)\n",
|
||||
__func__, stat);
|
||||
} else {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"%s: write time out (status = 0x%08x)\n",
|
||||
__func__, stat);
|
||||
mxcmci_softreset(host);
|
||||
}
|
||||
|
||||
/* Mark transfer as erroneus and inform the upper layers */
|
||||
|
||||
host->data->error = -ETIMEDOUT;
|
||||
host->req = NULL;
|
||||
host->cmd = NULL;
|
||||
host->data = NULL;
|
||||
mmc_request_done(host->mmc, req);
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops mxcmci_ops = {
|
||||
.request = mxcmci_request,
|
||||
.set_ios = mxcmci_set_ios,
|
||||
@@ -968,6 +1028,10 @@ static int mxcmci_probe(struct platform_device *pdev)
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
init_timer(&host->watchdog);
|
||||
host->watchdog.function = &mxcmci_watchdog;
|
||||
host->watchdog.data = (unsigned long)mmc;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_irq:
|
||||
|
Reference in New Issue
Block a user