summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-08 01:00:49 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-08 19:58:35 (GMT)
commit47d2261a3fa71cde24263559a4219a25e50d8c89 (patch)
tree28774d5b330ccf1b777a3af222d8356918328013 /drivers/mmc
parentfb7f27080adc65cd5f341bdf56a1d0c14f316c1b (diff)
parent5fb9d37f27351e42f002e372074249f92cbdf815 (diff)
downloadlinux-fsl-qoriq-47d2261a3fa71cde24263559a4219a25e50d8c89.tar.xz
Merge branch 'merge' into sdk-v1.6.x
This reverts v3.13-rc3+ (78fd82238d0e5716) to v3.12, except for commits which I noticed which appear relevant to the SDK. Signed-off-by: Scott Wood <scottwood@freescale.com> Conflicts: arch/powerpc/include/asm/kvm_host.h arch/powerpc/kvm/book3s_hv_rmhandlers.S arch/powerpc/kvm/book3s_interrupts.S arch/powerpc/kvm/e500.c arch/powerpc/kvm/e500mc.c arch/powerpc/sysdev/fsl_soc.h drivers/Kconfig drivers/cpufreq/ppc-corenet-cpufreq.c drivers/dma/fsldma.c drivers/dma/s3c24xx-dma.c drivers/misc/Makefile drivers/mmc/host/sdhci-of-esdhc.c drivers/mtd/devices/m25p80.c drivers/net/ethernet/freescale/gianfar.h drivers/platform/Kconfig drivers/platform/Makefile drivers/spi/spi-fsl-espi.c include/crypto/algapi.h include/linux/netdev_features.h include/linux/skbuff.h include/net/ip.h net/core/ethtool.c
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/card/queue.c3
-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
-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.c95
-rw-r--r--drivers/mmc/host/mmci.h4
-rw-r--r--drivers/mmc/host/msm_sdcc.c27
-rw-r--r--drivers/mmc/host/mvsdio.c46
-rw-r--r--drivers/mmc/host/mxcmmc.c12
-rw-r--r--drivers/mmc/host/mxs-mmc.c12
-rw-r--r--drivers/mmc/host/omap.c94
-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-acpi.c5
-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.h54
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c50
-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
49 files changed, 1314 insertions, 1913 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8eb28c0..f70f3e4 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2521,6 +2521,7 @@ 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);
@@ -2555,6 +2556,7 @@ 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/card/queue.c b/drivers/mmc/card/queue.c
index 50fb07e..b0f6bfd 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -15,7 +15,6 @@
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -201,7 +200,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+ limit = *mmc_dev(host)->dma_mask;
mq->card = card;
mq->queue = blk_init_queue(mmc_request_fn, lock);
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 4ecaac7..59cf22a 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);
@@ -931,6 +930,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
*
@@ -1370,31 +1394,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;
@@ -1419,7 +1434,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;
@@ -1501,7 +1516,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);
@@ -1542,14 +1557,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
@@ -1593,6 +1616,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;
@@ -1612,12 +1642,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);
}
/*
@@ -1705,28 +1735,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.
@@ -1739,8 +1747,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)
@@ -2335,7 +2351,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
@@ -2429,7 +2445,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work(&host->detect);
- _mmc_detect_change(host, 0, false);
+ mmc_detect_change(host, 0);
}
}
@@ -2510,8 +2526,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)
@@ -2589,7 +2605,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);
@@ -2663,6 +2679,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.
@@ -2708,7 +2746,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) {}
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 2cbb451..69e438e 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -255,6 +255,7 @@ struct atmel_mci_slot {
#define ATMCI_CARD_PRESENT 0
#define ATMCI_CARD_NEED_INIT 1
#define ATMCI_SHUTDOWN 2
+#define ATMCI_SUSPENDED 3
int detect_pin;
int wp_pin;
@@ -588,13 +589,6 @@ static void atmci_timeout_timer(unsigned long data)
if (host->mrq->cmd->data) {
host->mrq->cmd->data->error = -ETIMEDOUT;
host->data = NULL;
- /*
- * With some SDIO modules, sometimes DMA transfer hangs. If
- * stop_transfer() is not called then the DMA request is not
- * removed, following ones are queued and never computed.
- */
- if (host->state == STATE_DATA_XFER)
- host->stop_transfer(host);
} else {
host->mrq->cmd->error = -ETIMEDOUT;
host->cmd = NULL;
@@ -1809,14 +1803,12 @@ static void atmci_tasklet_func(unsigned long priv)
if (unlikely(status)) {
host->stop_transfer(host);
host->data = NULL;
- if (data) {
- if (status & ATMCI_DTOE) {
- data->error = -ETIMEDOUT;
- } else if (status & ATMCI_DCRCE) {
- data->error = -EILSEQ;
- } else {
- data->error = -EIO;
- }
+ if (status & ATMCI_DTOE) {
+ data->error = -ETIMEDOUT;
+ } else if (status & ATMCI_DCRCE) {
+ data->error = -EILSEQ;
+ } else {
+ data->error = -EIO;
}
}
@@ -2528,10 +2520,70 @@ static int __exit atmci_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int atmci_suspend(struct device *dev)
+{
+ struct atmel_mci *host = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+ struct atmel_mci_slot *slot = host->slot[i];
+ int ret;
+
+ if (!slot)
+ continue;
+ ret = mmc_suspend_host(slot->mmc);
+ if (ret < 0) {
+ while (--i >= 0) {
+ slot = host->slot[i];
+ if (slot
+ && test_bit(ATMCI_SUSPENDED, &slot->flags)) {
+ mmc_resume_host(host->slot[i]->mmc);
+ clear_bit(ATMCI_SUSPENDED, &slot->flags);
+ }
+ }
+ return ret;
+ } else {
+ set_bit(ATMCI_SUSPENDED, &slot->flags);
+ }
+ }
+
+ return 0;
+}
+
+static int atmci_resume(struct device *dev)
+{
+ struct atmel_mci *host = dev_get_drvdata(dev);
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+ struct atmel_mci_slot *slot = host->slot[i];
+ int err;
+
+ slot = host->slot[i];
+ if (!slot)
+ continue;
+ if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
+ continue;
+ err = mmc_resume_host(slot->mmc);
+ if (err < 0)
+ ret = err;
+ else
+ clear_bit(ATMCI_SUSPENDED, &slot->flags);
+ }
+
+ return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+
static struct platform_driver atmci_driver = {
.remove = __exit_p(atmci_remove),
.driver = {
.name = "atmel_mci",
+ .pm = &atmci_pm,
.of_match_table = of_match_ptr(atmci_dt_ids),
},
};
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index f5443a6..df9becd 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1157,6 +1157,11 @@ static int au1xmmc_remove(struct platform_device *pdev)
static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct au1xmmc_host *host = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = mmc_suspend_host(host->mmc);
+ if (ret)
+ return ret;
au_writel(0, HOST_CONFIG2(host));
au_writel(0, HOST_CONFIG(host));
@@ -1173,7 +1178,7 @@ static int au1xmmc_resume(struct platform_device *pdev)
au1xmmc_reset_controller(host);
- return 0;
+ return mmc_resume_host(host->mmc);
}
#else
#define au1xmmc_suspend NULL
diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c
index 2b7f37e..94fae2f 100644
--- a/drivers/mmc/host/bfin_sdh.c
+++ b/drivers/mmc/host/bfin_sdh.c
@@ -391,7 +391,6 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Disable 4 bit SDIO */
cfg &= ~SD4E;
}
- bfin_write_SDH_CFG(cfg);
host->power_mode = ios->power_mode;
#ifndef RSI_BLKSZ
@@ -416,6 +415,7 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
cfg &= ~SD_CMD_OD;
# endif
+
if (ios->power_mode != MMC_POWER_OFF)
cfg |= PWR_ON;
else
@@ -433,6 +433,7 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clk_ctl |= CLK_E;
host->clk_div = clk_div;
bfin_write_SDH_CLK_CTL(clk_ctl);
+
} else
sdh_stop_clock(host);
@@ -639,15 +640,21 @@ static int sdh_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int sdh_suspend(struct platform_device *dev, pm_message_t state)
{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
struct bfin_sd_host *drv_data = get_sdh_data(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc);
peripheral_free_list(drv_data->pin_req);
- return 0;
+ return ret;
}
static int sdh_resume(struct platform_device *dev)
{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
struct bfin_sd_host *drv_data = get_sdh_data(dev);
int ret = 0;
@@ -658,6 +665,10 @@ static int sdh_resume(struct platform_device *dev)
}
sdh_reset();
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
return ret;
}
#else
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
index 1087b4c..9d6e2b8 100644
--- a/drivers/mmc/host/cb710-mmc.c
+++ b/drivers/mmc/host/cb710-mmc.c
@@ -667,6 +667,12 @@ static const struct mmc_host_ops cb710_mmc_host = {
static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+ struct mmc_host *mmc = cb710_slot_to_mmc(slot);
+ int err;
+
+ err = mmc_suspend_host(mmc);
+ if (err)
+ return err;
cb710_mmc_enable_irq(slot, 0, ~0);
return 0;
@@ -675,9 +681,11 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
static int cb710_mmc_resume(struct platform_device *pdev)
{
struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+ struct mmc_host *mmc = cb710_slot_to_mmc(slot);
cb710_mmc_enable_irq(slot, 0, ~0);
- return 0;
+
+ return mmc_resume_host(mmc);
}
#endif /* CONFIG_PM */
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index d615374..e9fa87d 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -193,6 +193,7 @@ struct mmc_davinci_host {
#define DAVINCI_MMC_DATADIR_READ 1
#define DAVINCI_MMC_DATADIR_WRITE 2
unsigned char data_dir;
+ unsigned char suspended;
/* buffer is used during PIO of one scatterlist segment, and
* is updated along with buffer_bytes_left. bytes_left applies
@@ -1434,23 +1435,38 @@ static int davinci_mmcsd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+ int ret;
- writel(0, host->base + DAVINCI_MMCIM);
- mmc_davinci_reset_ctrl(host, 1);
- clk_disable(host->clk);
+ ret = mmc_suspend_host(host->mmc);
+ if (!ret) {
+ writel(0, host->base + DAVINCI_MMCIM);
+ mmc_davinci_reset_ctrl(host, 1);
+ clk_disable(host->clk);
+ host->suspended = 1;
+ } else {
+ host->suspended = 0;
+ }
- return 0;
+ return ret;
}
static int davinci_mmcsd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+ int ret;
+
+ if (!host->suspended)
+ return 0;
clk_enable(host->clk);
+
mmc_davinci_reset_ctrl(host, 0);
+ ret = mmc_resume_host(host->mmc);
+ if (!ret)
+ host->suspended = 0;
- return 0;
+ return ret;
}
static const struct dev_pm_ops davinci_mmcsd_pm = {
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3423c5e..6a1fa21 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -14,10 +14,8 @@
#include <linux/clk.h>
#include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h>
-#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/slab.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
@@ -32,39 +30,16 @@
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z))
-#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
#define EXYNOS4210_FIXED_CIU_CLK_DIV 2
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
-/* Block number in eMMC */
-#define DWMCI_BLOCK_NUM 0xFFFFFFFF
-
-#define SDMMC_EMMCP_BASE 0x1000
-#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
-#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200)
-#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204)
-#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C)
-
-/* SMU control bits */
-#define DWMCI_MPSCTRL_SECURE_READ_BIT BIT(7)
-#define DWMCI_MPSCTRL_SECURE_WRITE_BIT BIT(6)
-#define DWMCI_MPSCTRL_NON_SECURE_READ_BIT BIT(5)
-#define DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4)
-#define DWMCI_MPSCTRL_USE_FUSE_KEY BIT(3)
-#define DWMCI_MPSCTRL_ECB_MODE BIT(2)
-#define DWMCI_MPSCTRL_ENCRYPTION BIT(1)
-#define DWMCI_MPSCTRL_VALID BIT(0)
-
-#define EXYNOS_CCLKIN_MIN 50000000 /* unit: HZ */
-
/* Variations in Exynos specific dw-mshc controller */
enum dw_mci_exynos_type {
DW_MCI_TYPE_EXYNOS4210,
DW_MCI_TYPE_EXYNOS4412,
DW_MCI_TYPE_EXYNOS5250,
DW_MCI_TYPE_EXYNOS5420,
- DW_MCI_TYPE_EXYNOS5420_SMU,
};
/* Exynos implementation specific driver private data */
@@ -73,7 +48,6 @@ struct dw_mci_exynos_priv_data {
u8 ciu_div;
u32 sdr_timing;
u32 ddr_timing;
- u32 cur_speed;
};
static struct dw_mci_exynos_compatible {
@@ -92,80 +66,44 @@ static struct dw_mci_exynos_compatible {
}, {
.compatible = "samsung,exynos5420-dw-mshc",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420,
- }, {
- .compatible = "samsung,exynos5420-dw-mshc-smu",
- .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU,
},
};
static int dw_mci_exynos_priv_init(struct dw_mci *host)
{
- struct dw_mci_exynos_priv_data *priv = host->priv;
+ struct dw_mci_exynos_priv_data *priv;
+ int idx;
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) {
- mci_writel(host, MPSBEGIN0, 0);
- mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM);
- mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT |
- DWMCI_MPSCTRL_NON_SECURE_READ_BIT |
- DWMCI_MPSCTRL_VALID |
- DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT);
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
+ if (of_device_is_compatible(host->dev->of_node,
+ exynos_compat[idx].compatible))
+ priv->ctrl_type = exynos_compat[idx].ctrl_type;
}
+ host->priv = priv;
return 0;
}
static int dw_mci_exynos_setup_clock(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- unsigned long rate = clk_get_rate(host->ciu_clk);
- host->bus_hz = rate / (priv->ciu_div + 1);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int dw_mci_exynos_suspend(struct device *dev)
-{
- struct dw_mci *host = dev_get_drvdata(dev);
-
- return dw_mci_suspend(host);
-}
-
-static int dw_mci_exynos_resume(struct device *dev)
-{
- struct dw_mci *host = dev_get_drvdata(dev);
-
- dw_mci_exynos_priv_init(host);
- return dw_mci_resume(host);
-}
-
-/**
- * dw_mci_exynos_resume_noirq - Exynos-specific resume code
- *
- * On exynos5420 there is a silicon errata that will sometimes leave the
- * WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate
- * that it fired and we can clear it by writing a 1 back. Clear it to prevent
- * interrupts from going off constantly.
- *
- * We run this code on all exynos variants because it doesn't hurt.
- */
-
-static int dw_mci_exynos_resume_noirq(struct device *dev)
-{
- struct dw_mci *host = dev_get_drvdata(dev);
- u32 clksel;
-
- clksel = mci_readl(host, CLKSEL);
- if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
- mci_writel(host, CLKSEL, clksel);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420)
+ host->bus_hz /= (priv->ciu_div + 1);
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+ host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ host->bus_hz /= EXYNOS4210_FIXED_CIU_CLK_DIV;
return 0;
}
-#else
-#define dw_mci_exynos_suspend NULL
-#define dw_mci_exynos_resume NULL
-#define dw_mci_exynos_resume_noirq NULL
-#endif /* CONFIG_PM_SLEEP */
static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
{
@@ -183,68 +121,23 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- unsigned int wanted = ios->clock;
- unsigned long actual;
- u8 div = priv->ciu_div + 1;
- if (ios->timing == MMC_TIMING_UHS_DDR50) {
+ if (ios->timing == MMC_TIMING_UHS_DDR50)
mci_writel(host, CLKSEL, priv->ddr_timing);
- /* Should be double rate for DDR mode */
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- wanted <<= 1;
- } else {
+ else
mci_writel(host, CLKSEL, priv->sdr_timing);
- }
-
- /* Don't care if wanted clock is zero */
- if (!wanted)
- return;
-
- /* Guaranteed minimum frequency for cclkin */
- if (wanted < EXYNOS_CCLKIN_MIN)
- wanted = EXYNOS_CCLKIN_MIN;
-
- if (wanted != priv->cur_speed) {
- int ret = clk_set_rate(host->ciu_clk, wanted * div);
- if (ret)
- dev_warn(host->dev,
- "failed to set clk-rate %u error: %d\n",
- wanted * div, ret);
- actual = clk_get_rate(host->ciu_clk);
- host->bus_hz = actual / div;
- priv->cur_speed = wanted;
- host->current_speed = 0;
- }
}
static int dw_mci_exynos_parse_dt(struct dw_mci *host)
{
- struct dw_mci_exynos_priv_data *priv;
+ struct dw_mci_exynos_priv_data *priv = host->priv;
struct device_node *np = host->dev->of_node;
u32 timing[2];
u32 div = 0;
- int idx;
int ret;
- priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(host->dev, "mem alloc failed for private data\n");
- return -ENOMEM;
- }
-
- for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
- if (of_device_is_compatible(np, exynos_compat[idx].compatible))
- priv->ctrl_type = exynos_compat[idx].ctrl_type;
- }
-
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
- priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
- else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
- priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
- else {
- of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
- priv->ciu_div = div;
- }
+ of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
+ priv->ciu_div = div;
ret = of_property_read_u32_array(np,
"samsung,dw-mshc-sdr-timing", timing, 2);
@@ -259,131 +152,9 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return ret;
priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
- host->priv = priv;
return 0;
}
-static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
-{
- return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
-}
-
-static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
-{
- u32 clksel;
- clksel = mci_readl(host, CLKSEL);
- clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
- mci_writel(host, CLKSEL, clksel);
-}
-
-static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
-{
- u32 clksel;
- u8 sample;
-
- clksel = mci_readl(host, CLKSEL);
- sample = (clksel + 1) & 0x7;
- clksel = (clksel & ~0x7) | sample;
- mci_writel(host, CLKSEL, clksel);
- return sample;
-}
-
-static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
-{
- const u8 iter = 8;
- u8 __c;
- s8 i, loc = -1;
-
- for (i = 0; i < iter; i++) {
- __c = ror8(candiates, i);
- if ((__c & 0xc7) == 0xc7) {
- loc = i;
- goto out;
- }
- }
-
- for (i = 0; i < iter; i++) {
- __c = ror8(candiates, i);
- if ((__c & 0x83) == 0x83) {
- loc = i;
- goto out;
- }
- }
-
-out:
- return loc;
-}
-
-static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
- struct dw_mci_tuning_data *tuning_data)
-{
- struct dw_mci *host = slot->host;
- struct mmc_host *mmc = slot->mmc;
- const u8 *blk_pattern = tuning_data->blk_pattern;
- u8 *blk_test;
- unsigned int blksz = tuning_data->blksz;
- u8 start_smpl, smpl, candiates = 0;
- s8 found = -1;
- int ret = 0;
-
- blk_test = kmalloc(blksz, GFP_KERNEL);
- if (!blk_test)
- return -ENOMEM;
-
- start_smpl = dw_mci_exynos_get_clksmpl(host);
-
- do {
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- stop.opcode = MMC_STOP_TRANSMISSION;
- stop.arg = 0;
- stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- data.blksz = blksz;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, blk_test, blksz);
- mrq.cmd = &cmd;
- mrq.stop = &stop;
- mrq.data = &data;
- host->mrq = &mrq;
-
- mci_writel(host, TMOUT, ~0);
- smpl = dw_mci_exynos_move_next_clksmpl(host);
-
- mmc_wait_for_req(mmc, &mrq);
-
- if (!cmd.error && !data.error) {
- if (!memcmp(blk_pattern, blk_test, blksz))
- candiates |= (1 << smpl);
- } else {
- dev_dbg(host->dev,
- "Tuning error: cmd.error:%d, data.error:%d\n",
- cmd.error, data.error);
- }
- } while (start_smpl != smpl);
-
- found = dw_mci_exynos_get_best_clksmpl(candiates);
- if (found >= 0)
- dw_mci_exynos_set_clksmpl(host, found);
- else
- ret = -EIO;
-
- kfree(blk_test);
- return ret;
-}
-
/* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
@@ -400,7 +171,6 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
- .execute_tuning = dw_mci_exynos_execute_tuning,
};
static const struct of_device_id dw_mci_exynos_match[] = {
@@ -410,8 +180,6 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc",
.data = &exynos_drv_data, },
- { .compatible = "samsung,exynos5420-dw-mshc-smu",
- .data = &exynos_drv_data, },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
@@ -426,20 +194,13 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data);
}
-const struct dev_pm_ops dw_mci_exynos_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
- .resume_noirq = dw_mci_exynos_resume_noirq,
- .thaw_noirq = dw_mci_exynos_resume_noirq,
- .restore_noirq = dw_mci_exynos_resume_noirq,
-};
-
static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe,
.remove = __exit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match,
- .pm = &dw_mci_exynos_pmops,
+ .pm = &dw_mci_pltfm_pmops,
},
};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 5c49656..2089752 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -39,6 +39,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
{
struct dw_mci *host;
struct resource *regs;
+ int ret;
host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
if (!host)
@@ -58,6 +59,12 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
if (IS_ERR(host->regs))
return PTR_ERR(host->regs);
+ if (drv_data && drv_data->init) {
+ ret = drv_data->init(host);
+ if (ret)
+ return ret;
+ }
+
platform_set_drvdata(pdev, host);
return dw_mci_probe(host);
}
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
index 3e8e53a..14b5961 100644
--- a/drivers/mmc/host/dw_mmc-socfpga.c
+++ b/drivers/mmc/host/dw_mmc-socfpga.c
@@ -38,6 +38,21 @@ struct dw_mci_socfpga_priv_data {
static int dw_mci_socfpga_priv_init(struct dw_mci *host)
{
+ struct dw_mci_socfpga_priv_data *priv;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+
+ priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+ if (IS_ERR(priv->sysreg)) {
+ dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
+ return PTR_ERR(priv->sysreg);
+ }
+ host->priv = priv;
+
return 0;
}
@@ -64,24 +79,12 @@ static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
{
- struct dw_mci_socfpga_priv_data *priv;
+ struct dw_mci_socfpga_priv_data *priv = host->priv;
struct device_node *np = host->dev->of_node;
u32 timing[2];
u32 div = 0;
int ret;
- priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(host->dev, "mem alloc failed for private data\n");
- return -ENOMEM;
- }
-
- priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
- if (IS_ERR(priv->sysreg)) {
- dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
- return PTR_ERR(priv->sysreg);
- }
-
ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
if (ret)
dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
@@ -93,7 +96,6 @@ static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
return ret;
priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
- host->priv = priv;
return 0;
}
@@ -111,7 +113,7 @@ static const struct of_device_id dw_mci_socfpga_match[] = {
};
MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
-static int dw_mci_socfpga_probe(struct platform_device *pdev)
+int dw_mci_socfpga_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match;
@@ -126,7 +128,7 @@ static struct platform_driver dw_mci_socfpga_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dwmmc_socfpga",
- .of_match_table = dw_mci_socfpga_match,
+ .of_match_table = of_match_ptr(dw_mci_socfpga_match),
.pm = &dw_mci_pltfm_pmops,
},
};
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bce0de..018f365 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -29,7 +29,6 @@
#include <linux/irq.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
@@ -51,9 +50,6 @@
#define DW_MCI_RECV_STATUS 2
#define DW_MCI_DMA_THRESHOLD 16
-#define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */
-#define DW_MCI_FREQ_MIN 400000 /* unit: HZ */
-
#ifdef CONFIG_MMC_DW_IDMAC
#define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
@@ -80,38 +76,41 @@ struct idmac_desc {
};
#endif /* CONFIG_MMC_DW_IDMAC */
-static const u8 tuning_blk_pattern_4bit[] = {
- 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
- 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
- 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
- 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
- 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
- 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
- 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
- 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
-};
+/**
+ * struct dw_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
+ * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
+ * @ctype: Card type for this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ * processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ * &struct dw_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @id: Number of this slot.
+ * @last_detect_state: Most recently observed card detect state.
+ */
+struct dw_mci_slot {
+ struct mmc_host *mmc;
+ struct dw_mci *host;
-static const u8 tuning_blk_pattern_8bit[] = {
- 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
- 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
- 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
- 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
- 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
- 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
- 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
- 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
- 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
- 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
- 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
- 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
- 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
-};
+ int quirks;
+ int wp_gpio;
+
+ u32 ctype;
+
+ struct mmc_request *mrq;
+ struct list_head queue_node;
-static inline bool dw_mci_fifo_reset(struct dw_mci *host);
-static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host);
+ unsigned int clock;
+ unsigned long flags;
+#define DW_MMC_CARD_PRESENT 0
+#define DW_MMC_CARD_NEED_INIT 1
+ int id;
+ int last_detect_state;
+};
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -250,15 +249,10 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
cmdr = cmd->opcode;
- if (cmd->opcode == MMC_STOP_TRANSMISSION ||
- cmd->opcode == MMC_GO_IDLE_STATE ||
- cmd->opcode == MMC_GO_INACTIVE_STATE ||
- (cmd->opcode == SD_IO_RW_DIRECT &&
- ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
+ if (cmdr == MMC_STOP_TRANSMISSION)
cmdr |= SDMMC_CMD_STOP;
else
- if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
- cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+ cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
if (cmd->flags & MMC_RSP_PRESENT) {
/* We expect a response, so set this bit */
@@ -285,40 +279,6 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
return cmdr;
}
-static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
-{
- struct mmc_command *stop;
- u32 cmdr;
-
- if (!cmd->data)
- return 0;
-
- stop = &host->stop_abort;
- cmdr = cmd->opcode;
- memset(stop, 0, sizeof(struct mmc_command));
-
- if (cmdr == MMC_READ_SINGLE_BLOCK ||
- cmdr == MMC_READ_MULTIPLE_BLOCK ||
- cmdr == MMC_WRITE_BLOCK ||
- cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
- stop->opcode = MMC_STOP_TRANSMISSION;
- stop->arg = 0;
- stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
- } else if (cmdr == SD_IO_RW_EXTENDED) {
- stop->opcode = SD_IO_RW_DIRECT;
- stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
- ((cmd->arg >> 28) & 0x7);
- stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
- } else {
- return 0;
- }
-
- cmdr = stop->opcode | SDMMC_CMD_STOP |
- SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
-
- return cmdr;
-}
-
static void dw_mci_start_command(struct dw_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
@@ -333,10 +293,9 @@ static void dw_mci_start_command(struct dw_mci *host,
mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
}
-static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
+static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
{
- struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
- dw_mci_start_command(host, stop, host->stop_cmdr);
+ dw_mci_start_command(host, data->stop, host->stop_cmdr);
}
/* DMA interface functions */
@@ -345,10 +304,10 @@ static void dw_mci_stop_dma(struct dw_mci *host)
if (host->using_dma) {
host->dma_ops->stop(host);
host->dma_ops->cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
+ set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
-
- /* Data transfer was stopped by the interrupt handler */
- set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
static int dw_mci_get_dma_dir(struct mmc_data *data)
@@ -372,14 +331,6 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
dw_mci_get_dma_dir(data));
}
-static void dw_mci_idmac_reset(struct dw_mci *host)
-{
- u32 bmod = mci_readl(host, BMOD);
- /* Software reset of DMA */
- bmod |= SDMMC_IDMAC_SWRESET;
- mci_writel(host, BMOD, bmod);
-}
-
static void dw_mci_idmac_stop_dma(struct dw_mci *host)
{
u32 temp;
@@ -393,7 +344,6 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
/* Stop the IDMAC running */
temp = mci_readl(host, BMOD);
temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
- temp |= SDMMC_IDMAC_SWRESET;
mci_writel(host, BMOD, temp);
}
@@ -485,7 +435,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
p->des3 = host->sg_dma;
p->des0 = IDMAC_DES0_ER;
- dw_mci_idmac_reset(host);
+ mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
/* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDSTS, IDMAC_INT_CLR);
@@ -582,78 +532,6 @@ static void dw_mci_post_req(struct mmc_host *mmc,
data->host_cookie = 0;
}
-static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
-{
-#ifdef CONFIG_MMC_DW_IDMAC
- unsigned int blksz = data->blksz;
- const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
- u32 fifo_width = 1 << host->data_shift;
- u32 blksz_depth = blksz / fifo_width, fifoth_val;
- u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
- int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
-
- tx_wmark = (host->fifo_depth) / 2;
- tx_wmark_invers = host->fifo_depth - tx_wmark;
-
- /*
- * MSIZE is '1',
- * if blksz is not a multiple of the FIFO width
- */
- if (blksz % fifo_width) {
- msize = 0;
- rx_wmark = 1;
- goto done;
- }
-
- do {
- if (!((blksz_depth % mszs[idx]) ||
- (tx_wmark_invers % mszs[idx]))) {
- msize = idx;
- rx_wmark = mszs[idx] - 1;
- break;
- }
- } while (--idx > 0);
- /*
- * If idx is '0', it won't be tried
- * Thus, initial values are uesed
- */
-done:
- fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
- mci_writel(host, FIFOTH, fifoth_val);
-#endif
-}
-
-static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
-{
- unsigned int blksz = data->blksz;
- u32 blksz_depth, fifo_depth;
- u16 thld_size;
-
- WARN_ON(!(data->flags & MMC_DATA_READ));
-
- if (host->timing != MMC_TIMING_MMC_HS200 &&
- host->timing != MMC_TIMING_UHS_SDR104)
- goto disable;
-
- blksz_depth = blksz / (1 << host->data_shift);
- fifo_depth = host->fifo_depth;
-
- if (blksz_depth > fifo_depth)
- goto disable;
-
- /*
- * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
- * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz
- * Currently just choose blksz.
- */
- thld_size = blksz;
- mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
- return;
-
-disable:
- mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
-}
-
static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
{
int sg_len;
@@ -678,14 +556,6 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
(unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
sg_len);
- /*
- * Decide the MSIZE and RX/TX Watermark.
- * If current block size is same with previous size,
- * no need to update fifoth.
- */
- if (host->prev_blksz != data->blksz)
- dw_mci_adjust_fifoth(host, data);
-
/* Enable the DMA interface */
temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_DMA_ENABLE;
@@ -711,12 +581,10 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
host->sg = NULL;
host->data = data;
- if (data->flags & MMC_DATA_READ) {
+ if (data->flags & MMC_DATA_READ)
host->dir_status = DW_MCI_RECV_STATUS;
- dw_mci_ctrl_rd_thld(host, data);
- } else {
+ else
host->dir_status = DW_MCI_SEND_STATUS;
- }
if (dw_mci_submit_data_dma(host, data)) {
int flags = SG_MITER_ATOMIC;
@@ -738,21 +606,6 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
temp = mci_readl(host, CTRL);
temp &= ~SDMMC_CTRL_DMA_ENABLE;
mci_writel(host, CTRL, temp);
-
- /*
- * Use the initial fifoth_val for PIO mode.
- * If next issued data may be transfered by DMA mode,
- * prev_blksz should be invalidated.
- */
- mci_writel(host, FIFOTH, host->fifoth_val);
- host->prev_blksz = 0;
- } else {
- /*
- * Keep the current block size.
- * It will be used to decide whether to update
- * fifoth register next time.
- */
- host->prev_blksz = data->blksz;
}
}
@@ -779,31 +632,24 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
- unsigned int clock = slot->clock;
u32 div;
u32 clk_en_a;
- if (!clock) {
- mci_writel(host, CLKENA, 0);
- mci_send_cmd(slot,
- SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
- } else if (clock != host->current_speed || force_clkinit) {
- div = host->bus_hz / clock;
- if (host->bus_hz % clock && host->bus_hz > clock)
+ if (slot->clock != host->current_speed || force_clkinit) {
+ div = host->bus_hz / slot->clock;
+ if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)
/*
* move the + 1 after the divide to prevent
* over-clocking the card.
*/
div += 1;
- div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
+ div = (host->bus_hz != slot->clock) ? DIV_ROUND_UP(div, 2) : 0;
- if ((clock << div) != slot->__clk_old || force_clkinit)
- dev_info(&slot->mmc->class_dev,
- "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
- slot->id, host->bus_hz, clock,
- div ? ((host->bus_hz / div) >> 1) :
- host->bus_hz, div);
+ dev_info(&slot->mmc->class_dev,
+ "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ"
+ " div = %d)\n", slot->id, host->bus_hz, slot->clock,
+ div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div);
/* disable clock */
mci_writel(host, CLKENA, 0);
@@ -830,12 +676,9 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
mci_send_cmd(slot,
SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
- /* keep the clock with reflecting clock dividor */
- slot->__clk_old = clock << div;
+ host->current_speed = slot->clock;
}
- host->current_speed = clock;
-
/* Set the current slot bus width */
mci_writel(host, CTYPE, (slot->ctype << slot->id));
}
@@ -857,9 +700,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
host->pending_events = 0;
host->completed_events = 0;
- host->cmd_status = 0;
host->data_status = 0;
- host->dir_status = 0;
data = cmd->data;
if (data) {
@@ -883,8 +724,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (mrq->stop)
host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
- else
- host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
}
static void dw_mci_start_request(struct dw_mci *host,
@@ -967,13 +806,14 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
regs &= ~((0x1 << slot->id) << 16);
mci_writel(slot->host, UHS_REG, regs);
- slot->host->timing = ios->timing;
- /*
- * Use mirror of ios->clock to prevent race with mmc
- * core ios update when finding the minimum.
- */
- slot->clock = ios->clock;
+ if (ios->clock) {
+ /*
+ * Use mirror of ios->clock to prevent race with mmc
+ * core ios update when finding the minimum.
+ */
+ slot->clock = ios->clock;
+ }
if (drv_data && drv_data->set_ios)
drv_data->set_ios(slot->host, ios);
@@ -1099,38 +939,6 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
}
}
-static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci *host = slot->host;
- const struct dw_mci_drv_data *drv_data = host->drv_data;
- struct dw_mci_tuning_data tuning_data;
- int err = -ENOSYS;
-
- if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
- if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
- tuning_data.blk_pattern = tuning_blk_pattern_8bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
- } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
- tuning_data.blk_pattern = tuning_blk_pattern_4bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
- } else {
- return -EINVAL;
- }
- } else if (opcode == MMC_SEND_TUNING_BLOCK) {
- tuning_data.blk_pattern = tuning_blk_pattern_4bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
- } else {
- dev_err(host->dev,
- "Undefined command(%d) for tuning\n", opcode);
- return -EINVAL;
- }
-
- if (drv_data && drv_data->execute_tuning)
- err = drv_data->execute_tuning(slot, opcode, &tuning_data);
- return err;
-}
-
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -1139,7 +947,6 @@ static const struct mmc_host_ops dw_mci_ops = {
.get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd,
.enable_sdio_irq = dw_mci_enable_sdio_irq,
- .execute_tuning = dw_mci_execute_tuning,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -1171,7 +978,7 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
spin_lock(&host->lock);
}
-static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
+static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
{
u32 status = host->cmd_status;
@@ -1205,52 +1012,12 @@ static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
/* newer ip versions need a delay between retries */
if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
mdelay(20);
- }
-
- return cmd->error;
-}
-
-static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
-{
- u32 status = host->data_status;
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- if (status & SDMMC_INT_DRTO) {
- data->error = -ETIMEDOUT;
- } else if (status & SDMMC_INT_DCRC) {
- data->error = -EILSEQ;
- } else if (status & SDMMC_INT_EBE) {
- if (host->dir_status ==
- DW_MCI_SEND_STATUS) {
- /*
- * No data CRC status was returned.
- * The number of bytes transferred
- * will be exaggerated in PIO mode.
- */
- data->bytes_xfered = 0;
- data->error = -ETIMEDOUT;
- } else if (host->dir_status ==
- DW_MCI_RECV_STATUS) {
- data->error = -EIO;
- }
- } else {
- /* SDMMC_INT_SBE is included */
- data->error = -EIO;
+ if (cmd->data) {
+ dw_mci_stop_dma(host);
+ host->data = NULL;
}
-
- dev_err(host->dev, "data error, status 0x%08x\n", status);
-
- /*
- * After an error, there may be data lingering
- * in the FIFO
- */
- dw_mci_fifo_reset(host);
- } else {
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
}
-
- return data->error;
}
static void dw_mci_tasklet_func(unsigned long priv)
@@ -1258,16 +1025,14 @@ static void dw_mci_tasklet_func(unsigned long priv)
struct dw_mci *host = (struct dw_mci *)priv;
struct mmc_data *data;
struct mmc_command *cmd;
- struct mmc_request *mrq;
enum dw_mci_state state;
enum dw_mci_state prev_state;
- unsigned int err;
+ u32 status, ctrl;
spin_lock(&host->lock);
state = host->state;
data = host->data;
- mrq = host->mrq;
do {
prev_state = state;
@@ -1284,23 +1049,16 @@ static void dw_mci_tasklet_func(unsigned long priv)
cmd = host->cmd;
host->cmd = NULL;
set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
- err = dw_mci_command_complete(host, cmd);
- if (cmd == mrq->sbc && !err) {
+ dw_mci_command_complete(host, cmd);
+ if (cmd == host->mrq->sbc && !cmd->error) {
prev_state = state = STATE_SENDING_CMD;
__dw_mci_start_request(host, host->cur_slot,
- mrq->cmd);
+ host->mrq->cmd);
goto unlock;
}
- if (cmd->data && err) {
- dw_mci_stop_dma(host);
- send_stop_abort(host, data);
- state = STATE_SENDING_STOP;
- break;
- }
-
- if (!cmd->data || err) {
- dw_mci_request_end(host, mrq);
+ if (!host->mrq->data || cmd->error) {
+ dw_mci_request_end(host, host->mrq);
goto unlock;
}
@@ -1311,7 +1069,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) {
dw_mci_stop_dma(host);
- send_stop_abort(host, data);
+ if (data->stop)
+ send_stop_cmd(host, data);
state = STATE_DATA_ERROR;
break;
}
@@ -1331,27 +1090,60 @@ static void dw_mci_tasklet_func(unsigned long priv)
host->data = NULL;
set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
- err = dw_mci_data_complete(host, data);
-
- if (!err) {
- if (!data->stop || mrq->sbc) {
- if (mrq->sbc)
- data->stop->error = 0;
- dw_mci_request_end(host, mrq);
- goto unlock;
+ status = host->data_status;
+
+ if (status & DW_MCI_DATA_ERROR_FLAGS) {
+ if (status & SDMMC_INT_DRTO) {
+ data->error = -ETIMEDOUT;
+ } else if (status & SDMMC_INT_DCRC) {
+ data->error = -EILSEQ;
+ } else if (status & SDMMC_INT_EBE &&
+ host->dir_status ==
+ DW_MCI_SEND_STATUS) {
+ /*
+ * No data CRC status was returned.
+ * The number of bytes transferred will
+ * be exaggerated in PIO mode.
+ */
+ data->bytes_xfered = 0;
+ data->error = -ETIMEDOUT;
+ } else {
+ dev_err(host->dev,
+ "data FIFO error "
+ "(status=%08x)\n",
+ status);
+ data->error = -EIO;
}
+ /*
+ * After an error, there may be data lingering
+ * in the FIFO, so reset it - doing so
+ * generates a block interrupt, hence setting
+ * the scatter-gather pointer to NULL.
+ */
+ sg_miter_stop(&host->sg_miter);
+ host->sg = NULL;
+ ctrl = mci_readl(host, CTRL);
+ ctrl |= SDMMC_CTRL_FIFO_RESET;
+ mci_writel(host, CTRL, ctrl);
+ } else {
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ }
- /* stop command for open-ended transfer*/
- if (data->stop)
- send_stop_abort(host, data);
+ if (!data->stop) {
+ dw_mci_request_end(host, host->mrq);
+ goto unlock;
}
- /*
- * If err has non-zero,
- * stop-abort command has been already issued.
- */
- prev_state = state = STATE_SENDING_STOP;
+ if (host->mrq->sbc && !data->error) {
+ data->stop->error = 0;
+ dw_mci_request_end(host, host->mrq);
+ goto unlock;
+ }
+ prev_state = state = STATE_SENDING_STOP;
+ if (!data->error)
+ send_stop_cmd(host, data);
/* fall through */
case STATE_SENDING_STOP:
@@ -1359,19 +1151,9 @@ static void dw_mci_tasklet_func(unsigned long priv)
&host->pending_events))
break;
- /* CMD error in data command */
- if (mrq->cmd->error && mrq->data)
- dw_mci_fifo_reset(host);
-
host->cmd = NULL;
- host->data = NULL;
-
- if (mrq->stop)
- dw_mci_command_complete(host, mrq->stop);
- else
- host->cmd_status = 0;
-
- dw_mci_request_end(host, mrq);
+ dw_mci_command_complete(host, host->mrq->stop);
+ dw_mci_request_end(host, host->mrq);
goto unlock;
case STATE_DATA_ERROR:
@@ -1915,6 +1697,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
struct mmc_host *mmc = slot->mmc;
struct mmc_request *mrq;
int present;
+ u32 ctrl;
present = dw_mci_get_cd(mmc);
while (present != slot->last_detect_state) {
@@ -1953,10 +1736,11 @@ static void dw_mci_work_routine_card(struct work_struct *work)
case STATE_DATA_ERROR:
if (mrq->data->error == -EINPROGRESS)
mrq->data->error = -ENOMEDIUM;
+ if (!mrq->stop)
+ break;
/* fall through */
case STATE_SENDING_STOP:
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
+ mrq->stop->error = -ENOMEDIUM;
break;
}
@@ -1979,10 +1763,23 @@ static void dw_mci_work_routine_card(struct work_struct *work)
if (present == 0) {
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- /* Clear down the FIFO */
- dw_mci_fifo_reset(host);
+ /*
+ * Clear down the FIFO - doing so generates a
+ * block interrupt, hence setting the
+ * scatter-gather pointer to NULL.
+ */
+ sg_miter_stop(&host->sg_miter);
+ host->sg = NULL;
+
+ ctrl = mci_readl(host, CTRL);
+ ctrl |= SDMMC_CTRL_FIFO_RESET;
+ mci_writel(host, CTRL, ctrl);
+
#ifdef CONFIG_MMC_DW_IDMAC
- dw_mci_idmac_reset(host);
+ ctrl = mci_readl(host, BMOD);
+ /* Software reset of DMA */
+ ctrl |= SDMMC_IDMAC_SWRESET;
+ mci_writel(host, BMOD, ctrl);
#endif
}
@@ -2104,7 +1901,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
struct dw_mci_slot *slot;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int ctrl_id, ret;
- u32 freq[2];
u8 bus_width;
mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
@@ -2120,14 +1916,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
mmc->ops = &dw_mci_ops;
- if (of_property_read_u32_array(host->dev->of_node,
- "clock-freq-min-max", freq, 2)) {
- mmc->f_min = DW_MCI_FREQ_MIN;
- mmc->f_max = DW_MCI_FREQ_MAX;
- } else {
- mmc->f_min = freq[0];
- mmc->f_max = freq[1];
- }
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
+ mmc->f_max = host->bus_hz;
if (host->pdata->get_ocr)
mmc->ocr_avail = host->pdata->get_ocr(id);
@@ -2174,6 +1964,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->caps |= MMC_CAP_4_BIT_DATA;
}
+ if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
+
if (host->pdata->blk_settings) {
mmc->max_segs = host->pdata->blk_settings->max_segs;
mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
@@ -2215,6 +2008,12 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
/* Card initially undetected */
slot->last_detect_state = 0;
+ /*
+ * Card may have been plugged in prior to boot so we
+ * need to run the detect tasklet
+ */
+ queue_work(host->card_workqueue, &host->card_work);
+
return 0;
err_setup_bus:
@@ -2275,57 +2074,36 @@ no_dma:
return;
}
-static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
+static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
{
unsigned long timeout = jiffies + msecs_to_jiffies(500);
- u32 ctrl;
+ unsigned int ctrl;
- ctrl = mci_readl(host, CTRL);
- ctrl |= reset;
- mci_writel(host, CTRL, ctrl);
+ mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
+ SDMMC_CTRL_DMA_RESET));
/* wait till resets clear */
do {
ctrl = mci_readl(host, CTRL);
- if (!(ctrl & reset))
+ if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
+ SDMMC_CTRL_DMA_RESET)))
return true;
} while (time_before(jiffies, timeout));
- dev_err(host->dev,
- "Timeout resetting block (ctrl reset %#x)\n",
- ctrl & reset);
+ dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
return false;
}
-static inline bool dw_mci_fifo_reset(struct dw_mci *host)
-{
- /*
- * Reseting generates a block interrupt, hence setting
- * the scatter-gather pointer to NULL.
- */
- if (host->sg) {
- sg_miter_stop(&host->sg_miter);
- host->sg = NULL;
- }
-
- return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET);
-}
-
-static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host)
-{
- return dw_mci_ctrl_reset(host,
- SDMMC_CTRL_FIFO_RESET |
- SDMMC_CTRL_RESET |
- SDMMC_CTRL_DMA_RESET);
-}
-
#ifdef CONFIG_OF
static struct dw_mci_of_quirks {
char *quirk;
int id;
} of_quirks[] = {
{
+ .quirk = "supports-highspeed",
+ .id = DW_MCI_QUIRK_HIGHSPEED,
+ }, {
.quirk = "broken-cd",
.id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
},
@@ -2380,15 +2158,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
if (of_find_property(np, "enable-sdio-wakeup", NULL))
pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
- if (of_find_property(np, "supports-highspeed", NULL))
- pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
- if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
- pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
-
- if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
- pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
-
return pdata;
}
@@ -2452,15 +2221,6 @@ int dw_mci_probe(struct dw_mci *host)
host->bus_hz = clk_get_rate(host->ciu_clk);
}
- if (drv_data && drv_data->init) {
- ret = drv_data->init(host);
- if (ret) {
- dev_err(host->dev,
- "implementation specific init failed\n");
- goto err_clk_ciu;
- }
- }
-
if (drv_data && drv_data->setup_clock) {
ret = drv_data->setup_clock(host);
if (ret) {
@@ -2527,7 +2287,7 @@ int dw_mci_probe(struct dw_mci *host)
}
/* Reset all blocks */
- if (!dw_mci_ctrl_all_reset(host))
+ if (!mci_wait_reset(host->dev, host))
return -ENODEV;
host->dma_ops = host->pdata->dma_ops;
@@ -2557,8 +2317,8 @@ int dw_mci_probe(struct dw_mci *host)
fifo_size = host->pdata->fifo_depth;
}
host->fifo_depth = fifo_size;
- host->fifoth_val =
- SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
+ host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+ ((fifo_size/2) << 0));
mci_writel(host, FIFOTH, host->fifoth_val);
/* disable clock to CIU */
@@ -2696,6 +2456,23 @@ EXPORT_SYMBOL(dw_mci_remove);
*/
int dw_mci_suspend(struct dw_mci *host)
{
+ int i, ret = 0;
+
+ for (i = 0; i < host->num_slots; i++) {
+ struct dw_mci_slot *slot = host->slot[i];
+ if (!slot)
+ continue;
+ ret = mmc_suspend_host(slot->mmc);
+ if (ret < 0) {
+ while (--i >= 0) {
+ slot = host->slot[i];
+ if (slot)
+ mmc_resume_host(host->slot[i]->mmc);
+ }
+ return ret;
+ }
+ }
+
if (host->vmmc)
regulator_disable(host->vmmc);
@@ -2716,7 +2493,7 @@ int dw_mci_resume(struct dw_mci *host)
}
}
- if (!dw_mci_ctrl_all_reset(host)) {
+ if (!mci_wait_reset(host->dev, host)) {
ret = -ENODEV;
return ret;
}
@@ -2724,15 +2501,8 @@ int dw_mci_resume(struct dw_mci *host)
if (host->use_dma && host->dma_ops->init)
host->dma_ops->init(host);
- /*
- * Restore the initial value at FIFOTH register
- * And Invalidate the prev_blksz with zero
- */
+ /* Restore the old value at FIFOTH register */
mci_writel(host, FIFOTH, host->fifoth_val);
- host->prev_blksz = 0;
-
- /* Put in max timeout */
- mci_writel(host, TMOUT, 0xFFFFFFFF);
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
@@ -2748,6 +2518,10 @@ int dw_mci_resume(struct dw_mci *host)
dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
dw_mci_setup_bus(slot, true);
}
+
+ ret = mmc_resume_host(host->slot[i]->mmc);
+ if (ret < 0)
+ return ret;
}
return 0;
}
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 6bf24ab..81b2994 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -53,7 +53,6 @@
#define SDMMC_IDINTEN 0x090
#define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098
-#define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x)
/*
@@ -129,10 +128,6 @@
#define SDMMC_CMD_INDX(n) ((n) & 0x1F)
/* Status register defines */
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)
-/* FIFOTH register defines */
-#define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \
- ((r) & 0xFFF) << 16 | \
- ((t) & 0xFFF))
/* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9)
#define SDMMC_IDMAC_INT_NI BIT(8)
@@ -147,8 +142,6 @@
#define SDMMC_IDMAC_SWRESET BIT(0)
/* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
-/* Card read threshold */
-#define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x))
/* Register access macros */
#define mci_readl(dev, reg) \
@@ -191,52 +184,6 @@ extern int dw_mci_resume(struct dw_mci *host);
#endif
/**
- * struct dw_mci_slot - MMC slot state
- * @mmc: The mmc_host representing this slot.
- * @host: The MMC controller this slot is using.
- * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
- * @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
- * @ctype: Card type for this slot.
- * @mrq: mmc_request currently being processed or waiting to be
- * processed, or NULL when the slot is idle.
- * @queue_node: List node for placing this node in the @queue list of
- * &struct dw_mci.
- * @clock: Clock rate configured by set_ios(). Protected by host->lock.
- * @__clk_old: The last updated clock with reflecting clock divider.
- * Keeping track of this helps us to avoid spamming the console
- * with CONFIG_MMC_CLKGATE.
- * @flags: Random state bits associated with the slot.
- * @id: Number of this slot.
- * @last_detect_state: Most recently observed card detect state.
- */
-struct dw_mci_slot {
- struct mmc_host *mmc;
- struct dw_mci *host;
-
- int quirks;
- int wp_gpio;
-
- u32 ctype;
-
- struct mmc_request *mrq;
- struct list_head queue_node;
-
- unsigned int clock;
- unsigned int __clk_old;
-
- unsigned long flags;
-#define DW_MMC_CARD_PRESENT 0
-#define DW_MMC_CARD_NEED_INIT 1
- int id;
- int last_detect_state;
-};
-
-struct dw_mci_tuning_data {
- const u8 *blk_pattern;
- unsigned int blksz;
-};
-
-/**
* dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s).
* @init: early implementation specific initialization.
@@ -256,7 +203,5 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host);
- int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
- struct dw_mci_tuning_data *tuning_data);
};
#endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index de2139c..6651633 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -880,6 +880,8 @@ static int jz4740_mmc_suspend(struct device *dev)
{
struct jz4740_mmc_host *host = dev_get_drvdata(dev);
+ mmc_suspend_host(host->mmc);
+
jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
return 0;
@@ -891,6 +893,8 @@ static int jz4740_mmc_resume(struct device *dev)
jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+ mmc_resume_host(host->mmc);
+
return 0;
}
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f320579..c3785ed 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -62,7 +62,6 @@ static unsigned int fmax = 515633;
* @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
- * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
*/
struct variant_data {
unsigned int clkreg;
@@ -77,7 +76,6 @@ struct variant_data {
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
- bool pwrreg_nopower;
};
static struct variant_data variant_arm = {
@@ -111,7 +109,6 @@ static struct variant_data variant_u300 = {
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
.pwrreg_clkgate = true,
- .pwrreg_nopower = true,
};
static struct variant_data variant_nomadik = {
@@ -124,7 +121,6 @@ static struct variant_data variant_nomadik = {
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
.pwrreg_clkgate = true,
- .pwrreg_nopower = true,
};
static struct variant_data variant_ux500 = {
@@ -139,7 +135,6 @@ static struct variant_data variant_ux500 = {
.signal_direction = true,
.pwrreg_clkgate = true,
.busy_detect = true,
- .pwrreg_nopower = true,
};
static struct variant_data variant_ux500v2 = {
@@ -155,7 +150,6 @@ static struct variant_data variant_ux500v2 = {
.signal_direction = true,
.pwrreg_clkgate = true,
.busy_detect = true,
- .pwrreg_nopower = true,
};
static int mmci_card_busy(struct mmc_host *mmc)
@@ -195,21 +189,6 @@ static int mmci_validate_data(struct mmci_host *host,
return 0;
}
-static void mmci_reg_delay(struct mmci_host *host)
-{
- /*
- * According to the spec, at least three feedback clock cycles
- * of max 52 MHz must pass between two writes to the MMCICLOCK reg.
- * Three MCLK clock cycles must pass between two MMCIPOWER reg writes.
- * Worst delay time during card init is at 100 kHz => 30 us.
- * Worst delay time when up and running is at 25 MHz => 120 ns.
- */
- if (host->cclk < 25000000)
- udelay(30);
- else
- ndelay(120);
-}
-
/*
* This must be called with host->lock held
*/
@@ -1285,7 +1264,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
mmci_set_clkreg(host, ios->clock);
mmci_write_pwrreg(host, pwr);
- mmci_reg_delay(host);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1532,6 +1510,23 @@ static int mmci_probe(struct amba_device *dev,
mmc->f_max = min(host->mclk, fmax);
dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+ host->pinctrl = devm_pinctrl_get(&dev->dev);
+ if (IS_ERR(host->pinctrl)) {
+ ret = PTR_ERR(host->pinctrl);
+ goto clk_disable;
+ }
+
+ host->pins_default = pinctrl_lookup_state(host->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+
+ /* enable pins to be muxed in and configured */
+ if (!IS_ERR(host->pins_default)) {
+ ret = pinctrl_select_state(host->pinctrl, host->pins_default);
+ if (ret)
+ dev_warn(&dev->dev, "could not set default pins\n");
+ } else
+ dev_warn(&dev->dev, "could not get default pinstate\n");
+
/* Get regulators and the supported OCR mask */
mmc_regulator_get_supply(mmc);
if (!mmc->ocr_avail)
@@ -1730,67 +1725,41 @@ static int mmci_suspend(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev);
+ int ret = 0;
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
- pm_runtime_get_sync(dev);
- writel(0, host->base + MMCIMASK0);
+
+ ret = mmc_suspend_host(mmc);
+ if (ret == 0) {
+ pm_runtime_get_sync(dev);
+ writel(0, host->base + MMCIMASK0);
+ }
}
- return 0;
+ return ret;
}
static int mmci_resume(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev);
+ int ret = 0;
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
+
writel(MCI_IRQENABLE, host->base + MMCIMASK0);
pm_runtime_put(dev);
+
+ ret = mmc_resume_host(mmc);
}
- return 0;
+ return ret;
}
#endif
#ifdef CONFIG_PM_RUNTIME
-static void mmci_save(struct mmci_host *host)
-{
- unsigned long flags;
-
- if (host->variant->pwrreg_nopower) {
- spin_lock_irqsave(&host->lock, flags);
-
- writel(0, host->base + MMCIMASK0);
- writel(0, host->base + MMCIDATACTRL);
- writel(0, host->base + MMCIPOWER);
- writel(0, host->base + MMCICLOCK);
- mmci_reg_delay(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
-}
-
-static void mmci_restore(struct mmci_host *host)
-{
- unsigned long flags;
-
- if (host->variant->pwrreg_nopower) {
- spin_lock_irqsave(&host->lock, flags);
-
- writel(host->clk_reg, host->base + MMCICLOCK);
- writel(host->datactrl_reg, host->base + MMCIDATACTRL);
- writel(host->pwr_reg, host->base + MMCIPOWER);
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
- mmci_reg_delay(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
- }
-}
-
static int mmci_runtime_suspend(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
@@ -1798,8 +1767,6 @@ static int mmci_runtime_suspend(struct device *dev)
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
- pinctrl_pm_select_sleep_state(dev);
- mmci_save(host);
clk_disable_unprepare(host->clk);
}
@@ -1814,8 +1781,6 @@ static int mmci_runtime_resume(struct device *dev)
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
clk_prepare_enable(host->clk);
- mmci_restore(host);
- pinctrl_pm_select_default_state(dev);
}
return 0;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 168bc72..69080fa 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -200,6 +200,10 @@ struct mmci_host {
struct sg_mapping_iter sg_miter;
unsigned int size;
+ /* pinctrl handles */
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
struct dma_chan *dma_current;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 9405ecd..b900de4 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1416,10 +1416,28 @@ ioremap_free:
}
#ifdef CONFIG_PM
+#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
+static void
+do_resume_work(struct work_struct *work)
+{
+ struct msmsdcc_host *host =
+ container_of(work, struct msmsdcc_host, resume_task);
+ struct mmc_host *mmc = host->mmc;
+
+ if (mmc) {
+ mmc_resume_host(mmc);
+ if (host->stat_irq)
+ enable_irq(host->stat_irq);
+ }
+}
+#endif
+
+
static int
msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
{
struct mmc_host *mmc = mmc_get_drvdata(dev);
+ int rc = 0;
if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc);
@@ -1427,11 +1445,14 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
if (host->stat_irq)
disable_irq(host->stat_irq);
- msmsdcc_writel(host, 0, MMCIMASK0);
+ if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
+ rc = mmc_suspend_host(mmc);
+ if (!rc)
+ msmsdcc_writel(host, 0, MMCIMASK0);
if (host->clks_on)
msmsdcc_disable_clocks(host, 0);
}
- return 0;
+ return rc;
}
static int
@@ -1446,6 +1467,8 @@ msmsdcc_resume(struct platform_device *dev)
msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
+ if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
+ mmc_resume_host(mmc);
if (host->stat_irq)
enable_irq(host->stat_irq);
#if BUSCLK_PWRSAVE
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 45aa220..06c5b0b 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -655,7 +655,7 @@ static const struct mmc_host_ops mvsd_ops = {
.enable_sdio_irq = mvsd_enable_sdio_irq,
};
-static void
+static void __init
mv_conf_mbus_windows(struct mvsd_host *host,
const struct mbus_dram_target_info *dram)
{
@@ -677,7 +677,7 @@ mv_conf_mbus_windows(struct mvsd_host *host,
}
}
-static int mvsd_probe(struct platform_device *pdev)
+static int __init mvsd_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct mmc_host *mmc = NULL;
@@ -775,9 +775,9 @@ static int mvsd_probe(struct platform_device *pdev)
spin_lock_init(&host->lock);
- host->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(host->base)) {
- ret = PTR_ERR(host->base);
+ host->base = devm_request_and_ioremap(&pdev->dev, r);
+ if (!host->base) {
+ ret = -ENOMEM;
goto out;
}
@@ -819,7 +819,7 @@ out:
return ret;
}
-static int mvsd_remove(struct platform_device *pdev)
+static int __exit mvsd_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
@@ -838,6 +838,33 @@ static int mvsd_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int mvsd_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc);
+
+ return ret;
+}
+
+static int mvsd_resume(struct platform_device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+#else
+#define mvsd_suspend NULL
+#define mvsd_resume NULL
+#endif
+
static const struct of_device_id mvsdio_dt_ids[] = {
{ .compatible = "marvell,orion-sdio" },
{ /* sentinel */ }
@@ -845,15 +872,16 @@ static const struct of_device_id mvsdio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
static struct platform_driver mvsd_driver = {
- .probe = mvsd_probe,
- .remove = mvsd_remove,
+ .remove = __exit_p(mvsd_remove),
+ .suspend = mvsd_suspend,
+ .resume = mvsd_resume,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mvsdio_dt_ids,
},
};
-module_platform_driver(mvsd_driver);
+module_platform_driver_probe(mvsd_driver, mvsd_probe);
/* maximum card clock frequency (default 50MHz) */
module_param(maxfreq, int, 0);
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index f7199c8..c174c6a 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -1250,20 +1250,28 @@ static int mxcmci_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
+ int ret = 0;
+ if (mmc)
+ ret = mmc_suspend_host(mmc);
clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg);
- return 0;
+
+ return ret;
}
static int mxcmci_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
+ int ret = 0;
clk_prepare_enable(host->clk_per);
clk_prepare_enable(host->clk_ipg);
- return 0;
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
}
static const struct dev_pm_ops mxcmci_pm_ops = {
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 50fc9df..e1fa3ef 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -724,9 +724,13 @@ static int mxs_mmc_suspend(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp;
+ int ret = 0;
+
+ ret = mmc_suspend_host(mmc);
clk_disable_unprepare(ssp->clk);
- return 0;
+
+ return ret;
}
static int mxs_mmc_resume(struct device *dev)
@@ -734,9 +738,13 @@ static int mxs_mmc_resume(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp;
+ int ret = 0;
clk_prepare_enable(ssp->clk);
- return 0;
+
+ ret = mmc_resume_host(mmc);
+
+ return ret;
}
static const struct dev_pm_ops mxs_mmc_pm_ops = {
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 98b6b6e..b94f38e 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -22,7 +22,6 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
-#include <linux/of.h>
#include <linux/omap-dma.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -91,6 +90,17 @@
#define OMAP_MMC_CMDTYPE_AC 2
#define OMAP_MMC_CMDTYPE_ADTC 3
+#define OMAP_DMA_MMC_TX 21
+#define OMAP_DMA_MMC_RX 22
+#define OMAP_DMA_MMC2_TX 54
+#define OMAP_DMA_MMC2_RX 55
+
+#define OMAP24XX_DMA_MMC2_TX 47
+#define OMAP24XX_DMA_MMC2_RX 48
+#define OMAP24XX_DMA_MMC1_TX 61
+#define OMAP24XX_DMA_MMC1_RX 62
+
+
#define DRIVER_NAME "mmci-omap"
/* Specifies how often in millisecs to poll for card status changes
@@ -118,6 +128,7 @@ struct mmc_omap_slot {
struct mmc_omap_host {
int initialized;
+ int suspended;
struct mmc_request * mrq;
struct mmc_command * cmd;
struct mmc_data * data;
@@ -1320,7 +1331,7 @@ static int mmc_omap_probe(struct platform_device *pdev)
struct mmc_omap_host *host = NULL;
struct resource *res;
dma_cap_mask_t mask;
- unsigned sig = 0;
+ unsigned sig;
int i, ret = 0;
int irq;
@@ -1330,7 +1341,7 @@ static int mmc_omap_probe(struct platform_device *pdev)
}
if (pdata->nr_slots == 0) {
dev_err(&pdev->dev, "no slots\n");
- return -EPROBE_DEFER;
+ return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1397,20 +1408,19 @@ static int mmc_omap_probe(struct platform_device *pdev)
host->dma_tx_burst = -1;
host->dma_rx_burst = -1;
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (res)
- sig = res->start;
- host->dma_tx = dma_request_slave_channel_compat(mask,
- omap_dma_filter_fn, &sig, &pdev->dev, "tx");
+ if (mmc_omap2())
+ sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX;
+ else
+ sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX;
+ host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
if (!host->dma_tx)
dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n",
sig);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (res)
- sig = res->start;
- host->dma_rx = dma_request_slave_channel_compat(mask,
- omap_dma_filter_fn, &sig, &pdev->dev, "rx");
+ if (mmc_omap2())
+ sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX;
+ else
+ sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX;
+ host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
if (!host->dma_rx)
dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n",
sig);
@@ -1503,20 +1513,64 @@ static int mmc_omap_remove(struct platform_device *pdev)
return 0;
}
-#if IS_BUILTIN(CONFIG_OF)
-static const struct of_device_id mmc_omap_match[] = {
- { .compatible = "ti,omap2420-mmc", },
- { },
-};
+#ifdef CONFIG_PM
+static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int i, ret = 0;
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ if (host == NULL || host->suspended)
+ return 0;
+
+ for (i = 0; i < host->nr_slots; i++) {
+ struct mmc_omap_slot *slot;
+
+ slot = host->slots[i];
+ ret = mmc_suspend_host(slot->mmc);
+ if (ret < 0) {
+ while (--i >= 0) {
+ slot = host->slots[i];
+ mmc_resume_host(slot->mmc);
+ }
+ return ret;
+ }
+ }
+ host->suspended = 1;
+ return 0;
+}
+
+static int mmc_omap_resume(struct platform_device *pdev)
+{
+ int i, ret = 0;
+ struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+ if (host == NULL || !host->suspended)
+ return 0;
+
+ for (i = 0; i < host->nr_slots; i++) {
+ struct mmc_omap_slot *slot;
+ slot = host->slots[i];
+ ret = mmc_resume_host(slot->mmc);
+ if (ret < 0)
+ return ret;
+
+ host->suspended = 0;
+ }
+ return 0;
+}
+#else
+#define mmc_omap_suspend NULL
+#define mmc_omap_resume NULL
#endif
static struct platform_driver mmc_omap_driver = {
.probe = mmc_omap_probe,
.remove = mmc_omap_remove,
+ .suspend = mmc_omap_suspend,
+ .resume = mmc_omap_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(mmc_omap_match),
},
};
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dbd32ad..6ac63df 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -75,7 +75,6 @@
#define ICE 0x1
#define ICS 0x2
#define CEN (1 << 2)
-#define CLKD_MAX 0x3FF /* max clock divisor: 1023 */
#define CLKD_MASK 0x0000FFC0
#define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000
@@ -120,8 +119,7 @@
BRR_EN | BWR_EN | TC_EN | CC_EN)
#define MMC_AUTOSUSPEND_DELAY 100
-#define MMC_TIMEOUT_MS 20 /* 20 mSec */
-#define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */
+#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MIN_CLOCK 400000
#define OMAP_MMC_MAX_CLOCK 52000000
#define DRIVER_NAME "omap_hsmmc"
@@ -173,10 +171,6 @@ struct omap_hsmmc_host {
unsigned char bus_mode;
unsigned char power_mode;
int suspended;
- u32 con;
- u32 hctl;
- u32 sysctl;
- u32 capa;
int irq;
int use_dma, dma_ch;
struct dma_chan *tx_chan;
@@ -189,6 +183,7 @@ struct omap_hsmmc_host {
int use_reg;
int req_in_progress;
struct omap_hsmmc_next next_data;
+
struct omap_mmc_platform_data *pdata;
};
@@ -498,8 +493,8 @@ static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
if (ios->clock) {
dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
- if (dsor > CLKD_MAX)
- dsor = CLKD_MAX;
+ if (dsor > 250)
+ dsor = 250;
}
return dsor;
@@ -602,19 +597,24 @@ static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
{
struct mmc_ios *ios = &host->mmc->ios;
+ struct omap_mmc_platform_data *pdata = host->pdata;
+ int context_loss = 0;
u32 hctl, capa;
unsigned long timeout;
- if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
- return 1;
+ if (pdata->get_context_loss_count) {
+ context_loss = pdata->get_context_loss_count(host->dev);
+ if (context_loss < 0)
+ return 1;
+ }
- if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
- host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
- host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
- host->capa == OMAP_HSMMC_READ(host->base, CAPA))
- return 0;
+ dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
+ context_loss == host->context_loss ? "not " : "");
+ if (host->context_loss == context_loss)
+ return 1;
- host->context_loss++;
+ 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 &&
@@ -655,8 +655,9 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
omap_hsmmc_set_bus_mode(host);
out:
- dev_dbg(mmc_dev(host->mmc), "context is restored: restore count %d\n",
- host->context_loss);
+ host->context_loss = context_loss;
+
+ dev_dbg(mmc_dev(host->mmc), "context is restored\n");
return 0;
}
@@ -665,10 +666,15 @@ out:
*/
static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
{
- host->con = OMAP_HSMMC_READ(host->base, CON);
- host->hctl = OMAP_HSMMC_READ(host->base, HCTL);
- host->sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
- host->capa = OMAP_HSMMC_READ(host->base, CAPA);
+ struct omap_mmc_platform_data *pdata = host->pdata;
+ int context_loss;
+
+ if (pdata->get_context_loss_count) {
+ context_loss = pdata->get_context_loss_count(host->dev);
+ if (context_loss < 0)
+ return;
+ host->context_loss = context_loss;
+ }
}
#else
@@ -969,7 +975,8 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
unsigned long bit)
{
unsigned long i = 0;
- unsigned long limit = MMC_TIMEOUT_US;
+ unsigned long limit = (loops_per_jiffy *
+ msecs_to_jiffies(MMC_TIMEOUT_MS));
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
@@ -981,13 +988,13 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
- udelay(1);
+ cpu_relax();
}
i = 0;
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
(i++ < limit))
- udelay(1);
+ cpu_relax();
if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
dev_err(mmc_dev(host->mmc),
@@ -1171,6 +1178,9 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
struct omap_mmc_slot_data *slot = &mmc_slot(host);
int carddetect;
+ if (host->suspended)
+ return IRQ_HANDLED;
+
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (slot->card_detect)
@@ -1625,9 +1635,18 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
{
struct mmc_host *mmc = s->private;
struct omap_hsmmc_host *host = mmc_priv(mmc);
+ int context_loss = 0;
+
+ if (host->pdata->get_context_loss_count)
+ context_loss = host->pdata->get_context_loss_count(host->dev);
- seq_printf(s, "mmc%d:\n ctx_loss:\t%d\n\nregs:\n",
- mmc->index, host->context_loss);
+ seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n",
+ mmc->index, host->context_loss, context_loss);
+
+ if (host->suspended) {
+ seq_printf(s, "host suspended, can't read registers\n");
+ return 0;
+ }
pm_runtime_get_sync(host->dev);
@@ -1819,6 +1838,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->ops = &omap_hsmmc_ops;
+ /*
+ * If regulator_disable can only put vcc_aux to sleep then there is
+ * no off state.
+ */
+ if (mmc_slot(host).vcc_aux_disable_is_sleep)
+ mmc_slot(host).no_off = 1;
+
mmc->f_min = OMAP_MMC_MIN_CLOCK;
if (pdata->max_freq > 0)
@@ -1848,7 +1874,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host);
/* This can be removed once we support PBIAS with DT */
- if (host->dev->of_node && res->start == 0x4809c000)
+ if (host->dev->of_node && host->mapbase == 0x4809c000)
host->pbias_disable = 1;
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
@@ -2093,12 +2119,23 @@ static void omap_hsmmc_complete(struct device *dev)
static int omap_hsmmc_suspend(struct device *dev)
{
+ int ret = 0;
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (!host)
return 0;
+ if (host && host->suspended)
+ return 0;
+
pm_runtime_get_sync(host->dev);
+ host->suspended = 1;
+ ret = mmc_suspend_host(host->mmc);
+
+ if (ret) {
+ host->suspended = 0;
+ goto err;
+ }
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
omap_hsmmc_disable_irq(host);
@@ -2108,19 +2145,23 @@ static int omap_hsmmc_suspend(struct device *dev)
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
-
+err:
pm_runtime_put_sync(host->dev);
- return 0;
+ return ret;
}
/* Routine to resume the MMC device */
static int omap_hsmmc_resume(struct device *dev)
{
+ int ret = 0;
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (!host)
return 0;
+ if (host && !host->suspended)
+ return 0;
+
pm_runtime_get_sync(host->dev);
if (host->dbclk)
@@ -2131,9 +2172,16 @@ static int omap_hsmmc_resume(struct device *dev)
omap_hsmmc_protect_card(host);
+ /* Notify the core to resume the host */
+ ret = mmc_resume_host(host->mmc);
+ if (ret == 0)
+ host->suspended = 0;
+
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
- return 0;
+
+ return ret;
+
}
#else
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 32fe113..1956a3d 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -880,6 +880,35 @@ static int pxamci_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int pxamci_suspend(struct device *dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc);
+
+ return ret;
+}
+
+static int pxamci_resume(struct device *dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+
+static const struct dev_pm_ops pxamci_pm_ops = {
+ .suspend = pxamci_suspend,
+ .resume = pxamci_resume,
+};
+#endif
+
static struct platform_driver pxamci_driver = {
.probe = pxamci_probe,
.remove = pxamci_remove,
@@ -887,6 +916,9 @@ static struct platform_driver pxamci_driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pxa_mmc_dt_ids),
+#ifdef CONFIG_PM
+ .pm = &pxamci_pm_ops,
+#endif
},
};
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index c46feda..375a880e 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -364,7 +364,7 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
struct mmc_host *mmc = host->mmc;
struct mmc_card *card = mmc->card;
struct mmc_data *data = mrq->data;
- int uhs = mmc_card_uhs(card);
+ int uhs = mmc_sd_card_uhs(card);
int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
u8 cfg2, trans_mode;
int err;
@@ -1197,6 +1197,37 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.execute_tuning = sdmmc_execute_tuning,
};
+#ifdef CONFIG_PM
+static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = host->mmc;
+ int err;
+
+ dev_dbg(sdmmc_dev(host), "--> %s\n", __func__);
+
+ err = mmc_suspend_host(mmc);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int rtsx_pci_sdmmc_resume(struct platform_device *pdev)
+{
+ struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = host->mmc;
+
+ dev_dbg(sdmmc_dev(host), "--> %s\n", __func__);
+
+ return mmc_resume_host(mmc);
+}
+#else /* CONFIG_PM */
+#define rtsx_pci_sdmmc_suspend NULL
+#define rtsx_pci_sdmmc_resume NULL
+#endif /* CONFIG_PM */
+
static void init_extra_caps(struct realtek_pci_sdmmc *host)
{
struct mmc_host *mmc = host->mmc;
@@ -1336,6 +1367,8 @@ static struct platform_driver rtsx_pci_sdmmc_driver = {
.probe = rtsx_pci_sdmmc_drv_probe,
.remove = rtsx_pci_sdmmc_drv_remove,
.id_table = rtsx_pci_sdmmc_ids,
+ .suspend = rtsx_pci_sdmmc_suspend,
+ .resume = rtsx_pci_sdmmc_resume,
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME_RTSX_PCI_SDMMC,
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 2fce5ea..8d6794c 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1949,10 +1949,39 @@ static struct platform_device_id s3cmci_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
+
+#ifdef CONFIG_PM
+
+static int s3cmci_suspend(struct device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
+
+ return mmc_suspend_host(mmc);
+}
+
+static int s3cmci_resume(struct device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
+
+ return mmc_resume_host(mmc);
+}
+
+static const struct dev_pm_ops s3cmci_pm = {
+ .suspend = s3cmci_suspend,
+ .resume = s3cmci_resume,
+};
+
+#define s3cmci_pm_ops &s3cmci_pm
+#else /* CONFIG_PM */
+#define s3cmci_pm_ops NULL
+#endif /* CONFIG_PM */
+
+
static struct platform_driver s3cmci_driver = {
.driver = {
.name = "s3c-sdi",
.owner = THIS_MODULE,
+ .pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids,
.probe = s3cmci_probe,
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index ef19874..cdd4ce0 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -310,9 +310,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
dma_mask = DMA_BIT_MASK(32);
}
- err = dma_coerce_mask_and_coherent(dev, dma_mask);
- if (err)
- goto err_free;
+ dev->dma_mask = &dev->coherent_dma_mask;
+ dev->coherent_dma_mask = dma_mask;
}
if (c->slot) {
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 7a190fe..85472d3 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -316,7 +316,19 @@ err_pltfm_free:
static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
{
- return sdhci_pltfm_unregister(pdev);
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ int dead;
+ u32 scratch;
+
+ dead = 0;
+ scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+ if (scratch == (u32)-1)
+ dead = 1;
+ sdhci_remove_host(host, dead);
+
+ sdhci_free_host(host);
+
+ return 0;
}
static struct platform_driver sdhci_bcm_kona_driver = {
diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
index f6d8d67..36fa2df 100644
--- a/drivers/mmc/host/sdhci-bcm2835.c
+++ b/drivers/mmc/host/sdhci-bcm2835.c
@@ -178,7 +178,13 @@ err:
static int bcm2835_sdhci_remove(struct platform_device *pdev)
{
- return sdhci_pltfm_unregister(pdev);
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+ sdhci_remove_host(host, dead);
+ sdhci_pltfm_free(pdev);
+
+ return 0;
}
static const struct of_device_id bcm2835_sdhci_of_match[] = {
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 461a4c3..abc8cf0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -34,40 +34,12 @@
/* VENDOR SPEC register */
#define ESDHC_VENDOR_SPEC 0xc0
#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
-#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
-#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
#define ESDHC_WTMK_LVL 0x44
#define ESDHC_MIX_CTRL 0x48
-#define ESDHC_MIX_CTRL_DDREN (1 << 3)
#define ESDHC_MIX_CTRL_AC23EN (1 << 7)
-#define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22)
-#define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23)
-#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
/* Bits 3 and 6 are not SDHCI standard definitions */
#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
-/* dll control register */
-#define ESDHC_DLL_CTRL 0x60
-#define ESDHC_DLL_OVERRIDE_VAL_SHIFT 9
-#define ESDHC_DLL_OVERRIDE_EN_SHIFT 8
-
-/* tune control register */
-#define ESDHC_TUNE_CTRL_STATUS 0x68
-#define ESDHC_TUNE_CTRL_STEP 1
-#define ESDHC_TUNE_CTRL_MIN 0
-#define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1)
-
-#define ESDHC_TUNING_CTRL 0xcc
-#define ESDHC_STD_TUNING_EN (1 << 24)
-/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
-#define ESDHC_TUNING_START_TAP 0x1
-
-#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
-
-/* pinctrl state */
-#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
-#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
-
/*
* Our interpretation of the SDHCI_HOST_CONTROL register
*/
@@ -94,60 +66,21 @@
* As a result, the TC flag is not asserted and SW received timeout
* exeception. Bit1 of Vendor Spec registor is used to fix it.
*/
-#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
-/*
- * The flag enables the workaround for ESDHC errata ENGcm07207 which
- * affects i.MX25 and i.MX35.
- */
-#define ESDHC_FLAG_ENGCM07207 BIT(2)
-/*
- * The flag tells that the ESDHC controller is an USDHC block that is
- * integrated on the i.MX6 series.
- */
-#define ESDHC_FLAG_USDHC BIT(3)
-/* The IP supports manual tuning process */
-#define ESDHC_FLAG_MAN_TUNING BIT(4)
-/* The IP supports standard tuning process */
-#define ESDHC_FLAG_STD_TUNING BIT(5)
-/* The IP has SDHCI_CAPABILITIES_1 register */
-#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
-
-struct esdhc_soc_data {
- u32 flags;
-};
-
-static struct esdhc_soc_data esdhc_imx25_data = {
- .flags = ESDHC_FLAG_ENGCM07207,
-};
-
-static struct esdhc_soc_data esdhc_imx35_data = {
- .flags = ESDHC_FLAG_ENGCM07207,
-};
-
-static struct esdhc_soc_data esdhc_imx51_data = {
- .flags = 0,
-};
-
-static struct esdhc_soc_data esdhc_imx53_data = {
- .flags = ESDHC_FLAG_MULTIBLK_NO_INT,
-};
-
-static struct esdhc_soc_data usdhc_imx6q_data = {
- .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING,
-};
-
-static struct esdhc_soc_data usdhc_imx6sl_data = {
- .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
- | ESDHC_FLAG_HAVE_CAP1,
+#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
+
+enum imx_esdhc_type {
+ IMX25_ESDHC,
+ IMX35_ESDHC,
+ IMX51_ESDHC,
+ IMX53_ESDHC,
+ IMX6Q_USDHC,
};
struct pltfm_imx_data {
+ int flags;
u32 scratchpad;
+ enum imx_esdhc_type devtype;
struct pinctrl *pinctrl;
- struct pinctrl_state *pins_default;
- struct pinctrl_state *pins_100mhz;
- struct pinctrl_state *pins_200mhz;
- const struct esdhc_soc_data *socdata;
struct esdhc_platform_data boarddata;
struct clk *clk_ipg;
struct clk *clk_ahb;
@@ -157,20 +90,25 @@ struct pltfm_imx_data {
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
- u32 uhs_mode;
- u32 is_ddr;
+
};
static struct platform_device_id imx_esdhc_devtype[] = {
{
.name = "sdhci-esdhc-imx25",
- .driver_data = (kernel_ulong_t) &esdhc_imx25_data,
+ .driver_data = IMX25_ESDHC,
}, {
.name = "sdhci-esdhc-imx35",
- .driver_data = (kernel_ulong_t) &esdhc_imx35_data,
+ .driver_data = IMX35_ESDHC,
}, {
.name = "sdhci-esdhc-imx51",
- .driver_data = (kernel_ulong_t) &esdhc_imx51_data,
+ .driver_data = IMX51_ESDHC,
+ }, {
+ .name = "sdhci-esdhc-imx53",
+ .driver_data = IMX53_ESDHC,
+ }, {
+ .name = "sdhci-usdhc-imx6q",
+ .driver_data = IMX6Q_USDHC,
}, {
/* sentinel */
}
@@ -178,34 +116,38 @@ static struct platform_device_id imx_esdhc_devtype[] = {
MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
static const struct of_device_id imx_esdhc_dt_ids[] = {
- { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
- { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
- { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, },
- { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, },
- { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
- { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
+ { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
+ { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
+ { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
+ { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
+ { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
{
- return data->socdata == &esdhc_imx25_data;
+ return data->devtype == IMX25_ESDHC;
}
-static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
+static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
{
- return data->socdata == &esdhc_imx53_data;
+ return data->devtype == IMX35_ESDHC;
}
-static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
+static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
+{
+ return data->devtype == IMX51_ESDHC;
+}
+
+static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
{
- return data->socdata == &usdhc_imx6q_data;
+ return data->devtype == IMX53_ESDHC;
}
-static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
+static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
{
- return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
+ return data->devtype == IMX6Q_USDHC;
}
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
@@ -222,21 +164,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
struct pltfm_imx_data *imx_data = pltfm_host->priv;
u32 val = readl(host->ioaddr + reg);
- if (unlikely(reg == SDHCI_PRESENT_STATE)) {
- u32 fsl_prss = val;
- /* save the least 20 bits */
- val = fsl_prss & 0x000FFFFF;
- /* move dat[0-3] bits */
- val |= (fsl_prss & 0x0F000000) >> 4;
- /* move cmd line bit */
- val |= (fsl_prss & 0x00800000) << 1;
- }
-
if (unlikely(reg == SDHCI_CAPABILITIES)) {
- /* ignore bit[0-15] as it stores cap_1 register val for mx6sl */
- if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
- val &= 0xffff0000;
-
/* In FSL esdhc IC module, only bit20 is used to indicate the
* ADMA2 capability of esdhc, but this bit is messed up on
* some SOCs (e.g. on MX25, MX35 this bit is set, but they
@@ -250,25 +178,6 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
}
}
- if (unlikely(reg == SDHCI_CAPABILITIES_1)) {
- if (esdhc_is_usdhc(imx_data)) {
- if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
- val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
- else
- /* imx6q/dl does not have cap_1 register, fake one */
- val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
- | SDHCI_SUPPORT_SDR50
- | SDHCI_USE_SDR50_TUNING;
- }
- }
-
- if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) {
- val = 0;
- val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
- val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
- val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT;
- }
-
if (unlikely(reg == SDHCI_INT_STATUS)) {
if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) {
val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
@@ -315,7 +224,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
}
}
- if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+ if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
&& (reg == SDHCI_INT_STATUS)
&& (val & SDHCI_INT_DATA_END))) {
u32 v;
@@ -347,12 +256,10 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
- u16 ret = 0;
- u32 val;
if (unlikely(reg == SDHCI_HOST_VERSION)) {
reg ^= 2;
- if (esdhc_is_usdhc(imx_data)) {
+ if (is_imx6q_usdhc(imx_data)) {
/*
* The usdhc register returns a wrong host version.
* Correct it here.
@@ -361,30 +268,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
}
}
- if (unlikely(reg == SDHCI_HOST_CONTROL2)) {
- val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- if (val & ESDHC_VENDOR_SPEC_VSELECT)
- ret |= SDHCI_CTRL_VDD_180;
-
- if (esdhc_is_usdhc(imx_data)) {
- if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
- val = readl(host->ioaddr + ESDHC_MIX_CTRL);
- else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
- /* the std tuning bits is in ACMD12_ERR for imx6sl */
- val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
- }
-
- if (val & ESDHC_MIX_CTRL_EXE_TUNE)
- ret |= SDHCI_CTRL_EXEC_TUNING;
- if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
- ret |= SDHCI_CTRL_TUNED_CLK;
-
- ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
- ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
-
- return ret;
- }
-
return readw(host->ioaddr + reg);
}
@@ -392,59 +275,10 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
- u32 new_val = 0;
switch (reg) {
- case SDHCI_CLOCK_CONTROL:
- new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- if (val & SDHCI_CLOCK_CARD_EN)
- new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
- else
- new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
- writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
- return;
- case SDHCI_HOST_CONTROL2:
- new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- if (val & SDHCI_CTRL_VDD_180)
- new_val |= ESDHC_VENDOR_SPEC_VSELECT;
- else
- new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
- writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
- imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
- if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
- new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
- if (val & SDHCI_CTRL_TUNED_CLK)
- new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
- else
- new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
- writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
- } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
- u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
- u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
- new_val = readl(host->ioaddr + ESDHC_TUNING_CTRL);
- if (val & SDHCI_CTRL_EXEC_TUNING) {
- new_val |= ESDHC_STD_TUNING_EN |
- ESDHC_TUNING_START_TAP;
- v |= ESDHC_MIX_CTRL_EXE_TUNE;
- m |= ESDHC_MIX_CTRL_FBCLK_SEL;
- } else {
- new_val &= ~ESDHC_STD_TUNING_EN;
- v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
- m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
- }
-
- if (val & SDHCI_CTRL_TUNED_CLK)
- v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
- else
- v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
-
- writel(new_val, host->ioaddr + ESDHC_TUNING_CTRL);
- writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
- writel(m, host->ioaddr + ESDHC_MIX_CTRL);
- }
- return;
case SDHCI_TRANSFER_MODE:
- if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+ if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
&& (host->cmd->data->blocks > 1)
&& (host->cmd->data->flags & MMC_DATA_READ)) {
@@ -454,7 +288,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
}
- if (esdhc_is_usdhc(imx_data)) {
+ if (is_imx6q_usdhc(imx_data)) {
u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
/* Swap AC23 bit */
if (val & SDHCI_TRNS_AUTO_CMD23) {
@@ -476,10 +310,10 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
val |= SDHCI_CMD_ABORTCMD;
if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
- (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+ (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
- if (esdhc_is_usdhc(imx_data))
+ if (is_imx6q_usdhc(imx_data))
writel(val << 16,
host->ioaddr + SDHCI_TRANSFER_MODE);
else
@@ -545,10 +379,8 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
* The reset on usdhc fails to clear MIX_CTRL register.
* Do it manually here.
*/
- if (esdhc_is_usdhc(imx_data)) {
+ if (is_imx6q_usdhc(imx_data))
writel(0, host->ioaddr + ESDHC_MIX_CTRL);
- imx_data->is_ddr = 0;
- }
}
}
@@ -577,60 +409,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- unsigned int host_clock = clk_get_rate(pltfm_host->clk);
- int pre_div = 2;
- int div = 1;
- u32 temp, val;
-
- if (clock == 0) {
- if (esdhc_is_usdhc(imx_data)) {
- val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
- host->ioaddr + ESDHC_VENDOR_SPEC);
- }
- goto out;
- }
-
- if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
- pre_div = 1;
-
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | ESDHC_CLOCK_MASK);
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
- while (host_clock / pre_div / 16 > clock && pre_div < 256)
- pre_div *= 2;
-
- while (host_clock / pre_div / div > clock && div < 16)
- div++;
- host->mmc->actual_clock = host_clock / pre_div / div;
- dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
- clock, host->mmc->actual_clock);
-
- if (imx_data->is_ddr)
- pre_div >>= 2;
- else
- pre_div >>= 1;
- div--;
-
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | (div << ESDHC_DIVIDER_SHIFT)
- | (pre_div << ESDHC_PREDIV_SHIFT));
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
- if (esdhc_is_usdhc(imx_data)) {
- val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
- host->ioaddr + ESDHC_VENDOR_SPEC);
- }
-
- mdelay(1);
-out:
- host->clock = clock;
+ esdhc_set_clock(host, clock, clk_get_rate(pltfm_host->clk));
}
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
@@ -674,192 +454,7 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
return 0;
}
-static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
-{
- u32 reg;
-
- /* FIXME: delay a bit for card to be ready for next tuning due to errors */
- mdelay(1);
-
- reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
- reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
- ESDHC_MIX_CTRL_FBCLK_SEL;
- writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
- writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
- dev_dbg(mmc_dev(host->mmc),
- "tunning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
- val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
-}
-
-static void esdhc_request_done(struct mmc_request *mrq)
-{
- complete(&mrq->completion);
-}
-
-static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
-{
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
- char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
-
- mrq.cmd = &cmd;
- mrq.cmd->mrq = &mrq;
- mrq.data = &data;
- mrq.data->mrq = &mrq;
- mrq.cmd->data = mrq.data;
-
- mrq.done = esdhc_request_done;
- init_completion(&(mrq.completion));
-
- disable_irq(host->irq);
- spin_lock(&host->lock);
- host->mrq = &mrq;
-
- sdhci_send_command(host, mrq.cmd);
-
- spin_unlock(&host->lock);
- enable_irq(host->irq);
-
- wait_for_completion(&mrq.completion);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
-static void esdhc_post_tuning(struct sdhci_host *host)
-{
- u32 reg;
-
- reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
- reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
- writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
-}
-
-static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
-{
- int min, max, avg, ret;
-
- /* find the mininum delay first which can pass tuning */
- min = ESDHC_TUNE_CTRL_MIN;
- while (min < ESDHC_TUNE_CTRL_MAX) {
- esdhc_prepare_tuning(host, min);
- if (!esdhc_send_tuning_cmd(host, opcode))
- break;
- min += ESDHC_TUNE_CTRL_STEP;
- }
-
- /* find the maxinum delay which can not pass tuning */
- max = min + ESDHC_TUNE_CTRL_STEP;
- while (max < ESDHC_TUNE_CTRL_MAX) {
- esdhc_prepare_tuning(host, max);
- if (esdhc_send_tuning_cmd(host, opcode)) {
- max -= ESDHC_TUNE_CTRL_STEP;
- break;
- }
- max += ESDHC_TUNE_CTRL_STEP;
- }
-
- /* use average delay to get the best timing */
- avg = (min + max) / 2;
- esdhc_prepare_tuning(host, avg);
- ret = esdhc_send_tuning_cmd(host, opcode);
- esdhc_post_tuning(host);
-
- dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
- ret ? "failed" : "passed", avg, ret);
-
- return ret;
-}
-
-static int esdhc_change_pinstate(struct sdhci_host *host,
- unsigned int uhs)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct pinctrl_state *pinctrl;
-
- dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
-
- if (IS_ERR(imx_data->pinctrl) ||
- IS_ERR(imx_data->pins_default) ||
- IS_ERR(imx_data->pins_100mhz) ||
- IS_ERR(imx_data->pins_200mhz))
- return -EINVAL;
-
- switch (uhs) {
- case MMC_TIMING_UHS_SDR50:
- pinctrl = imx_data->pins_100mhz;
- break;
- case MMC_TIMING_UHS_SDR104:
- pinctrl = imx_data->pins_200mhz;
- break;
- default:
- /* back to default state for other legacy timing */
- pinctrl = imx_data->pins_default;
- }
-
- return pinctrl_select_state(imx_data->pinctrl, pinctrl);
-}
-
-static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
-
- switch (uhs) {
- case MMC_TIMING_UHS_SDR12:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
- break;
- case MMC_TIMING_UHS_SDR25:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
- break;
- case MMC_TIMING_UHS_SDR50:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
- break;
- case MMC_TIMING_UHS_SDR104:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
- break;
- case MMC_TIMING_UHS_DDR50:
- imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
- writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
- ESDHC_MIX_CTRL_DDREN,
- host->ioaddr + ESDHC_MIX_CTRL);
- imx_data->is_ddr = 1;
- if (boarddata->delay_line) {
- u32 v;
- v = boarddata->delay_line <<
- ESDHC_DLL_OVERRIDE_VAL_SHIFT |
- (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
- if (is_imx53_esdhc(imx_data))
- v <<= 1;
- writel(v, host->ioaddr + ESDHC_DLL_CTRL);
- }
- break;
- }
-
- return esdhc_change_pinstate(host, uhs);
-}
-
-static struct sdhci_ops sdhci_esdhc_ops = {
+static const struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le,
.write_l = esdhc_writel_le,
@@ -870,7 +465,6 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_min_clock = esdhc_pltfm_get_min_clock,
.get_ro = esdhc_pltfm_get_ro,
.platform_bus_width = esdhc_pltfm_bus_width,
- .set_uhs_signaling = esdhc_set_uhs_signaling,
};
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -912,14 +506,6 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
of_property_read_u32(np, "max-frequency", &boarddata->f_max);
- if (of_find_property(np, "no-1-8-v", NULL))
- boarddata->support_vsel = false;
- else
- boarddata->support_vsel = true;
-
- if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
- boarddata->delay_line = 0;
-
return 0;
}
#else
@@ -953,8 +539,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
goto free_sdhci;
}
- imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
- pdev->id_entry->driver_data;
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ imx_data->devtype = pdev->id_entry->driver_data;
pltfm_host->priv = imx_data;
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
@@ -981,39 +568,29 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_prepare_enable(imx_data->clk_ipg);
clk_prepare_enable(imx_data->clk_ahb);
- imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
+ imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
goto disable_clk;
}
- imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
- PINCTRL_STATE_DEFAULT);
- if (IS_ERR(imx_data->pins_default)) {
- err = PTR_ERR(imx_data->pins_default);
- dev_err(mmc_dev(host->mmc), "could not get default state\n");
- goto disable_clk;
- }
-
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
- if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
+ if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
| SDHCI_QUIRK_BROKEN_ADMA;
+ if (is_imx53_esdhc(imx_data))
+ imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
+
/*
* The imx6q ROM code will change the default watermark level setting
* to something insane. Change it back here.
*/
- if (esdhc_is_usdhc(imx_data)) {
+ if (is_imx6q_usdhc(imx_data))
writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
- host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
- }
- if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
- sdhci_esdhc_ops.platform_execute_tuning =
- esdhc_executing_tuning;
boarddata = &imx_data->boarddata;
if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
if (!host->mmc->parent->platform_data) {
@@ -1073,23 +650,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
break;
}
- /* sdr50 and sdr104 needs work on 1.8v signal voltage */
- if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) {
- imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
- ESDHC_PINCTRL_STATE_100MHZ);
- imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
- ESDHC_PINCTRL_STATE_200MHZ);
- if (IS_ERR(imx_data->pins_100mhz) ||
- IS_ERR(imx_data->pins_200mhz)) {
- dev_warn(mmc_dev(host->mmc),
- "could not get ultra high speed state, work on normal mode\n");
- /* fall back to not support uhs by specify no 1.8v quirk */
- host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
- }
- } else {
- host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
- }
-
err = sdhci_add_host(host);
if (err)
goto disable_clk;
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 3abd1e7..7725160 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -57,4 +57,58 @@
#define ESDHC_HOST_CONTROL_RES 0x01
#define ESDHC_VOL_SEL 0x04
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
+ unsigned int host_clock)
+{
+ u32 timeout;
+ int pre_div = 2;
+ int div = 1;
+ u32 temp;
+
+ if (clock == 0)
+ goto out;
+
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+ temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+ | ESDHC_CLOCK_MASK);
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+ while (host_clock / pre_div / 16 > clock && pre_div < 256)
+ pre_div *= 2;
+
+ while (host_clock / pre_div / div > clock && div < 16)
+ div++;
+
+ dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+ clock, host_clock / pre_div / div);
+
+ pre_div >>= 1;
+ div--;
+
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+ temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+ | (div << ESDHC_DIVIDER_SHIFT)
+ | (pre_div << ESDHC_PREDIV_SHIFT));
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+ /* Wait max 20 ms */
+ timeout = 20;
+ while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & ESDHC_CLK_STABLE)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never "
+ "stabilised.\n", mmc_hostname(host->mmc));
+ return;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ temp |= ESDHC_CLOCK_CRDEN;
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+ mdelay(1);
+out:
+ host->clock = clock;
+}
+
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 3af4587..0f9f36b 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -336,14 +336,6 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{
- u32 timeout;
- int pre_div = 2;
- int div = 1;
- u32 temp;
-
- if (clock == 0)
- goto out;
-
/* Workaround to reduce the clock frequency for p1010 esdhc */
if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
if (clock > 20000000)
@@ -352,46 +344,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
clock -= 5000000;
}
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | ESDHC_CLOCK_MASK | ESDHC_CLOCK_CRDEN);
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
- while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
- pre_div *= 2;
-
- while (host->max_clk / pre_div / div > clock && div < 16)
- div++;
-
- dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
- clock, host->max_clk / pre_div / div);
-
- pre_div >>= 1;
- div--;
-
- temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | (div << ESDHC_DIVIDER_SHIFT)
- | (pre_div << ESDHC_PREDIV_SHIFT));
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
- /* Wait max 20 ms */
- timeout = 20;
- while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & ESDHC_CLK_STABLE)) {
- if (timeout == 0) {
- pr_err("%s: Internal clock never "
- "stabilised.\n", mmc_hostname(host->mmc));
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- temp |= ESDHC_CLOCK_CRDEN;
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- mdelay(1);
-out:
- host->clock = clock;
+ /* Set the clock */
+ esdhc_set_clock(host, clock, host->max_clk);
}
#ifdef CONFIG_PM
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 8f75381..d7d6bc8 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -37,12 +37,6 @@
#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50
-#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190
-#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9
-#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa
-#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb
-#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5
-#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6
/*
* PCI registers
@@ -362,28 +356,6 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.allow_runtime_pm = true,
};
-/* Define Host controllers for Intel Merrifield platform */
-#define INTEL_MRFL_EMMC_0 0
-#define INTEL_MRFL_EMMC_1 1
-
-static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
-{
- if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) &&
- (PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1))
- /* SD support is not ready yet */
- return -ENODEV;
-
- slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
- MMC_CAP_1_8V_DDR;
-
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
- .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .probe_slot = intel_mrfl_mmc_probe_slot,
-};
-
/* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE
@@ -967,54 +939,6 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
},
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_EMMC0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_EMMC1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRFL_MMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
- },
{
.vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bfb3d8e..c76dab0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -49,6 +49,7 @@ static unsigned int debug_quirks2;
static void sdhci_finish_data(struct sdhci_host *);
+static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_tuning_timer(unsigned long data);
@@ -989,7 +990,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
tasklet_schedule(&host->finish_tasklet);
}
-void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{
int flags;
u32 mask;
@@ -1068,7 +1069,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
-EXPORT_SYMBOL_GPL(sdhci_send_command);
static void sdhci_finish_command(struct sdhci_host *host)
{
@@ -1451,8 +1451,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
}
if (host->version >= SDHCI_SPEC_300 &&
- (ios->power_mode == MMC_POWER_UP) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
+ (ios->power_mode == MMC_POWER_UP))
sdhci_enable_preset_value(host, false);
sdhci_set_clock(host, ios->clock);
@@ -1892,14 +1891,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return 0;
}
- if (host->ops->platform_execute_tuning) {
- spin_unlock(&host->lock);
- enable_irq(host->irq);
- err = host->ops->platform_execute_tuning(host, opcode);
- sdhci_runtime_pm_put(host);
- return err;
- }
-
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
/*
@@ -2006,7 +1997,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (!tuning_loop_counter || !timeout) {
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- err = -EIO;
} else {
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
pr_info(DRIVER_NAME ": Tuning procedure"
@@ -2521,14 +2511,6 @@ again:
result = IRQ_HANDLED;
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
- /*
- * If we know we'll call the driver to signal SDIO IRQ, disregard
- * further indications of Card Interrupt in the status to avoid a
- * needless loop.
- */
- if (cardint)
- intmask &= ~SDHCI_INT_CARD_INT;
if (intmask && --max_loops)
goto again;
out:
@@ -2584,6 +2566,8 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
int sdhci_suspend_host(struct sdhci_host *host)
{
+ int ret;
+
if (host->ops->platform_suspend)
host->ops->platform_suspend(host);
@@ -2595,6 +2579,19 @@ int sdhci_suspend_host(struct sdhci_host *host)
host->flags &= ~SDHCI_NEEDS_RETUNING;
}
+ ret = mmc_suspend_host(host->mmc);
+ if (ret) {
+ if (host->flags & SDHCI_USING_RETUNING_TIMER) {
+ host->flags |= SDHCI_NEEDS_RETUNING;
+ mod_timer(&host->tuning_timer, jiffies +
+ host->tuning_count * HZ);
+ }
+
+ sdhci_enable_card_detection(host);
+
+ return ret;
+ }
+
if (!device_may_wakeup(mmc_dev(host->mmc))) {
sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
free_irq(host->irq, host);
@@ -2602,14 +2599,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_enable_irq_wakeups(host);
enable_irq_wake(host->irq);
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(sdhci_suspend_host);
int sdhci_resume_host(struct sdhci_host *host)
{
- int ret = 0;
+ int ret;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma)
@@ -2638,6 +2635,7 @@ int sdhci_resume_host(struct sdhci_host *host)
mmiowb();
}
+ ret = mmc_resume_host(host->mmc);
sdhci_enable_card_detection(host);
if (host->ops->platform_resume)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4e68539..096b203 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -290,7 +290,6 @@ struct sdhci_ops {
unsigned int (*get_ro)(struct sdhci_host *host);
void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
- int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host);
@@ -399,8 +398,6 @@ extern void sdhci_reset(struct sdhci_host *host, u8 mask);
extern void sdhci_card_detect(struct sdhci_host *host);
extern int sdhci_add_host(struct sdhci_host *host);
extern void sdhci_remove_host(struct sdhci_host *host, int dead);
-extern void sdhci_send_command(struct sdhci_host *host,
- struct mmc_command *cmd);
#ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host);
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index b7e3057..50adbd1 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -516,7 +516,9 @@ static void sdricoh_pcmcia_detach(struct pcmcia_device *link)
#ifdef CONFIG_PM
static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
{
+ struct mmc_host *mmc = link->priv;
dev_dbg(&link->dev, "suspend\n");
+ mmc_suspend_host(mmc);
return 0;
}
@@ -525,6 +527,7 @@ static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
struct mmc_host *mmc = link->priv;
dev_dbg(&link->dev, "resume\n");
sdricoh_reset(mmc_priv(mmc));
+ mmc_resume_host(mmc);
return 0;
}
#else
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index d032b08..36629a0 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -964,7 +964,7 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
{
- int ret = clk_prepare_enable(host->hclk);
+ int ret = clk_enable(host->hclk);
if (!ret) {
host->clk = clk_get_rate(host->hclk);
@@ -1018,7 +1018,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (host->power) {
pm_runtime_put_sync(&host->pd->dev);
- clk_disable_unprepare(host->hclk);
+ clk_disable(host->hclk);
host->power = false;
if (ios->power_mode == MMC_POWER_OFF)
sh_mmcif_set_power(host, ios);
@@ -1466,7 +1466,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
mutex_init(&host->thread_lock);
- clk_disable_unprepare(host->hclk);
+ clk_disable(host->hclk);
ret = mmc_add_host(mmc);
if (ret < 0)
goto emmcaddh;
@@ -1487,7 +1487,7 @@ ereqirq1:
ereqirq0:
pm_runtime_suspend(&pdev->dev);
eresume:
- clk_disable_unprepare(host->hclk);
+ clk_disable(host->hclk);
eclkupdate:
clk_put(host->hclk);
eclkget:
@@ -1505,7 +1505,7 @@ static int sh_mmcif_remove(struct platform_device *pdev)
int irq[2];
host->dying = true;
- clk_prepare_enable(host->hclk);
+ clk_enable(host->hclk);
pm_runtime_get_sync(&pdev->dev);
dev_pm_qos_hide_latency_limit(&pdev->dev);
@@ -1530,7 +1530,7 @@ static int sh_mmcif_remove(struct platform_device *pdev)
if (irq[1] >= 0)
free_irq(irq[1], host);
- clk_disable_unprepare(host->hclk);
+ clk_disable(host->hclk);
mmc_free_host(host->mmc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1538,21 +1538,28 @@ static int sh_mmcif_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
static int sh_mmcif_suspend(struct device *dev)
{
struct sh_mmcif_host *host = dev_get_drvdata(dev);
+ int ret = mmc_suspend_host(host->mmc);
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+ if (!ret)
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
- return 0;
+ return ret;
}
static int sh_mmcif_resume(struct device *dev)
{
- return 0;
+ struct sh_mmcif_host *host = dev_get_drvdata(dev);
+
+ return mmc_resume_host(host->mmc);
}
-#endif
+#else
+#define sh_mmcif_suspend NULL
+#define sh_mmcif_resume NULL
+#endif /* CONFIG_PM */
static const struct of_device_id mmcif_of_match[] = {
{ .compatible = "renesas,sh-mmcif" },
@@ -1561,7 +1568,8 @@ static const struct of_device_id mmcif_of_match[] = {
MODULE_DEVICE_TABLE(of, mmcif_of_match);
static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(sh_mmcif_suspend, sh_mmcif_resume)
+ .suspend = sh_mmcif_suspend,
+ .resume = sh_mmcif_resume,
};
static struct platform_driver sh_mmcif_driver = {
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index d1760eb..43d9628 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -1030,7 +1030,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{
- return 0;
+ return mmc_suspend_host(tifm_get_drvdata(sock));
}
static int tifm_sd_resume(struct tifm_dev *sock)
@@ -1044,6 +1044,8 @@ static int tifm_sd_resume(struct tifm_dev *sock)
if (rc)
host->eject = 1;
+ else
+ rc = mmc_resume_host(mmc);
return rc;
}
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index f3b2d8c..b380225 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1145,9 +1145,12 @@ int tmio_mmc_host_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct tmio_mmc_host *host = mmc_priv(mmc);
+ int ret = mmc_suspend_host(mmc);
- tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
- return 0;
+ if (!ret)
+ tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
+
+ return ret;
}
EXPORT_SYMBOL(tmio_mmc_host_suspend);
@@ -1160,7 +1163,7 @@ int tmio_mmc_host_resume(struct device *dev)
/* The MMC core will perform the complete set up */
host->resuming = true;
- return 0;
+ return mmc_resume_host(mmc);
}
EXPORT_SYMBOL(tmio_mmc_host_resume);
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 63fac78..4f84586 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -1269,18 +1269,21 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
{
struct via_crdr_mmc_host *host;
+ int ret = 0;
host = pci_get_drvdata(pcidev);
via_save_pcictrlreg(host);
via_save_sdcreg(host);
+ ret = mmc_suspend_host(host->mmc);
+
pci_save_state(pcidev);
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
pci_disable_device(pcidev);
pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
- return 0;
+ return ret;
}
static int via_sd_resume(struct pci_dev *pcidev)
@@ -1313,6 +1316,8 @@ static int via_sd_resume(struct pci_dev *pcidev)
via_restore_pcictrlreg(sdhost);
via_init_sdc_pm(sdhost);
+ ret = mmc_resume_host(sdhost->mmc);
+
return ret;
}
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 4262296..e9028ad 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2392,12 +2392,26 @@ static void vub300_disconnect(struct usb_interface *interface)
#ifdef CONFIG_PM
static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
{
- return 0;
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ if (!vub300 || !vub300->mmc) {
+ return 0;
+ } else {
+ struct mmc_host *mmc = vub300->mmc;
+ mmc_suspend_host(mmc);
+ return 0;
+ }
}
static int vub300_resume(struct usb_interface *intf)
{
- return 0;
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ if (!vub300 || !vub300->mmc) {
+ return 0;
+ } else {
+ struct mmc_host *mmc = vub300->mmc;
+ mmc_resume_host(mmc);
+ return 0;
+ }
}
#else
#define vub300_suspend NULL
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index 1defd5e..e954b77 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1814,11 +1814,28 @@ static void wbsd_pnp_remove(struct pnp_dev *dev)
#ifdef CONFIG_PM
+static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
+{
+ BUG_ON(host == NULL);
+
+ return mmc_suspend_host(host->mmc);
+}
+
+static int wbsd_resume(struct wbsd_host *host)
+{
+ BUG_ON(host == NULL);
+
+ wbsd_init_device(host);
+
+ return mmc_resume_host(host->mmc);
+}
+
static int wbsd_platform_suspend(struct platform_device *dev,
pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
struct wbsd_host *host;
+ int ret;
if (mmc == NULL)
return 0;
@@ -1827,7 +1844,12 @@ static int wbsd_platform_suspend(struct platform_device *dev,
host = mmc_priv(mmc);
+ ret = wbsd_suspend(host, state);
+ if (ret)
+ return ret;
+
wbsd_chip_poweroff(host);
+
return 0;
}
@@ -1850,8 +1872,7 @@ static int wbsd_platform_resume(struct platform_device *dev)
*/
mdelay(5);
- wbsd_init_device(host);
- return 0;
+ return wbsd_resume(host);
}
#ifdef CONFIG_PNP
@@ -1859,12 +1880,16 @@ static int wbsd_platform_resume(struct platform_device *dev)
static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
{
struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+ struct wbsd_host *host;
if (mmc == NULL)
return 0;
DBGF("Suspending...\n");
- return 0;
+
+ host = mmc_priv(mmc);
+
+ return wbsd_suspend(host, state);
}
static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
@@ -1897,8 +1922,7 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
*/
mdelay(5);
- wbsd_init_device(host);
- return 0;
+ return wbsd_resume(host);
}
#endif /* CONFIG_PNP */
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
index e902ed7..34231d5 100644
--- a/drivers/mmc/host/wmt-sdmmc.c
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -212,14 +212,28 @@ struct wmt_mci_priv {
static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable)
{
- u32 reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
-
- if (enable ^ priv->power_inverted)
- reg_tmp &= ~BM_SD_OFF;
- else
- reg_tmp |= BM_SD_OFF;
-
- writeb(reg_tmp, priv->sdmmc_base + SDMMC_BUSMODE);
+ u32 reg_tmp;
+ if (enable) {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ } else {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ }
}
static void wmt_mci_read_response(struct mmc_host *mmc)
@@ -925,23 +939,28 @@ static int wmt_mci_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct wmt_mci_priv *priv;
+ int ret;
if (!mmc)
return 0;
priv = mmc_priv(mmc);
- reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
- writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
- SDMMC_BUSMODE);
+ ret = mmc_suspend_host(mmc);
- reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
- writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN);
+ if (!ret) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+ SDMMC_BUSMODE);
- writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
- writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN);
- clk_disable(priv->clk_sdmmc);
- return 0;
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ clk_disable(priv->clk_sdmmc);
+ }
+ return ret;
}
static int wmt_mci_resume(struct device *dev)
@@ -950,6 +969,7 @@ static int wmt_mci_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct wmt_mci_priv *priv;
+ int ret = 0;
if (mmc) {
priv = mmc_priv(mmc);
@@ -967,9 +987,10 @@ static int wmt_mci_resume(struct device *dev)
writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base +
SDMMC_INTMASK0);
+ ret = mmc_resume_host(mmc);
}
- return 0;
+ return ret;
}
static const struct dev_pm_ops wmt_mci_pm = {