summaryrefslogtreecommitdiff
path: root/drivers/mmc/core/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r--drivers/mmc/core/core.c154
1 files changed, 96 insertions, 58 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 57a2b40..bf18b6b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -23,7 +23,6 @@
#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>
@@ -302,7 +301,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, true);
+ EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
if (err) {
pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err);
@@ -919,6 +918,31 @@ 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
*
@@ -1358,31 +1382,22 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
int bit;
- /*
- * 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;
- }
-
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;
+ bit = ffs(ocr);
+ if (bit) {
+ bit -= 1;
+
ocr &= 3 << bit;
- mmc_power_cycle(host, ocr);
+
+ mmc_host_clk_hold(host);
+ host->ios.vdd = bit;
+ mmc_set_ios(host);
+ mmc_host_clk_release(host);
} else {
- bit = fls(ocr) - 1;
- ocr &= 3 << bit;
- if (bit != host->ios.vdd)
- dev_warn(mmc_dev(host), "exceeding card's volts\n");
+ pr_warning("%s: host doesn't support card's voltages\n",
+ mmc_hostname(host));
+ ocr = 0;
}
return ocr;
@@ -1407,7 +1422,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, u32 ocr)
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
{
struct mmc_command cmd = {0};
int err = 0;
@@ -1489,7 +1504,7 @@ power_cycle:
if (err) {
pr_debug("%s: Signal voltage switch failed, "
"power cycling card\n", mmc_hostname(host));
- mmc_power_cycle(host, ocr);
+ mmc_power_cycle(host);
}
mmc_host_clk_release(host);
@@ -1530,14 +1545,22 @@ 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, u32 ocr)
+void mmc_power_up(struct mmc_host *host)
{
+ int bit;
+
if (host->ios.power_mode == MMC_POWER_ON)
return;
mmc_host_clk_hold(host);
- host->ios.vdd = fls(ocr) - 1;
+ /* 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;
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else
@@ -1581,6 +1604,13 @@ 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;
@@ -1600,12 +1630,12 @@ void mmc_power_off(struct mmc_host *host)
mmc_host_clk_release(host);
}
-void mmc_power_cycle(struct mmc_host *host, u32 ocr)
+void mmc_power_cycle(struct mmc_host *host)
{
mmc_power_off(host);
/* Wait at least 1 ms according to SD spec */
mmc_delay(1);
- mmc_power_up(host, ocr);
+ mmc_power_up(host);
}
/*
@@ -1693,28 +1723,6 @@ 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.
@@ -1727,8 +1735,16 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
- _mmc_detect_change(host, delay, true);
+#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);
}
+
EXPORT_SYMBOL(mmc_detect_change);
void mmc_init_erase(struct mmc_card *card)
@@ -2318,7 +2334,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, host->ocr_avail);
+ mmc_power_up(host);
/*
* Some eMMCs (with VCCQ always on) may not be reset after power up, so
@@ -2407,7 +2423,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, false);
+ mmc_detect_change(host, 0);
}
}
@@ -2488,8 +2504,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, host->ocr_avail);
- _mmc_detect_change(host, 0, false);
+ mmc_power_up(host);
+ mmc_detect_change(host, 0);
}
void mmc_stop_host(struct mmc_host *host)
@@ -2567,7 +2583,7 @@ int mmc_power_restore_host(struct mmc_host *host)
return -EINVAL;
}
- mmc_power_up(host, host->card->ocr);
+ mmc_power_up(host);
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
@@ -2641,6 +2657,28 @@ 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.
@@ -2686,7 +2724,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, false);
+ mmc_detect_change(host, 0);
}