summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-18 14:47:30 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-18 14:47:30 -0800
commitc2ac2ae44d4c32382d001672021116e771bef4c9 (patch)
tree39a6ab0a118f562bb58ebc9e4c9cb709ac6ce29a /drivers/mmc
parent2d3c627502f2a9b0a7de06a5a2df2365542a72c9 (diff)
parente395c4387c746b4cc7aace4c44baecd7e69a3249 (diff)
Merge tag 'mmc-updates-for-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball: "MMC highlights for 3.13: Core: - Improve runtime PM support, remove mmc_{suspend,resume}_host(). - Add MMC_CAP_RUNTIME_RESUME, for delaying MMC resume until we're outside of the resume sequence (in runtime_resume) to decrease system resume time. Drivers: - dw_mmc: Support HS200 mode. - sdhci-eshdc-imx: Support SD3.0 SDR clock tuning, DDR on IMX6. - sdhci-pci: Add support for Intel Clovertrail and Merrifield" * tag 'mmc-updates-for-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (108 commits) mmc: wbsd: Silence compiler warning mmc: core: Silence compiler warning in __mmc_switch mmc: sh_mmcif: Convert to clk_prepare|unprepare mmc: sh_mmcif: Convert to PM macros when defining dev_pm_ops mmc: dw_mmc: exynos: Revert the sdr_timing assignment mmc: sdhci: Avoid needless loop while handling SDIO interrupts in sdhci_irq mmc: core: Add MMC_CAP_RUNTIME_RESUME to resume at runtime_resume mmc: core: Improve runtime PM support during suspend/resume for sd/mmc mmc: core: Remove redundant mmc_power_up|off at runtime callbacks mmc: Don't force card to active state when entering suspend/shutdown MIPS: db1235: Don't use MMC_CLKGATE mmc: core: Remove deprecated mmc_suspend|resume_host APIs mmc: mmci: Move away from using deprecated APIs mmc: via-sdmmc: Move away from using deprecated APIs mmc: tmio: Move away from using deprecated APIs mmc: sh_mmcif: Move away from using deprecated APIs mmc: sdricoh_cs: Move away from using deprecated APIs mmc: rtsx: Remove redundant suspend and resume callbacks mmc: wbsd: Move away from using deprecated APIs mmc: pxamci: Remove redundant suspend and resume callbacks ...
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/bus.c2
-rw-r--r--drivers/mmc/core/core.c154
-rw-r--r--drivers/mmc/core/core.h6
-rw-r--r--drivers/mmc/core/mmc.c127
-rw-r--r--drivers/mmc/core/mmc_ops.c96
-rw-r--r--drivers/mmc/core/sd.c118
-rw-r--r--drivers/mmc/core/sdio.c82
-rw-r--r--drivers/mmc/host/atmel-mci.c82
-rw-r--r--drivers/mmc/host/au1xmmc.c7
-rw-r--r--drivers/mmc/host/bfin_sdh.c15
-rw-r--r--drivers/mmc/host/cb710-mmc.c10
-rw-r--r--drivers/mmc/host/davinci_mmc.c26
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c291
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c7
-rw-r--r--drivers/mmc/host/dw_mmc-socfpga.c34
-rw-r--r--drivers/mmc/host/dw_mmc.c604
-rw-r--r--drivers/mmc/host/dw_mmc.h55
-rw-r--r--drivers/mmc/host/jz4740_mmc.c4
-rw-r--r--drivers/mmc/host/mmci.c17
-rw-r--r--drivers/mmc/host/msm_sdcc.c27
-rw-r--r--drivers/mmc/host/mvsdio.c35
-rw-r--r--drivers/mmc/host/mxcmmc.c12
-rw-r--r--drivers/mmc/host/mxs-mmc.c12
-rw-r--r--drivers/mmc/host/omap.c53
-rw-r--r--drivers/mmc/host/omap_hsmmc.c112
-rw-r--r--drivers/mmc/host/pxamci.c32
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c35
-rw-r--r--drivers/mmc/host/s3cmci.c29
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c14
-rw-r--r--drivers/mmc/host/sdhci-bcm2835.c8
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c550
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h37
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c35
-rw-r--r--drivers/mmc/host/sdhci-pci.c76
-rw-r--r--drivers/mmc/host/sdhci.c44
-rw-r--r--drivers/mmc/host/sdhci.h3
-rw-r--r--drivers/mmc/host/sdricoh_cs.c3
-rw-r--r--drivers/mmc/host/sh_mmcif.c32
-rw-r--r--drivers/mmc/host/tifm_sd.c4
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c9
-rw-r--r--drivers/mmc/host/via-sdmmc.c7
-rw-r--r--drivers/mmc/host/vub300.c18
-rw-r--r--drivers/mmc/host/wbsd.c34
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c57
45 files changed, 1786 insertions, 1231 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1a3163f1407e..29d5d988a51c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2448,7 +2448,6 @@ static int _mmc_blk_suspend(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
- pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue);
@@ -2483,7 +2482,6 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue);
}
- pm_runtime_put(&card->dev);
}
return 0;
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 3e227bd91e81..64145a32b917 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -342,7 +342,7 @@ int mmc_add_card(struct mmc_card *card)
break;
}
- if (mmc_sd_card_uhs(card) &&
+ if (mmc_card_uhs(card) &&
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bf18b6bfce48..57a2b403bf8e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -23,6 +23,7 @@
#include <linux/log2.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_wakeup.h>
#include <linux/suspend.h>
#include <linux/fault-inject.h>
#include <linux/random.h>
@@ -301,7 +302,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
}
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
+ EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
if (err) {
pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err);
@@ -918,31 +919,6 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
EXPORT_SYMBOL(__mmc_claim_host);
/**
- * mmc_try_claim_host - try exclusively to claim a host
- * @host: mmc host to claim
- *
- * Returns %1 if the host is claimed, %0 otherwise.
- */
-int mmc_try_claim_host(struct mmc_host *host)
-{
- int claimed_host = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (!host->claimed || host->claimer == current) {
- host->claimed = 1;
- host->claimer = current;
- host->claim_cnt += 1;
- claimed_host = 1;
- }
- spin_unlock_irqrestore(&host->lock, flags);
- if (host->ops->enable && claimed_host && host->claim_cnt == 1)
- host->ops->enable(host);
- return claimed_host;
-}
-EXPORT_SYMBOL(mmc_try_claim_host);
-
-/**
* mmc_release_host - release a host
* @host: mmc host to release
*
@@ -1382,22 +1358,31 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
int bit;
- ocr &= host->ocr_avail;
+ /*
+ * Sanity check the voltages that the card claims to
+ * support.
+ */
+ if (ocr & 0x7F) {
+ dev_warn(mmc_dev(host),
+ "card claims to support voltages below defined range\n");
+ ocr &= ~0x7F;
+ }
- bit = ffs(ocr);
- if (bit) {
- bit -= 1;
+ ocr &= host->ocr_avail;
+ if (!ocr) {
+ dev_warn(mmc_dev(host), "no support for card's volts\n");
+ return 0;
+ }
+ if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
+ bit = ffs(ocr) - 1;
ocr &= 3 << bit;
-
- mmc_host_clk_hold(host);
- host->ios.vdd = bit;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
+ mmc_power_cycle(host, ocr);
} else {
- pr_warning("%s: host doesn't support card's voltages\n",
- mmc_hostname(host));
- ocr = 0;
+ bit = fls(ocr) - 1;
+ ocr &= 3 << bit;
+ if (bit != host->ios.vdd)
+ dev_warn(mmc_dev(host), "exceeding card's volts\n");
}
return ocr;
@@ -1422,7 +1407,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
}
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
{
struct mmc_command cmd = {0};
int err = 0;
@@ -1504,7 +1489,7 @@ power_cycle:
if (err) {
pr_debug("%s: Signal voltage switch failed, "
"power cycling card\n", mmc_hostname(host));
- mmc_power_cycle(host);
+ mmc_power_cycle(host, ocr);
}
mmc_host_clk_release(host);
@@ -1545,22 +1530,14 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
* If a host does all the power sequencing itself, ignore the
* initial MMC_POWER_UP stage.
*/
-void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host, u32 ocr)
{
- int bit;
-
if (host->ios.power_mode == MMC_POWER_ON)
return;
mmc_host_clk_hold(host);
- /* If ocr is set, we use it */
- if (host->ocr)
- bit = ffs(host->ocr) - 1;
- else
- bit = fls(host->ocr_avail) - 1;
-
- host->ios.vdd = bit;
+ host->ios.vdd = fls(ocr) - 1;
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else
@@ -1604,13 +1581,6 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0;
host->ios.vdd = 0;
-
- /*
- * Reset ocr mask to be the highest possible voltage supported for
- * this mmc host. This value will be used at next power up.
- */
- host->ocr = 1 << (fls(host->ocr_avail) - 1);
-
if (!mmc_host_is_spi(host)) {
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
@@ -1630,12 +1600,12 @@ void mmc_power_off(struct mmc_host *host)
mmc_host_clk_release(host);
}
-void mmc_power_cycle(struct mmc_host *host)
+void mmc_power_cycle(struct mmc_host *host, u32 ocr)
{
mmc_power_off(host);
/* Wait at least 1 ms according to SD spec */
mmc_delay(1);
- mmc_power_up(host);
+ mmc_power_up(host, ocr);
}
/*
@@ -1723,6 +1693,28 @@ void mmc_detach_bus(struct mmc_host *host)
mmc_bus_put(host);
}
+static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
+ bool cd_irq)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+ WARN_ON(host->removed);
+ spin_unlock_irqrestore(&host->lock, flags);
+#endif
+
+ /*
+ * If the device is configured as wakeup, we prevent a new sleep for
+ * 5 s to give provision for user space to consume the event.
+ */
+ if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
+ device_can_wakeup(mmc_dev(host)))
+ pm_wakeup_event(mmc_dev(host), 5000);
+
+ host->detect_change = 1;
+ mmc_schedule_delayed_work(&host->detect, delay);
+}
+
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
@@ -1735,16 +1727,8 @@ void mmc_detach_bus(struct mmc_host *host)
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
- WARN_ON(host->removed);
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
- host->detect_change = 1;
- mmc_schedule_delayed_work(&host->detect, delay);
+ _mmc_detect_change(host, delay, true);
}
-
EXPORT_SYMBOL(mmc_detect_change);
void mmc_init_erase(struct mmc_card *card)
@@ -2334,7 +2318,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
- mmc_power_up(host);
+ mmc_power_up(host, host->ocr_avail);
/*
* Some eMMCs (with VCCQ always on) may not be reset after power up, so
@@ -2423,7 +2407,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
* rescan handle the card removal.
*/
cancel_delayed_work(&host->detect);
- mmc_detect_change(host, 0);
+ _mmc_detect_change(host, 0, false);
}
}
@@ -2504,8 +2488,8 @@ void mmc_start_host(struct mmc_host *host)
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host);
else
- mmc_power_up(host);
- mmc_detect_change(host, 0);
+ mmc_power_up(host, host->ocr_avail);
+ _mmc_detect_change(host, 0, false);
}
void mmc_stop_host(struct mmc_host *host)
@@ -2583,7 +2567,7 @@ int mmc_power_restore_host(struct mmc_host *host)
return -EINVAL;
}
- mmc_power_up(host);
+ mmc_power_up(host, host->card->ocr);
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
@@ -2657,28 +2641,6 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
#ifdef CONFIG_PM
-/**
- * mmc_suspend_host - suspend a host
- * @host: mmc host
- */
-int mmc_suspend_host(struct mmc_host *host)
-{
- /* This function is deprecated */
- return 0;
-}
-EXPORT_SYMBOL(mmc_suspend_host);
-
-/**
- * mmc_resume_host - resume a previously suspended host
- * @host: mmc host
- */
-int mmc_resume_host(struct mmc_host *host)
-{
- /* This function is deprecated */
- return 0;
-}
-EXPORT_SYMBOL(mmc_resume_host);
-
/* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
to sync the card.
@@ -2724,7 +2686,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
spin_unlock_irqrestore(&host->lock, flags);
- mmc_detect_change(host, 0);
+ _mmc_detect_change(host, 0, false);
}
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 5345d156493e..443a584660f0 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -42,13 +42,13 @@ void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr);
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
-void mmc_power_up(struct mmc_host *host);
+void mmc_power_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host);
-void mmc_power_cycle(struct mmc_host *host);
+void mmc_power_cycle(struct mmc_host *host, u32 ocr);
static inline void mmc_delay(unsigned int ms)
{
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6d02012a1d0b..f631f5a9bf79 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -934,6 +935,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto err;
}
+ card->ocr = ocr;
card->type = MMC_TYPE_MMC;
card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
@@ -1404,9 +1406,9 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
if (notify_type == EXT_CSD_POWER_OFF_LONG)
timeout = card->ext_csd.power_off_longtime;
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_POWER_OFF_NOTIFICATION,
- notify_type, timeout);
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_OFF_NOTIFICATION,
+ notify_type, timeout, true, false);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
@@ -1477,6 +1479,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
mmc_claim_host(host);
+ if (mmc_card_suspended(host->card))
+ goto out;
+
if (mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card);
if (err)
@@ -1496,51 +1501,93 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
- if (!err)
+ if (!err) {
mmc_power_off(host);
+ mmc_card_set_suspended(host->card);
+ }
out:
mmc_release_host(host);
return err;
}
/*
- * Suspend callback from host.
+ * Suspend callback
*/
static int mmc_suspend(struct mmc_host *host)
{
- return _mmc_suspend(host, true);
-}
+ int err;
-/*
- * Shutdown callback
- */
-static int mmc_shutdown(struct mmc_host *host)
-{
- return _mmc_suspend(host, false);
+ err = _mmc_suspend(host, true);
+ if (!err) {
+ pm_runtime_disable(&host->card->dev);
+ pm_runtime_set_suspended(&host->card->dev);
+ }
+
+ return err;
}
/*
- * Resume callback from host.
- *
* This function tries to determine if the same card is still present
* and, if so, restore all state to it.
*/
-static int mmc_resume(struct mmc_host *host)
+static int _mmc_resume(struct mmc_host *host)
{
- int err;
+ int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
- err = mmc_init_card(host, host->ocr, host->card);
+
+ if (!mmc_card_suspended(host->card))
+ goto out;
+
+ mmc_power_up(host, host->card->ocr);
+ err = mmc_init_card(host, host->card->ocr, host->card);
+ mmc_card_clr_suspended(host->card);
+
+out:
mmc_release_host(host);
+ return err;
+}
+
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+ int err = 0;
+
+ /*
+ * In a specific case for poweroff notify, we need to resume the card
+ * before we can shutdown it properly.
+ */
+ if (mmc_can_poweroff_notify(host->card) &&
+ !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
+ err = _mmc_resume(host);
+
+ if (!err)
+ err = _mmc_suspend(host, false);
return err;
}
+/*
+ * Callback for resume.
+ */
+static int mmc_resume(struct mmc_host *host)
+{
+ int err = 0;
+
+ if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
+ err = _mmc_resume(host);
+ pm_runtime_set_active(&host->card->dev);
+ pm_runtime_mark_last_busy(&host->card->dev);
+ }
+ pm_runtime_enable(&host->card->dev);
+
+ return err;
+}
/*
* Callback for runtime_suspend.
@@ -1552,18 +1599,11 @@ static int mmc_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- mmc_claim_host(host);
-
- err = mmc_suspend(host);
- if (err) {
+ err = _mmc_suspend(host, true);
+ if (err)
pr_err("%s: error %d doing aggessive suspend\n",
mmc_hostname(host), err);
- goto out;
- }
- mmc_power_off(host);
-out:
- mmc_release_host(host);
return err;
}
@@ -1574,18 +1614,14 @@ static int mmc_runtime_resume(struct mmc_host *host)
{
int err;
- if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
return 0;
- mmc_claim_host(host);
-
- mmc_power_up(host);
- err = mmc_resume(host);
+ err = _mmc_resume(host);
if (err)
pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err);
- mmc_release_host(host);
return 0;
}
@@ -1595,7 +1631,7 @@ static int mmc_power_restore(struct mmc_host *host)
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host);
- ret = mmc_init_card(host, host->ocr, host->card);
+ ret = mmc_init_card(host, host->card->ocr, host->card);
mmc_release_host(host);
return ret;
@@ -1640,7 +1676,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
int mmc_attach_mmc(struct mmc_host *host)
{
int err;
- u32 ocr;
+ u32 ocr, rocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -1666,23 +1702,12 @@ int mmc_attach_mmc(struct mmc_host *host)
goto err;
}
- /*
- * Sanity check the voltages that the card claims to
- * support.
- */
- if (ocr & 0x7F) {
- pr_warning("%s: card claims to support voltages "
- "below the defined range. These will be ignored.\n",
- mmc_hostname(host));
- ocr &= ~0x7F;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
+ rocr = mmc_select_voltage(host, ocr);
/*
* Can we support the voltage of the card?
*/
- if (!host->ocr) {
+ if (!rocr) {
err = -EINVAL;
goto err;
}
@@ -1690,7 +1715,7 @@ int mmc_attach_mmc(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_init_card(host, host->ocr, NULL);
+ err = mmc_init_card(host, rocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index ef183483d5b6..e5b5eeb548d1 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -23,6 +23,40 @@
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
+ bool ignore_crc)
+{
+ int err;
+ struct mmc_command cmd = {0};
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ cmd.opcode = MMC_SEND_STATUS;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ if (ignore_crc)
+ cmd.flags &= ~MMC_RSP_CRC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ return err;
+
+ /* NOTE: callers are required to understand the difference
+ * between "native" and SPI format status words!
+ */
+ if (status)
+ *status = cmd.resp[0];
+
+ return 0;
+}
+
+int mmc_send_status(struct mmc_card *card, u32 *status)
+{
+ return __mmc_send_status(card, status, false);
+}
+
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@@ -370,16 +404,18 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
* @use_busy_signal: use the busy signal as response type
+ * @send_status: send status cmd to poll for busy
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms, bool use_busy_signal)
+ unsigned int timeout_ms, bool use_busy_signal, bool send_status)
{
int err;
struct mmc_command cmd = {0};
unsigned long timeout;
- u32 status;
+ u32 status = 0;
+ bool ignore_crc = false;
BUG_ON(!card);
BUG_ON(!card->host);
@@ -408,17 +444,37 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (!use_busy_signal)
return 0;
- /* Must check status to be sure of no errors */
+ /*
+ * Must check status to be sure of no errors
+ * If CMD13 is to check the busy completion of the timing change,
+ * disable the check of CRC error.
+ */
+ if (index == EXT_CSD_HS_TIMING &&
+ !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ ignore_crc = true;
+
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
- err = mmc_send_status(card, &status);
- if (err)
- return err;
+ if (send_status) {
+ err = __mmc_send_status(card, &status, ignore_crc);
+ if (err)
+ return err;
+ }
if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
break;
if (mmc_host_is_spi(card->host))
break;
+ /*
+ * We are not allowed to issue a status command and the host
+ * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
+ * rely on waiting for the stated timeout to be sufficient.
+ */
+ if (!send_status) {
+ mmc_delay(timeout_ms);
+ return 0;
+ }
+
/* Timeout if the device never leaves the program state. */
if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state! %s\n",
@@ -445,36 +501,10 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
- return __mmc_switch(card, set, index, value, timeout_ms, true);
+ return __mmc_switch(card, set, index, value, timeout_ms, true, true);
}
EXPORT_SYMBOL_GPL(mmc_switch);
-int mmc_send_status(struct mmc_card *card, u32 *status)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;