aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c42
-rw-r--r--drivers/mmc/card/queue.c14
-rw-r--r--drivers/mmc/card/queue.h18
-rw-r--r--drivers/mmc/core/core.c7
-rw-r--r--drivers/mmc/core/mmc.c16
-rw-r--r--drivers/mmc/core/sdio.c1
-rw-r--r--[-rwxr-xr-x]drivers/mmc/core/sdio_io.c0
-rw-r--r--drivers/mmc/host/Kconfig11
-rw-r--r--drivers/mmc/host/mshci-s3c.c18
-rw-r--r--drivers/mmc/host/mshci.c8
-rw-r--r--drivers/mmc/host/sdhci-s3c.c51
-rw-r--r--drivers/mmc/host/sdhci.c35
-rw-r--r--drivers/mmc/host/sdhci.h1
13 files changed, 171 insertions, 51 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index a47f1ea..7406c4b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1015,7 +1015,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
brq->data.error) {
#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_P4NOTE) || \
- defined(CONFIG_MACH_C1_USA_ATT)
+ defined(CONFIG_MACH_C1_USA_ATT) \
+ || defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
if (mmc_card_mmc(card)) {
pr_err("brq->sbc.opcode=%d,"
"brq->cmd.opcode=%d.\n",
@@ -1354,6 +1355,11 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
}
while (reqs < max_packed_rw - 1) {
+ /* We should stop no-more packing its nopacked_period */
+ if ((card->host->caps2 & MMC_CAP2_ADAPT_PACKED)
+ && mmc_is_nopacked_period(mq))
+ break;
+
spin_lock_irq(q->queue_lock);
next = blk_fetch_request(q);
spin_unlock_irq(q->queue_lock);
@@ -1939,7 +1945,8 @@ snd_packed_rd:
}
}
#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_P4NOTE) || \
- defined(CONFIG_MACH_C1_USA_ATT)
+ defined(CONFIG_MACH_C1_USA_ATT) \
+ || defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
/*
* It's for Engineering DEBUGGING only
* This has to be removed before PVR(guessing)
@@ -2016,7 +2023,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
/* complete ongoing async transfer before issuing discard */
if (card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
- if (req->cmd_flags & REQ_SECURE)
+ if (req->cmd_flags & REQ_SECURE &&
+ !(card->quirks & MMC_QUIRK_MOVINAND_SECURE))
ret = mmc_blk_issue_secdiscard_rq(mq, req);
else
ret = mmc_blk_issue_discard_rq(mq, req);
@@ -2289,6 +2297,8 @@ static int mmc_add_disk(struct mmc_blk_data *md)
return ret;
}
+#define CID_MANFID_SAMSUNG 0x15
+
static const struct mmc_fixup blk_fixups[] =
{
MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
@@ -2311,6 +2321,28 @@ static const struct mmc_fixup blk_fixups[] =
MMC_QUIRK_BLK_NO_CMD23),
MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23),
+
+ /*
+ * Some issue about secure erase/secure trim for Samsung MoviNAND
+ */
+
+ MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+ MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_MOVINAND_SECURE),
+
END_FIXUP
};
@@ -2458,7 +2490,11 @@ static void __exit mmc_blk_exit(void)
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(mmc_blk_init);
+#else
module_init(mmc_blk_init);
+#endif
module_exit(mmc_blk_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index bf5d183..b384995 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -62,6 +62,9 @@ static int mmc_queue_thread(void *d)
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
req = blk_fetch_request(q);
+ /* set nopacked_period if next request is RT class */
+ if (req && IS_RT_CLASS_REQ(req))
+ mmc_set_nopacked_period(mq, HZ);
mq->mqrq_cur->req = req;
spin_unlock_irq(q->queue_lock);
@@ -100,6 +103,7 @@ static void mmc_request(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata;
struct request *req;
+ struct io_context *ioc;
if (!mq) {
while ((req = blk_fetch_request(q)) != NULL) {
@@ -109,6 +113,14 @@ static void mmc_request(struct request_queue *q)
return;
}
+ ioc = get_io_context(GFP_NOWAIT, 0);
+ if (ioc) {
+ /* Set nopacked period if requesting process is RT class */
+ if (IOPRIO_PRIO_CLASS(ioc->ioprio) == IOPRIO_CLASS_RT)
+ mmc_set_nopacked_period(mq, HZ);
+ put_io_context(ioc);
+ }
+
if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
wake_up_process(mq->thread);
}
@@ -182,6 +194,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
+ mq->nopacked_period = 0;
+
blk_queue_prep_rq(mq->queue, mmc_prep_request);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index be58b3c..f1ba6df 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -46,6 +46,8 @@ struct mmc_queue {
struct mmc_queue_req mqrq[2];
struct mmc_queue_req *mqrq_cur;
struct mmc_queue_req *mqrq_prev;
+ /* Jiffies until which disable packed command. */
+ unsigned long nopacked_period;
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -59,4 +61,20 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
extern void mmc_queue_bounce_post(struct mmc_queue_req *);
+#define IS_RT_CLASS_REQ(x) \
+ (IOPRIO_PRIO_CLASS(req_get_ioprio(x)) == IOPRIO_CLASS_RT)
+
+static inline void mmc_set_nopacked_period(struct mmc_queue *mq,
+ unsigned long nopacked_jiffies)
+{
+ mq->nopacked_period = jiffies + nopacked_jiffies;
+ smp_wmb();
+}
+
+static inline int mmc_is_nopacked_period(struct mmc_queue *mq)
+{
+ smp_rmb();
+ return (int)time_is_after_jiffies(mq->nopacked_period);
+}
+
#endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index e33a805..ddd6d50 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -214,7 +214,8 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
}
#if (defined(CONFIG_MIDAS_COMMON) && !defined(CONFIG_EXYNOS4_DEV_DWMCI)) || \
- defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_SLP_NAPLES)
+ defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_SLP_NAPLES) || \
+ defined(CONFIG_MACH_TRATS)
#ifndef CONFIG_MMC_POLLING_WAIT_CMD23
if(mrq->sbc) {
@@ -2695,7 +2696,11 @@ static void __exit mmc_exit(void)
destroy_workqueue(workqueue);
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(mmc_init);
+#else
subsys_initcall(mmc_init);
+#endif
module_exit(mmc_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 53f0e21..81a77a8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -118,6 +118,10 @@ static int mmc_decode_cid(struct mmc_card *card)
return -EINVAL;
}
+ pr_info("%s: %s: %08x%08x%08x%08x\n", mmc_hostname(card->host),
+ card->cid.prod_name,
+ card->raw_cid[0], card->raw_cid[1],
+ card->raw_cid[2], card->raw_cid[3]);
return 0;
}
@@ -350,7 +354,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
- if (card->ext_csd.rev > 6) {
+ /* eMMC 4.5 : ext_csd rev. is 6
+ * eMMC 5.0 : ext_csd rev. is 7
+ * It's temporary change.
+ */
+ if (card->ext_csd.rev > 7) {
printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
@@ -571,8 +579,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
if (card->ext_csd.rev >= 5) {
- /* enable discard feature if emmc is 4.41 */
- card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+ /* enable discard feature if emmc is 4.41+ */
+ if ((ext_csd[EXT_CSD_VENDOR_SPECIFIC_FIELD + 0] & 0x1) &&
+ (card->cid.manfid == 0x15))
+ card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
/* check whether the eMMC card supports HPI */
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 979cf0b..620a4b2 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -1058,6 +1058,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
.alive = mmc_sdio_alive,
};
+
/*
* Starting point for SDIO card init.
*/
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 3169452..3169452 100755..100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e231dcc..d6a7e81 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -54,6 +54,17 @@ config MMC_MSHCI_ASYNC_OPS
If unsure, say N.
+config MMC_MSHCI_ENABLE_CACHE
+ tristate "Use Cache defined in eMMC 4.5"
+ depends on MMC_MSHCI
+ default n
+ help
+ This selects eMMC cache control feature of eMMC4.5.
+ These functions might make the performance of MMC better.
+ This should be used when the eMMC device supports cache feature.
+
+ If unsure, say N.
+
config MMC_SDHCI
tristate "Secure Digital Host Controller Interface support"
depends on HAS_DMA
diff --git a/drivers/mmc/host/mshci-s3c.c b/drivers/mmc/host/mshci-s3c.c
index 5023d10..58670ca 100644
--- a/drivers/mmc/host/mshci-s3c.c
+++ b/drivers/mmc/host/mshci-s3c.c
@@ -408,13 +408,14 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
if (parent_clk) {
#ifdef CONFIG_EXYNOS4_MSHC_EPLL_45MHZ
if (!strcmp("fout_epll", \
- parent_clk->name)) {
- clk_set_rate \
+ parent_clk->name) &&
+ soc_is_exynos4210()) {
+ clk_set_rate \
(parent_clk, 180633600);
pdata->cfg_ddr(pdev, 0);
#elif defined(CONFIG_EXYNOS4_MSHC_VPLL_46MHZ)
if (!strcmp("fout_vpll", \
- parent_clk->name)) {
+ parent_clk->name)) {
clk_set_rate \
(parent_clk, 370882812);
pdata->cfg_ddr(pdev, 0);
@@ -460,7 +461,7 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
if (!host->ioaddr) {
dev_err(dev, "failed to map registers\n");
ret = -ENXIO;
- goto err_req_regs;
+ goto err_add_host;
}
/* Ensure we have minimal gpio selected CMD/CLK/Detect */
@@ -541,8 +542,9 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
return 0;
err_add_host:
- release_resource(sc->ioarea);
- kfree(sc->ioarea);
+ if (host->ioaddr)
+ iounmap(host->ioaddr);
+ release_mem_region(sc->ioarea->start, resource_size(sc->ioarea));
err_req_regs:
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
@@ -629,7 +631,11 @@ static void __exit mshci_s3c_exit(void)
platform_driver_unregister(&mshci_s3c_driver);
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(mshci_s3c_init);
+#else
module_init(mshci_s3c_init);
+#endif
module_exit(mshci_s3c_exit);
MODULE_DESCRIPTION("Samsung MSHCI (HSMMC) glue");
diff --git a/drivers/mmc/host/mshci.c b/drivers/mmc/host/mshci.c
index 9431405..45997c5 100644
--- a/drivers/mmc/host/mshci.c
+++ b/drivers/mmc/host/mshci.c
@@ -1134,7 +1134,7 @@ static void mshci_request(struct mmc_host *mmc, struct mmc_request *mrq)
/* We shouldn't wait for data inihibit for stop commands, even
though they might use busy signaling */
- if (mrq->cmd->opcode == 12) {
+ if ((mrq->cmd->opcode == 12) || (mrq->cmd->opcode == 13)) {
/* nothing to do */
} else {
for (;;) {
@@ -1619,7 +1619,8 @@ static void mshci_cmd_irq(struct mshci_host *host, u32 intmask)
/* to notify an error happend */
host->error_state = 1;
#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_P4NOTE) || \
- defined(CONFIG_MACH_C1_USA_ATT)
+ defined(CONFIG_MACH_C1_USA_ATT) \
+ || defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
if (host->mmc && host->mmc->card)
mshci_dumpregs(host);
#endif
@@ -1704,7 +1705,8 @@ static void mshci_data_irq(struct mshci_host *host, u32 intmask, u8 intr_src)
/* to notify an error happend */
host->error_state = 1;
#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_P4NOTE) || \
- defined(CONFIG_MACH_C1_USA_ATT)
+ defined(CONFIG_MACH_C1_USA_ATT) \
+ || defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
if (host->mmc && host->mmc->card)
mshci_dumpregs(host);
#endif
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 5a81b34..97b40b8 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -386,17 +386,11 @@ static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
pr_info("%s: card inserted.\n",
mmc_hostname(host->mmc));
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-#ifdef CONFIG_MACH_MIDAS_01_BD
- sdhci_s3c_vtf_on_off(1);
-#endif
} else {
dev_dbg(&dev->dev, "card removed.\n");
pr_info("%s: card removed.\n",
mmc_hostname(host->mmc));
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-#ifdef CONFIG_MACH_MIDAS_01_BD
- sdhci_s3c_vtf_on_off(0);
-#endif
}
tasklet_schedule(&host->card_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
@@ -586,7 +580,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (!host->ioaddr) {
dev_err(dev, "failed to map registers\n");
ret = -ENXIO;
- goto err_req_regs;
+ goto err_add_host;
}
/* Ensure we have minimal gpio selected CMD/CLK/Detect */
@@ -652,11 +646,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (pdata->pm_flags)
host->mmc->pm_flags |= pdata->pm_flags;
-#ifdef CONFIG_MACH_MIDAS_01_BD
- /* before calling shhci_add_host, you should turn vdd_tflash on */
- sdhci_s3c_vtf_on_off(1);
-#endif
-
/* To turn on vmmc regulator only if sd card exists,
GPIO pin for card detection should be initialized.
Moved from sdhci_s3c_setup_card_detect_gpio() function */
@@ -721,20 +710,12 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
gpio_is_valid(pdata->ext_cd_gpio))
sdhci_s3c_setup_card_detect_gpio(sc);
-#ifdef CONFIG_MACH_MIDAS_01_BD
- /* if card dose not exist, it should turn vtf off */
- if (pdata->cd_type == S3C_SDHCI_CD_GPIO &&
- sdhci_s3c_get_card_exist(host))
- sdhci_s3c_vtf_on_off(1);
- else
- sdhci_s3c_vtf_on_off(0);
-#endif
-
return 0;
err_add_host:
- release_resource(sc->ioarea);
- kfree(sc->ioarea);
+ if (host->ioaddr)
+ iounmap(host->ioaddr);
+ release_mem_region(sc->ioarea->start, resource_size(sc->ioarea));
err_req_regs:
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
@@ -798,26 +779,21 @@ static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm)
ret = sdhci_suspend_host(host, pm);
-#ifdef CONFIG_MACH_MIDAS_01_BD
- /* turn vdd_tflash off */
- sdhci_s3c_vtf_on_off(0);
-#endif
return ret;
}
+static void sdhci_s3c_shutdown(struct platform_device *dev)
+{
+ struct sdhci_host *host = platform_get_drvdata(dev);
+
+ sdhci_shutdown_host(host);
+}
+
static int sdhci_s3c_resume(struct platform_device *dev)
{
struct sdhci_host *host = platform_get_drvdata(dev);
int ret = 0;
-#ifdef CONFIG_MACH_MIDAS_01_BD
- /* turn vdd_tflash off if a card exists*/
- if (sdhci_s3c_get_card_exist(host))
- sdhci_s3c_vtf_on_off(1);
- else
- sdhci_s3c_vtf_on_off(0);
-
-#endif
ret = sdhci_resume_host(host);
return ret;
}
@@ -832,6 +808,7 @@ static struct platform_driver sdhci_s3c_driver = {
.remove = __devexit_p(sdhci_s3c_remove),
.suspend = sdhci_s3c_suspend,
.resume = sdhci_s3c_resume,
+ .shutdown = sdhci_s3c_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-sdhci",
@@ -848,7 +825,11 @@ static void __exit sdhci_s3c_exit(void)
platform_driver_unregister(&sdhci_s3c_driver);
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(sdhci_s3c_init);
+#else
module_init(sdhci_s3c_init);
+#endif
module_exit(sdhci_s3c_exit);
MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1fe77ad..349f073 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -36,10 +36,12 @@
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+#ifndef CONFIG_FAST_RESUME
#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
defined(CONFIG_MMC_SDHCI_MODULE))
#define SDHCI_USE_LEDS_CLASS
#endif
+#endif
#define MAX_TUNING_LOOP 40
@@ -1966,6 +1968,10 @@ static void sdhci_tasklet_finish(unsigned long param)
controllers do not like that. */
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
+#ifdef CONFIG_MACH_PX
+ printk(KERN_DEBUG "%s: Controller is resetted!\n",
+ mmc_hostname(host->mmc));
+#endif
}
host->mrq = NULL;
@@ -2062,6 +2068,10 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
+#ifdef CONFIG_MACH_PX
+ printk(KERN_DEBUG "%s: finish tasklet schedule\n",
+ mmc_hostname(host->mmc));
+#endif
return;
}
@@ -2346,6 +2356,28 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
EXPORT_SYMBOL_GPL(sdhci_suspend_host);
+void sdhci_shutdown_host(struct sdhci_host *host)
+{
+ sdhci_disable_card_detection(host);
+
+ free_irq(host->irq, host);
+
+ if (host->vmmc) {
+ if (regulator_is_enabled(host->vmmc)) {
+#ifdef CONFIG_MIDAS_COMMON
+ if (host->ops->set_power)
+ host->ops->set_power(0);
+#endif
+ regulator_disable(host->vmmc);
+ pr_info("%s : MMC Card OFF\n", __func__);
+#if defined(CONFIG_TARGET_LOCALE_KOR)
+ mdelay(5);
+#endif
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(sdhci_shutdown_host);
+
int sdhci_resume_host(struct sdhci_host *host)
{
int ret;
@@ -2660,6 +2692,9 @@ int sdhci_add_host(struct sdhci_host *host)
if (caps[1] & SDHCI_DRIVER_TYPE_D)
mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+ if (mmc->pm_flags & MMC_PM_IGNORE_SUSPEND_RESUME)
+ mmc->pm_caps |= MMC_PM_KEEP_POWER;
+
/*
* If Power Off Notify capability is enabled by the host,
* set notify to short power off notify timeout value.
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b04e361..b5f48f8 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -375,6 +375,7 @@ extern int sdhci_add_host(struct sdhci_host *host);
extern void sdhci_remove_host(struct sdhci_host *host, int dead);
#ifdef CONFIG_PM
+extern void sdhci_shutdown_host(struct sdhci_host *host);
extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
extern int sdhci_resume_host(struct sdhci_host *host);
extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);