diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2013-05-15 20:53:22 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-05-23 00:09:16 +0100 |
commit | 0125962000777cd1e2ce53deefb99779d5ee5199 (patch) | |
tree | a7c3a3c8d7e53391b9b02362407919c7f11045aa /drivers/mmc/host/mmci.c | |
parent | 9cc639a20fdc0b935e55d4992f93963f95233ca4 (diff) |
ARM: 7726/1: mmc: mmci: Add card_busy function to improve UHS card support
To verify a signal voltage switch at initialization of UHS cards the
.card_busy callback is used. For some of the ST-variants, card busy
detection on the DAT0 pin is supported.
We extend the variant struct with a busy_detect flag to indicate
support for it. A corresponding busy detect function, which polls the
busy status bit, is then set to the .card_busy callback.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r-- | drivers/mmc/host/mmci.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ccfe0bc62f78..c3785edc0e92 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -61,6 +61,7 @@ static unsigned int fmax = 515633; * @pwrreg_powerup: power up value for MMCIPOWER register * @signal_direction: input/out direction of bus signals can be indicated * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock + * @busy_detect: true if busy detection on dat0 is supported */ struct variant_data { unsigned int clkreg; @@ -74,6 +75,7 @@ struct variant_data { u32 pwrreg_powerup; bool signal_direction; bool pwrreg_clkgate; + bool busy_detect; }; static struct variant_data variant_arm = { @@ -132,6 +134,7 @@ static struct variant_data variant_ux500 = { .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, .pwrreg_clkgate = true, + .busy_detect = true, }; static struct variant_data variant_ux500v2 = { @@ -146,8 +149,28 @@ static struct variant_data variant_ux500v2 = { .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, .pwrreg_clkgate = true, + .busy_detect = true, }; +static int mmci_card_busy(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned long flags; + int busy = 0; + + pm_runtime_get_sync(mmc_dev(mmc)); + + spin_lock_irqsave(&host->lock, flags); + if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY) + busy = 1; + spin_unlock_irqrestore(&host->lock, flags); + + pm_runtime_mark_last_busy(mmc_dev(mmc)); + pm_runtime_put_autosuspend(mmc_dev(mmc)); + + return busy; +} + /* * Validate mmc prerequisites */ @@ -193,6 +216,9 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) */ static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) { + /* Keep ST Micro busy mode if enabled */ + datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE; + if (host->datactrl_reg != datactrl) { host->datactrl_reg = datactrl; writel(datactrl, host->base + MMCIDATACTRL); @@ -1319,7 +1345,7 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static const struct mmc_host_ops mmci_ops = { +static struct mmc_host_ops mmci_ops = { .request = mmci_request, .pre_req = mmci_pre_request, .post_req = mmci_post_request, @@ -1455,6 +1481,11 @@ static int mmci_probe(struct amba_device *dev, goto clk_disable; } + if (variant->busy_detect) { + mmci_ops.card_busy = mmci_card_busy; + mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE); + } + mmc->ops = &mmci_ops; /* * The ARM and ST versions of the block have slightly different |