summaryrefslogtreecommitdiff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/mmc/core
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/bus.c14
-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/core/sdio_bus.c24
8 files changed, 310 insertions, 311 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 64145a3..704bf66 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -27,7 +27,7 @@
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
-static ssize_t type_show(struct device *dev,
+static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
@@ -45,13 +45,11 @@ static ssize_t type_show(struct device *dev,
return -EFAULT;
}
}
-static DEVICE_ATTR_RO(type);
-static struct attribute *mmc_dev_attrs[] = {
- &dev_attr_type.attr,
- NULL,
+static struct device_attribute mmc_dev_attrs[] = {
+ __ATTR(type, S_IRUGO, mmc_type_show, NULL),
+ __ATTR_NULL,
};
-ATTRIBUTE_GROUPS(mmc_dev);
/*
* This currently matches any MMC driver to any MMC card - drivers
@@ -220,7 +218,7 @@ static const struct dev_pm_ops mmc_bus_pm_ops = {
static struct bus_type mmc_bus_type = {
.name = "mmc",
- .dev_groups = mmc_dev_groups,
+ .dev_attrs = mmc_dev_attrs,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
@@ -342,7 +340,7 @@ int mmc_add_card(struct mmc_card *card)
break;
}
- if (mmc_card_uhs(card) &&
+ if (mmc_sd_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 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);
}
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 443a584..5345d15 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, 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);
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, u32 ocr);
+void mmc_power_up(struct mmc_host *host);
void mmc_power_off(struct mmc_host *host);
-void mmc_power_cycle(struct mmc_host *host, u32 ocr);
+void mmc_power_cycle(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f631f5a..6d02012 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -13,7 +13,6 @@
#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>
@@ -935,7 +934,6 @@ 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));
@@ -1406,9 +1404,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, true, false);
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_OFF_NOTIFICATION,
+ notify_type, timeout);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
@@ -1479,9 +1477,6 @@ 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)
@@ -1501,93 +1496,51 @@ 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
+ * Suspend callback from host.
*/
static int mmc_suspend(struct mmc_host *host)
{
- int err;
-
- err = _mmc_suspend(host, true);
- if (!err) {
- pm_runtime_disable(&host->card->dev);
- pm_runtime_set_suspended(&host->card->dev);
- }
+ return _mmc_suspend(host, true);
+}
- return err;
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+ return _mmc_suspend(host, false);
}
/*
+ * 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 = 0;
+ int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
-
- 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_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ err = mmc_init_card(host, host->ocr, host->card);
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.
@@ -1599,11 +1552,18 @@ static int mmc_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- err = _mmc_suspend(host, true);
- if (err)
+ mmc_claim_host(host);
+
+ err = mmc_suspend(host);
+ 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;
}
@@ -1614,14 +1574,18 @@ static int mmc_runtime_resume(struct mmc_host *host)
{
int err;
- if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- err = _mmc_resume(host);
+ mmc_claim_host(host);
+
+ mmc_power_up(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;
}
@@ -1631,7 +1595,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->card->ocr, host->card);
+ ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return ret;
@@ -1676,7 +1640,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
int mmc_attach_mmc(struct mmc_host *host)
{
int err;
- u32 ocr, rocr;
+ u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -1702,12 +1666,23 @@ int mmc_attach_mmc(struct mmc_host *host)
goto err;
}
- rocr = mmc_select_voltage(host, ocr);
+ /*
+ * 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);
/*
* Can we support the voltage of the card?
*/
- if (!rocr) {
+ if (!host->ocr) {
err = -EINVAL;
goto err;
}
@@ -1715,7 +1690,7 @@ int mmc_attach_mmc(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_init_card(host, rocr, NULL);
+ err = mmc_init_card(host, host->ocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index e5b5eeb..ef18348 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -23,40 +23,6 @@
#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;
@@ -404,18 +370,16 @@ 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, bool send_status)
+ unsigned int timeout_ms, bool use_busy_signal)
{
int err;
struct mmc_command cmd = {0};
unsigned long timeout;
- u32 status = 0;
- bool ignore_crc = false;
+ u32 status;
BUG_ON(!card);
BUG_ON(!card->host);
@@ -444,37 +408,17 @@ 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
- * 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;
-
+ /* Must check status to be sure of no errors */
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
- if (send_status) {
- err = __mmc_send_status(card, &status, ignore_crc);
- if (err)
- return err;
- }
+ err = mmc_send_status(card, &status);
+ 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",
@@ -501,10 +445,36 @@ 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, true);
+ return __mmc_switch(card, set, index, value, timeout_ms, 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;
+
+ 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;
+}
+
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6f42050..5e8823d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -13,7 +13,6 @@
#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>
@@ -722,7 +721,6 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
int err;
u32 max_current;
int retries = 10;
- u32 pocr = ocr;
try_again:
if (!retries) {
@@ -775,8 +773,7 @@ try_again:
*/
if (!mmc_host_is_spi(host) && rocr &&
((*rocr & 0x41000000) == 0x41000000)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- pocr);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
if (err == -EAGAIN) {
retries--;
goto try_again;
@@ -938,7 +935,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (IS_ERR(card))
return PTR_ERR(card);
- card->ocr = ocr;
card->type = MMC_TYPE_SD;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
@@ -1068,7 +1064,10 @@ static void mmc_sd_detect(struct mmc_host *host)
}
}
-static int _mmc_sd_suspend(struct mmc_host *host)
+/*
+ * Suspend callback from host.
+ */
+static int mmc_sd_suspend(struct mmc_host *host)
{
int err = 0;
@@ -1076,77 +1075,34 @@ static int _mmc_sd_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
-
- if (mmc_card_suspended(host->card))
- goto out;
-
if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
- if (!err) {
+ if (!err)
mmc_power_off(host);
- mmc_card_set_suspended(host->card);
- }
-
-out:
mmc_release_host(host);
- return err;
-}
-
-/*
- * Callback for suspend
- */
-static int mmc_sd_suspend(struct mmc_host *host)
-{
- int err;
-
- err = _mmc_sd_suspend(host);
- 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_sd_resume(struct mmc_host *host)
+static int mmc_sd_resume(struct mmc_host *host)
{
- int err = 0;
+ int err;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
-
- if (!mmc_card_suspended(host->card))
- goto out;
-
- mmc_power_up(host, host->card->ocr);
- err = mmc_sd_init_card(host, host->card->ocr, host->card);
- mmc_card_clr_suspended(host->card);
-
-out:
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- return err;
-}
-
-/*
- * Callback for resume
- */
-static int mmc_sd_resume(struct mmc_host *host)
-{
- int err = 0;
-
- if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
- err = _mmc_sd_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;
}
@@ -1161,11 +1117,18 @@ static int mmc_sd_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- err = _mmc_sd_suspend(host);
- if (err)
+ mmc_claim_host(host);
+
+ err = mmc_sd_suspend(host);
+ 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;
}
@@ -1176,14 +1139,18 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
{
int err;
- if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- err = _mmc_sd_resume(host);
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ err = mmc_sd_resume(host);
if (err)
pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err);
+ mmc_release_host(host);
return 0;
}
@@ -1193,7 +1160,7 @@ static int mmc_sd_power_restore(struct mmc_host *host)
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
- ret = mmc_sd_init_card(host, host->card->ocr, host->card);
+ ret = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return ret;
@@ -1238,7 +1205,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
int mmc_attach_sd(struct mmc_host *host)
{
int err;
- u32 ocr, rocr;
+ u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -1262,12 +1229,31 @@ int mmc_attach_sd(struct mmc_host *host)
goto err;
}
- rocr = mmc_select_voltage(host, ocr);
+ /*
+ * 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;
+ }
+
+ if ((ocr & MMC_VDD_165_195) &&
+ !(host->ocr_avail_sd & MMC_VDD_165_195)) {
+ pr_warning("%s: SD card claims to support the "
+ "incompletely defined 'low voltage range'. This "
+ "will be ignored.\n", mmc_hostname(host));
+ ocr &= ~MMC_VDD_165_195;
+ }
+
+ host->ocr = mmc_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
- if (!rocr) {
+ if (!host->ocr) {
err = -EINVAL;
goto err;
}
@@ -1275,7 +1261,7 @@ int mmc_attach_sd(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_sd_init_card(host, rocr, NULL);
+ err = mmc_sd_init_card(host, host->ocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4d721c6..80d89cff 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -593,28 +593,23 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *card;
int err;
int retries = 10;
- u32 rocr = 0;
- u32 ocr_card = ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
- /* to query card if 1.8V signalling is supported */
- if (mmc_host_uhs(host))
- ocr |= R4_18V_PRESENT;
-
try_again:
if (!retries) {
pr_warning("%s: Skipping voltage switch\n",
mmc_hostname(host));
ocr &= ~R4_18V_PRESENT;
+ host->ocr &= ~R4_18V_PRESENT;
}
/*
* Inform the card of the voltage
*/
if (!powered_resume) {
- err = mmc_send_io_op_cond(host, ocr, &rocr);
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
if (err)
goto err;
}
@@ -637,8 +632,8 @@ try_again:
goto err;
}
- if ((rocr & R4_MEMORY_PRESENT) &&
- mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
+ if ((ocr & R4_MEMORY_PRESENT) &&
+ mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO;
if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
@@ -668,9 +663,8 @@ try_again:
* systems that claim 1.8v signalling in fact do not support
* it.
*/
- if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- ocr);
+ if (!powered_resume && (ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
if (err == -EAGAIN) {
sdio_reset(host);
mmc_go_idle(host);
@@ -680,10 +674,12 @@ try_again:
goto try_again;
} else if (err) {
ocr &= ~R4_18V_PRESENT;
+ host->ocr &= ~R4_18V_PRESENT;
}
err = 0;
} else {
ocr &= ~R4_18V_PRESENT;
+ host->ocr &= ~R4_18V_PRESENT;
}
/*
@@ -763,7 +759,6 @@ try_again:
card = oldcard;
}
- card->ocr = ocr_card;
mmc_fixup_device(card, NULL);
if (card->type == MMC_TYPE_SD_COMBO) {
@@ -986,7 +981,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Restore power if needed */
if (!mmc_card_keep_power(host)) {
- mmc_power_up(host, host->card->ocr);
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
/*
* Tell runtime PM core we just powered up the card,
* since it still believes the card is powered off.
@@ -1004,7 +1000,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host);
mmc_go_idle(host);
- err = mmc_sdio_init_card(host, host->card->ocr, host->card,
+ err = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
@@ -1044,6 +1040,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
static int mmc_sdio_power_restore(struct mmc_host *host)
{
int ret;
+ u32 ocr;
BUG_ON(!host);
BUG_ON(!host->card);
@@ -1065,17 +1062,32 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
* for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
* harmless in other situations.
*
+ * With these steps taken, mmc_select_voltage() is also required to
+ * restore the correct voltage setting of the card.
*/
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
- ret = mmc_send_io_op_cond(host, 0, NULL);
+ ret = mmc_send_io_op_cond(host, 0, &ocr);
if (ret)
goto out;
- ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
+ if (host->ocr_avail_sdio)
+ host->ocr_avail = host->ocr_avail_sdio;
+
+ host->ocr = mmc_select_voltage(host, ocr & ~0x7F);
+ if (!host->ocr) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+
+ ret = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
if (!ret && host->sdio_irqs)
mmc_signal_sdio_irq(host);
@@ -1096,7 +1108,7 @@ static int mmc_sdio_runtime_suspend(struct mmc_host *host)
static int mmc_sdio_runtime_resume(struct mmc_host *host)
{
/* Restore power and re-initialize. */
- mmc_power_up(host, host->card->ocr);
+ mmc_power_up(host);
return mmc_sdio_power_restore(host);
}
@@ -1119,7 +1131,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
int mmc_attach_sdio(struct mmc_host *host)
{
int err, i, funcs;
- u32 ocr, rocr;
+ u32 ocr;
struct mmc_card *card;
BUG_ON(!host);
@@ -1133,13 +1145,23 @@ int mmc_attach_sdio(struct mmc_host *host)
if (host->ocr_avail_sdio)
host->ocr_avail = host->ocr_avail_sdio;
+ /*
+ * 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;
+ }
- rocr = mmc_select_voltage(host, ocr);
+ host->ocr = mmc_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
- if (!rocr) {
+ if (!host->ocr) {
err = -EINVAL;
goto err;
}
@@ -1147,10 +1169,22 @@ int mmc_attach_sdio(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, rocr, NULL, 0);
- if (err)
- goto err;
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+ err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
+ if (err) {
+ if (err == -EAGAIN) {
+ /*
+ * Retry initialization with S18R set to 0.
+ */
+ host->ocr &= ~R4_18V_PRESENT;
+ err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
+ }
+ if (err)
+ goto err;
+ }
card = host->card;
/*
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 157b570..6d67492 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -34,8 +34,7 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
\
func = dev_to_sdio_func (dev); \
return sprintf (buf, format_string, func->field); \
-} \
-static DEVICE_ATTR_RO(field)
+}
sdio_config_attr(class, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
@@ -48,16 +47,14 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
func->class, func->vendor, func->device);
}
-static DEVICE_ATTR_RO(modalias);
-
-static struct attribute *sdio_dev_attrs[] = {
- &dev_attr_class.attr,
- &dev_attr_vendor.attr,
- &dev_attr_device.attr,
- &dev_attr_modalias.attr,
- NULL,
+
+static struct device_attribute sdio_dev_attrs[] = {
+ __ATTR_RO(class),
+ __ATTR_RO(vendor),
+ __ATTR_RO(device),
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
};
-ATTRIBUTE_GROUPS(sdio_dev);
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
const struct sdio_device_id *id)
@@ -228,7 +225,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
static struct bus_type sdio_bus_type = {
.name = "sdio",
- .dev_groups = sdio_dev_groups,
+ .dev_attrs = sdio_dev_attrs,
.match = sdio_bus_match,
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
@@ -308,7 +305,8 @@ static void sdio_acpi_set_handle(struct sdio_func *func)
struct mmc_host *host = func->card->host;
u64 addr = (host->slotno << 16) | func->num;
- acpi_preset_companion(&func->dev, ACPI_HANDLE(host->parent), addr);
+ ACPI_HANDLE_SET(&func->dev,
+ acpi_get_child(ACPI_HANDLE(host->parent), addr));
}
#else
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}