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 ...
此提交包含在:
@@ -35,7 +35,6 @@
|
||||
#include <linux/mmc/core.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -44,7 +43,6 @@
|
||||
#include <plat/cpu.h>
|
||||
|
||||
/* OMAP HSMMC Host Controller Registers */
|
||||
#define OMAP_HSMMC_SYSCONFIG 0x0010
|
||||
#define OMAP_HSMMC_SYSSTATUS 0x0014
|
||||
#define OMAP_HSMMC_CON 0x002C
|
||||
#define OMAP_HSMMC_BLK 0x0104
|
||||
@@ -161,8 +159,6 @@ struct omap_hsmmc_host {
|
||||
unsigned int dma_sg_idx;
|
||||
unsigned char bus_mode;
|
||||
unsigned char power_mode;
|
||||
u32 *buffer;
|
||||
u32 bytesleft;
|
||||
int suspended;
|
||||
int irq;
|
||||
int use_dma, dma_ch;
|
||||
@@ -171,7 +167,6 @@ struct omap_hsmmc_host {
|
||||
int slot_id;
|
||||
int response_busy;
|
||||
int context_loss;
|
||||
int vdd;
|
||||
int protect_card;
|
||||
int reqs_blocked;
|
||||
int use_reg;
|
||||
@@ -300,12 +295,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
|
||||
struct regulator *reg;
|
||||
int ocr_value = 0;
|
||||
|
||||
mmc_slot(host).set_power = omap_hsmmc_set_power;
|
||||
|
||||
reg = regulator_get(host->dev, "vmmc");
|
||||
if (IS_ERR(reg)) {
|
||||
dev_dbg(host->dev, "vmmc regulator missing\n");
|
||||
return PTR_ERR(reg);
|
||||
} else {
|
||||
mmc_slot(host).set_power = omap_hsmmc_set_power;
|
||||
host->vcc = reg;
|
||||
ocr_value = mmc_regulator_get_ocrmask(reg);
|
||||
if (!mmc_slot(host).ocr_mask) {
|
||||
@@ -495,7 +490,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
|
||||
unsigned long regval;
|
||||
unsigned long timeout;
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
|
||||
dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
|
||||
|
||||
omap_hsmmc_stop_clock(host);
|
||||
|
||||
@@ -579,21 +574,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
|
||||
if (host->context_loss == context_loss)
|
||||
return 1;
|
||||
|
||||
/* Wait for hardware reset */
|
||||
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
|
||||
while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
|
||||
&& time_before(jiffies, timeout))
|
||||
;
|
||||
|
||||
/* Do software reset */
|
||||
OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
|
||||
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
|
||||
while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
|
||||
&& time_before(jiffies, timeout))
|
||||
;
|
||||
|
||||
OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
|
||||
OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
|
||||
if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
|
||||
return 1;
|
||||
|
||||
if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
|
||||
if (host->power_mode != MMC_POWER_OFF &&
|
||||
@@ -745,7 +727,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
|
||||
{
|
||||
int cmdreg = 0, resptype = 0, cmdtype = 0;
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
|
||||
dev_vdbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
|
||||
mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
|
||||
host->cmd = cmd;
|
||||
|
||||
@@ -934,7 +916,7 @@ static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
|
||||
buf += len;
|
||||
}
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc), "%s\n", res);
|
||||
dev_vdbg(mmc_dev(host->mmc), "%s\n", res);
|
||||
}
|
||||
#else
|
||||
static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
|
||||
@@ -981,72 +963,40 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
|
||||
__func__);
|
||||
}
|
||||
|
||||
static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
|
||||
{
|
||||
omap_hsmmc_reset_controller_fsm(host, SRC);
|
||||
host->cmd->error = err;
|
||||
|
||||
if (host->data) {
|
||||
omap_hsmmc_reset_controller_fsm(host, SRD);
|
||||
omap_hsmmc_dma_cleanup(host, err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
|
||||
{
|
||||
struct mmc_data *data;
|
||||
int end_cmd = 0, end_trans = 0;
|
||||
|
||||
if (!host->req_in_progress) {
|
||||
do {
|
||||
OMAP_HSMMC_WRITE(host->base, STAT, status);
|
||||
/* Flush posted write */
|
||||
status = OMAP_HSMMC_READ(host->base, STAT);
|
||||
} while (status & INT_EN_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
data = host->data;
|
||||
dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
|
||||
dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
|
||||
|
||||
if (status & ERR) {
|
||||
omap_hsmmc_dbg_report_irq(host, status);
|
||||
if ((status & CMD_TIMEOUT) ||
|
||||
(status & CMD_CRC)) {
|
||||
if (host->cmd) {
|
||||
if (status & CMD_TIMEOUT) {
|
||||
omap_hsmmc_reset_controller_fsm(host,
|
||||
SRC);
|
||||
host->cmd->error = -ETIMEDOUT;
|
||||
} else {
|
||||
host->cmd->error = -EILSEQ;
|
||||
}
|
||||
end_cmd = 1;
|
||||
}
|
||||
if (host->data || host->response_busy) {
|
||||
if (host->data)
|
||||
omap_hsmmc_dma_cleanup(host,
|
||||
-ETIMEDOUT);
|
||||
host->response_busy = 0;
|
||||
omap_hsmmc_reset_controller_fsm(host, SRD);
|
||||
}
|
||||
}
|
||||
if ((status & DATA_TIMEOUT) ||
|
||||
(status & DATA_CRC)) {
|
||||
if (host->data || host->response_busy) {
|
||||
int err = (status & DATA_TIMEOUT) ?
|
||||
-ETIMEDOUT : -EILSEQ;
|
||||
if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
|
||||
hsmmc_command_incomplete(host, -ETIMEDOUT);
|
||||
else if (status & (CMD_CRC | DATA_CRC))
|
||||
hsmmc_command_incomplete(host, -EILSEQ);
|
||||
|
||||
if (host->data)
|
||||
omap_hsmmc_dma_cleanup(host, err);
|
||||
else
|
||||
host->mrq->cmd->error = err;
|
||||
host->response_busy = 0;
|
||||
omap_hsmmc_reset_controller_fsm(host, SRD);
|
||||
end_trans = 1;
|
||||
}
|
||||
}
|
||||
if (status & CARD_ERR) {
|
||||
dev_dbg(mmc_dev(host->mmc),
|
||||
"Ignoring card err CMD%d\n", host->cmd->opcode);
|
||||
if (host->cmd)
|
||||
end_cmd = 1;
|
||||
if (host->data)
|
||||
end_trans = 1;
|
||||
end_cmd = 1;
|
||||
if (host->data || host->response_busy) {
|
||||
end_trans = 1;
|
||||
host->response_busy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
OMAP_HSMMC_WRITE(host->base, STAT, status);
|
||||
|
||||
if (end_cmd || ((status & CC) && host->cmd))
|
||||
omap_hsmmc_cmd_done(host, host->cmd);
|
||||
if ((end_trans || (status & TC)) && host->mrq)
|
||||
@@ -1062,11 +1012,13 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
|
||||
int status;
|
||||
|
||||
status = OMAP_HSMMC_READ(host->base, STAT);
|
||||
do {
|
||||
while (status & INT_EN_MASK && host->req_in_progress) {
|
||||
omap_hsmmc_do_irq(host, status);
|
||||
|
||||
/* Flush posted write */
|
||||
OMAP_HSMMC_WRITE(host->base, STAT, status);
|
||||
status = OMAP_HSMMC_READ(host->base, STAT);
|
||||
} while (status & INT_EN_MASK);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -1501,12 +1453,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
case MMC_POWER_OFF:
|
||||
mmc_slot(host).set_power(host->dev, host->slot_id,
|
||||
0, 0);
|
||||
host->vdd = 0;
|
||||
break;
|
||||
case MMC_POWER_UP:
|
||||
mmc_slot(host).set_power(host->dev, host->slot_id,
|
||||
1, ios->vdd);
|
||||
host->vdd = ios->vdd;
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
do_send_init_stream = 1;
|
||||
@@ -1598,10 +1548,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
|
||||
value = OMAP_HSMMC_READ(host->base, CAPA);
|
||||
OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
|
||||
|
||||
/* Set the controller to AUTO IDLE mode */
|
||||
value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
|
||||
OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
|
||||
|
||||
/* Set SD bus power bit */
|
||||
set_sd_bus_power(host);
|
||||
}
|
||||
@@ -1659,8 +1605,6 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
|
||||
seq_printf(s, "SYSCONFIG:\t0x%08x\n",
|
||||
OMAP_HSMMC_READ(host->base, SYSCONFIG));
|
||||
seq_printf(s, "CON:\t\t0x%08x\n",
|
||||
OMAP_HSMMC_READ(host->base, CON));
|
||||
seq_printf(s, "HCTL:\t\t0x%08x\n",
|
||||
@@ -2105,8 +2049,7 @@ static int omap_hsmmc_suspend(struct device *dev)
|
||||
if (ret) {
|
||||
host->suspended = 0;
|
||||
if (host->pdata->resume) {
|
||||
ret = host->pdata->resume(dev, host->slot_id);
|
||||
if (ret)
|
||||
if (host->pdata->resume(dev, host->slot_id))
|
||||
dev_dbg(dev, "Unmask interrupt failed\n");
|
||||
}
|
||||
goto err;
|
||||
|
新增問題並參考
封鎖使用者