From bac1959b76f55a7845b0bb20eafd32e40c49dd74 Mon Sep 17 00:00:00 2001
From: JiebingLi <jiebing.li@intel.com>
Date: Wed, 25 Nov 2009 19:43:03 +0800
Subject: [PATCH 077/104] MMC driver Beta 1.0 It is a consolidated patch against upstream Linux 2.6.31.6

Beta features:
1. removed CEATA function from MMC bus driver
2. Added 25MHz support at High-Speed mode for SDIO Comms devices
3. Added eMMC support for Moorestown platform
4. Fixed sighting 3469229 and 3452438

Kernel configuration:
CONFIG_MMC=y
CONFIG_MRST_LNW_A2_WR=y
CONFIG_SDIO_SUSPEND=y
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_BOUNCE=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PCI=y

Note: Please DO NOT enable CONFIG_MMC_SDHCI_MRST_EMMC unless you
      are sure that you want to enable eMMC device for Moorestown.

Signed-off-by: JiebingLi <jiebing.li@intel.com>
---
 drivers/mmc/Kconfig           |   14 ++
 drivers/mmc/card/block.c      |    3 +-
 drivers/mmc/core/Kconfig      |   11 +
 drivers/mmc/core/core.c       |    6 +
 drivers/mmc/core/mmc.c        |   41 ++++-
 drivers/mmc/core/sd.c         |    8 +
 drivers/mmc/core/sdio.c       |  464 +++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/sdio_bus.c   |   38 ++++
 drivers/mmc/core/sdio_bus.h   |    4 +
 drivers/mmc/host/Kconfig      |   10 +
 drivers/mmc/host/sdhci-pci.c  |   81 ++++++--
 drivers/mmc/host/sdhci.c      |  125 ++++++++++-
 drivers/mmc/host/sdhci.h      |    3 +
 include/linux/mmc/card.h      |   12 +
 include/linux/mmc/host.h      |    2 +
 include/linux/mmc/sdio_func.h |   14 ++
 include/linux/pci_ids.h       |    2 +
 17 files changed, 810 insertions(+), 28 deletions(-)

diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f2eeb38..2c19682 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -19,6 +19,20 @@ config MMC_DEBUG
 	  This is an option for use by developers; most people should
 	  say N here.  This enables MMC core and driver debugging.
 
+config MRST_LNW_A1_WR
+	bool "software workaround for Moorestown LNW A-1"
+	depends on MMC
+	help
+	  This is an option for Moorestown developers to add workaround
+	  in the code due to LNW A-1 Silicon restrictions.
+
+config MRST_LNW_A2_WR
+	bool "software workaround for Moorestown LNW A-2"
+	depends on MMC
+	help
+	  This is an option for Moorestown developers to add workaround
+	  in the code due to LNW A-2 Silicon restrictions.
+
 if MMC
 
 source "drivers/mmc/core/Kconfig"
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1f552c6..f4ebc68 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -534,7 +534,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 * messages to tell when the card is present.
 	 */
 
-	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+		"mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
 
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index bb22ffd..205186c 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -16,3 +16,14 @@ config MMC_UNSAFE_RESUME
 
 	  This option sets a default which can be overridden by the
 	  module parameter "removable=0" or "removable=1".
+
+config SDIO_SUSPEND
+	bool "SDIO selective suspend/resume"
+	depends on MMC && PM
+	help
+	  If you say Y here, you can use driver calls or the sysfs
+	  "power/level" file to suspend or resume the SDIO
+	  peripherals.
+
+	  If you are unsure about this, say N here.
+
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 30acd52..951561d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -213,9 +213,15 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 	mrq->done_data = &complete;
 	mrq->done = mmc_wait_done;
 
+	if (host->port_mutex)
+		mutex_lock(host->port_mutex);
+
 	mmc_start_request(host, mrq);
 
 	wait_for_completion(&complete);
+
+	if (host->port_mutex)
+		mutex_unlock(host->port_mutex);
 }
 
 EXPORT_SYMBOL(mmc_wait_for_req);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0eac6c8..15aaa66 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -179,8 +179,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	err = mmc_send_ext_csd(card, ext_csd);
 	if (err) {
-		/* If the host or the card can't do the switch,
-		 * fail more gracefully. */
+		/*
+		 * If the host or the card can't do the switch,
+		 * fail more gracefully.
+		 */
 		if ((err != -EINVAL)
 		 && (err != -ENOSYS)
 		 && (err != -EFAULT))
@@ -294,6 +296,28 @@ static struct device_type mmc_type = {
 };
 
 /*
+ * Distinguish the fake MMCA4 MMC card.
+ *
+ * Transcend 2GB MMC card is a kind of MMCA3.31 MMC card.
+ * However, it makes up itself as a MMCA4 one via SPEC_VERS
+ * field of its CSD register. Once it's treated as MMCA4 by
+ * driver, 4 bit bus is activated which leads to data error.
+ */
+static bool fake_mmca4_card(struct mmc_card *card)
+{
+	if (card->cid.manfid == 0x1e &&
+		card->cid.oemid == 0xffff &&
+		card->cid.prod_name[0] == 'M' &&
+		card->cid.prod_name[1] == 'M' &&
+		card->cid.prod_name[2] == 'C' &&
+		card->cid.month == 9 &&
+		card->cid.year == 2008)
+		return true;
+	else
+		return false;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -389,6 +413,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		err = mmc_decode_cid(card);
 		if (err)
 			goto free_card;
+
+		/*
+		 * Get card's true specification version
+		 */
+		if (fake_mmca4_card(card))
+			card->csd.mmca_vsn = CSD_SPEC_VER_3;
 	}
 
 	/*
@@ -409,6 +439,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			goto free_card;
 	}
 
+/*
+ * avoid MMC cards to switch to HS timing
+ * which doesn't work yet due to LNW A-1 Silicon bug
+ */
+#if !defined CONFIG_MRST_LNW_A1_WR && !defined CONFIG_MRST_LNW_A2_WR
 	/*
 	 * Activate high speed (if supported)
 	 */
@@ -428,7 +463,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 		}
 	}
-
+#endif
 	/*
 	 * Compute bus speed.
 	 */
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index fdd414e..5aae661 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -234,6 +234,7 @@ out:
 	return err;
 }
 
+#if !defined CONFIG_MRST_LNW_A1_WR && !defined CONFIG_MRST_LNW_A2_WR
 /*
  * Test if the card supports high-speed mode and, if so, switch to it.
  */
@@ -281,6 +282,7 @@ out:
 
 	return err;
 }
+#endif
 
 MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
 	card->raw_cid[2], card->raw_cid[3]);
@@ -460,12 +462,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 			goto free_card;
 	}
 
+/*
+ * avoid SD cards to switch to HS timing
+ * which doesn't work yet due to LNW A-1 Silicon bug
+ */
+#if !defined CONFIG_MRST_LNW_A1_WR && !defined CONFIG_MRST_LNW_A2_WR
 	/*
 	 * Attempt to change to high-speed (if supported)
 	 */
 	err = mmc_switch_hs(card);
 	if (err)
 		goto free_card;
+#endif
 
 	/*
 	 * Compute bus speed.
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 06b6408..42977e1 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -24,6 +24,262 @@
 #include "sdio_ops.h"
 #include "sdio_cis.h"
 
+#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+
+#ifdef CONFIG_SDIO_SUSPEND
+
+static int sdio_suspend_func(struct mmc_card *card,
+	 struct sdio_func *func, pm_message_t msg)
+{
+	struct device *dev;
+	int error = 0;
+
+	dev = &func->dev;
+	BUG_ON(!dev);
+
+	if (dev->bus)
+		if (dev->bus->suspend)
+			error = dev->bus->suspend(dev, msg);
+
+	return error;
+}
+
+static int sdio_resume_func(struct mmc_card *card, struct sdio_func *func)
+{
+	struct device *dev;
+	int error = 0;
+
+	dev = &func->dev;
+	BUG_ON(!dev);
+
+	if (dev->bus)
+		if (dev->bus->resume)
+			error = dev->bus->resume(dev);
+
+	return error;
+}
+
+int sdio_suspend_host(struct mmc_card *card, pm_message_t msg)
+{
+	int ret = 0;
+	int i = 0;
+	struct device *dev;
+	struct sdio_driver *drv;
+
+	mutex_lock(&card->pm_mutex);
+
+	if (!mmc_card_present(card) ||
+		mmc_card_suspended(card))
+		goto done;
+
+	for (i = 0; i < card->sdio_funcs; i++)
+		if (!sdio_func_suspended(card->sdio_func[i])) {
+			dev = &(card->sdio_func[i])->dev;
+			BUG_ON(!dev);
+
+			drv = to_sdio_driver(dev->driver);
+
+			if (dev->driver && drv->suspend)
+				goto done;
+		}
+
+	ret = mmc_suspend_host(card->host, msg);
+
+	if (ret == 0)
+		mmc_card_set_suspended(card);
+
+done:
+	mutex_unlock(&card->pm_mutex);
+
+	return ret;
+}
+
+int sdio_resume_host(struct mmc_card *card)
+{
+	int ret = 0;
+
+	mutex_lock(&card->pm_mutex);
+
+	if (!mmc_card_present(card)) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	if (mmc_card_suspended(card)) {
+		ret = mmc_resume_host(card->host);
+
+		if (ret == 0)
+			mmc_card_clear_suspended(card);
+		else
+			goto done;
+	}
+
+done:
+	mutex_unlock(&card->pm_mutex);
+
+	return ret;
+}
+
+/*
+ * This routine handles external suspend request coming from sysfs
+ */
+int sdio_external_suspend_device(struct sdio_func *func, pm_message_t msg)
+{
+	int ret = 0;
+	struct mmc_card *card = func->card;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	mutex_lock(&card->pm_mutex);
+
+	if (!sdio_func_present(func) ||
+		sdio_func_suspended(func)) {
+		mutex_unlock(&card->pm_mutex);
+		goto done;
+	}
+
+	/* suspend the function of the SDIO device */
+	ret = sdio_suspend_func(card, func, msg);
+
+	if (ret != 0) {
+		mutex_unlock(&card->pm_mutex);
+		goto done;
+	}
+
+	sdio_func_set_suspended(func);
+
+	mutex_unlock(&card->pm_mutex);
+
+	ret = sdio_suspend_host(card, msg);
+
+done:
+	return ret;
+}
+
+/*
+ * This routine handles external resume request coming from sysfs
+ */
+int sdio_external_resume_device(struct sdio_func *func)
+{
+	int ret = 0;
+	struct mmc_card *card = func->card;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	ret = sdio_resume_host(card);
+	if (ret)
+		goto done;
+
+	mutex_lock(&card->pm_mutex);
+
+	if (sdio_func_suspended(func)) {
+		ret = sdio_resume_func(card, func);
+
+			if (ret != 0) {
+				mutex_unlock(&card->pm_mutex);
+				goto done;
+			} else
+				sdio_func_clear_suspended(func);
+	}
+
+	mutex_unlock(&card->pm_mutex);
+done:
+
+	return ret;
+}
+
+static const char power_group[] = "power";
+
+static const char resume_string[] = "resume";
+static const char suspend_string[] = "suspend";
+
+static ssize_t
+show_level(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sdio_func *func = container_of(dev, struct sdio_func, dev);
+	const char *p = suspend_string;
+
+	BUG_ON(!func);
+
+	if (sdio_func_suspended(func))
+		p = suspend_string;
+	else
+		p = resume_string;
+
+	return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t
+set_level(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct sdio_func *func = container_of(dev, struct sdio_func, dev);
+	int len = count;
+	char *cp;
+	int ret = 0;
+
+	BUG_ON(!func);
+
+	cp = memchr(buf, '\n', count);
+	if (cp)
+		len = cp - buf;
+
+	down(&dev->sem);
+
+	if (len == sizeof resume_string - 1 &&
+		strncmp(buf, resume_string, len) == 0) {
+		ret = sdio_external_resume_device(func);
+	} else if (len == sizeof suspend_string - 1 &&
+		strncmp(buf, suspend_string, len) == 0) {
+		ret = sdio_external_suspend_device(func, PMSG_SUSPEND);
+	} else {
+		ret = -EINVAL;
+	}
+
+	up(&dev->sem);
+
+	return (ret < 0 ? ret : count);
+}
+
+static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
+
+void sdio_remove_sysfs_file(struct sdio_func *func)
+{
+	struct device *dev = &func->dev;
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+
+	if (dev->driver && drv->suspend)
+		sysfs_remove_file_from_group(&dev->kobj,
+			&dev_attr_level.attr,
+			power_group);
+}
+
+int sdio_create_sysfs_file(struct sdio_func *func)
+{
+	int ret;
+	struct device *dev = &func->dev;
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+
+	if (dev->driver && drv->suspend) {
+		ret = sysfs_add_file_to_group(&dev->kobj,
+			&dev_attr_level.attr,
+			power_group);
+
+		if (ret)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	sdio_remove_sysfs_file(func);
+	return ret;
+}
+
+#endif /* CONFIG_SDIO_SUSPEND */
+
 static int sdio_read_fbr(struct sdio_func *func)
 {
 	int ret;
@@ -187,6 +443,7 @@ static int sdio_disable_cd(struct mmc_card *card)
 	return mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
 }
 
+#if !defined(CONFIG_MRST_LNW_A1_WR) && !defined(CONFIG_MRST_LNW_A2_WR)
 /*
  * Test if the card supports high-speed mode and, if so, switch to it.
  */
@@ -216,6 +473,128 @@ static int sdio_enable_hs(struct mmc_card *card)
 
 	return 0;
 }
+#else
+static int sdio_enable_hs(struct mmc_card *card)
+{
+	return 0;
+}
+#endif
+
+/*
+ * Handle the re-initialization of a SDIO card.
+ */
+static int mmc_sdio_reinit_card(struct mmc_host *host,
+	struct mmc_card *oldcard)
+{
+	int err = 0;
+	u16 funcs;
+	u32 ocr;
+	struct mmc_card *card;
+
+#if !defined(CONFIG_MRST_LNW_A1_WR) && !defined(CONFIG_MRST_LNW_A2_WR)
+	unsigned int max_dtr;
+#endif
+
+	BUG_ON(!host);
+	WARN_ON(!host->claimed);
+
+	if (!oldcard)
+		goto err;
+
+	card = oldcard;
+
+	err = mmc_send_io_op_cond(host, 0, &ocr);
+	if (err)
+		goto remove;
+
+	/*
+	 * Inform the card of the voltage
+	 */
+	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+	if (err)
+		goto remove;
+
+	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto remove;
+	}
+
+	funcs = (ocr & 0x70000000) >> 28;
+
+	if (funcs != card->sdio_funcs)
+		printk(KERN_INFO "funcs number is changed from OCR register after suspend!\n");
+
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err)
+			goto remove;
+
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto remove;
+	}
+
+	/*
+	 * Read the common CIS tuples.
+	 */
+	err = sdio_read_cccr(card);
+	if (err)
+		goto remove;
+
+#if defined(CONFIG_MRST_LNW_A1_WR) || defined(CONFIG_MRST_LNW_A2_WR)
+	/* restricting to 24MHz for Langwell A0 */
+	if (card->cis.max_dtr > 24000000)
+		card->cis.max_dtr = 24000000;
+
+	mmc_set_clock(host, card->cis.max_dtr);
+#else
+	/*
+	 * Switch to high-speed (if supported).
+	 */
+	err = sdio_enable_hs(card);
+	if (err)
+		goto remove;
+
+	max_dtr = card->cis.max_dtr;
+
+	/*
+	 * Change to the card's maximum speed.
+	 */
+	if (mmc_card_highspeed(card)) {
+		if (max_dtr > 50000000)
+			max_dtr = 50000000;
+	} else if (max_dtr > 25000000)
+		max_dtr = 25000000;
+
+	mmc_set_clock(host, max_dtr);
+#endif
+
+	/*
+	 * Switch to wider bus (if supported).
+	 */
+	err = sdio_enable_wide(card);
+	if (err)
+		goto remove;
+
+	host->card = card;
+
+	return 0;
+
+remove:
+err:
+	return err;
+}
 
 /*
  * Handle the detection and initialisation of a card.
@@ -478,6 +857,10 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
 	int i, funcs;
 	struct mmc_card *card;
 
+#if !defined(CONFIG_MRST_LNW_A1_WR) && !defined(CONFIG_MRST_LNW_A2_WR)
+	unsigned int max_dtr;
+#endif
+
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
 
@@ -574,3 +957,84 @@ err:
 	return err;
 }
 
+/*
+ * warn device driver and perform a SDIO device reset.
+ * Assume that device driver knows hot to handle resets.
+ */
+int sdio_reset_device(struct mmc_card *card)
+{
+	int ret = 0;
+	int i = 0;
+	u8 reg = 0;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!card->sdio_func);
+
+	if (!mmc_card_present(card) ||
+		mmc_card_suspended(card)) {
+		dev_dbg(&card->dev, "device reset not allowed\n");
+		return -EINVAL;
+	}
+
+	for (; i < card->sdio_funcs; i++) {
+		struct sdio_func *func = card->sdio_func[i];
+		struct sdio_driver *drv;
+
+		if (func && func->dev.driver) {
+			drv = to_sdio_driver(func->dev.driver);
+			if (drv->pre_reset) {
+				ret = (drv->pre_reset)(func);
+				if (ret)
+					break;
+			}
+		}
+	}
+
+	if (ret)
+		goto err;
+
+	/* reset SDIO card via CMD52 */
+	mmc_claim_host(card->host);
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_ABORT, 0, &reg);
+
+	if (ret)
+		reg = 0x08;
+	else
+		reg |= 0x08;
+
+	mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_ABORT, reg, NULL);
+
+	/* re-enumerate the device */
+	ret = mmc_sdio_reinit_card(card->host, card);
+
+	mmc_release_host(card->host);
+
+	if (ret)
+		goto err;
+
+	for (i = card->sdio_funcs - 1; i >= 0; i--) {
+		struct sdio_func *func = card->sdio_func[i];
+		struct sdio_driver *drv;
+
+		if (func && func->dev.driver) {
+			drv = to_sdio_driver(func->dev.driver);
+			if (drv->post_reset) {
+				ret = (drv->post_reset)(func);
+				if (ret)
+					break;
+			}
+		}
+	}
+
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	return -EINVAL;
+
+}
+EXPORT_SYMBOL_GPL(sdio_reset_device);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 9e060c8..84414e8 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -124,6 +124,14 @@ static int sdio_bus_probe(struct device *dev)
 	if (!id)
 		return -ENODEV;
 
+	/*
+	 * create the user interface to call suspend/resume
+	 * from susfs
+	 */
+#ifdef CONFIG_SDIO_SUSPEND
+	sdio_create_sysfs_file(func);
+#endif
+
 	/* Set the default block size so the driver is sure it's something
 	 * sensible. */
 	sdio_claim_host(func);
@@ -140,6 +148,10 @@ static int sdio_bus_remove(struct device *dev)
 	struct sdio_driver *drv = to_sdio_driver(dev->driver);
 	struct sdio_func *func = dev_to_sdio_func(dev);
 
+#ifdef CONFIG_SDIO_SUSPEND
+	sdio_remove_sysfs_file(func);
+#endif
+
 	drv->remove(func);
 
 	if (func->irq_handler) {
@@ -153,6 +165,30 @@ static int sdio_bus_remove(struct device *dev)
 	return 0;
 }
 
+static int sdio_bus_suspend(struct device *dev, pm_message_t state)
+{
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	int ret = 0;
+
+	if (dev->driver && drv->suspend)
+		ret = drv->suspend(func, state);
+
+	return ret;
+}
+
+static int sdio_bus_resume(struct device *dev)
+{
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	int ret = 0;
+
+	if (dev->driver && drv->resume)
+		ret = drv->resume(func);
+
+	return ret;
+}
+
 static struct bus_type sdio_bus_type = {
 	.name		= "sdio",
 	.dev_attrs	= sdio_dev_attrs,
@@ -160,6 +196,8 @@ static struct bus_type sdio_bus_type = {
 	.uevent		= sdio_bus_uevent,
 	.probe		= sdio_bus_probe,
 	.remove		= sdio_bus_remove,
+	.suspend	= sdio_bus_suspend,
+	.resume		= sdio_bus_resume,
 };
 
 int sdio_register_bus(void)
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
index 567a768..18616b2 100644
--- a/drivers/mmc/core/sdio_bus.h
+++ b/drivers/mmc/core/sdio_bus.h
@@ -18,5 +18,9 @@ void sdio_remove_func(struct sdio_func *func);
 int sdio_register_bus(void);
 void sdio_unregister_bus(void);
 
+#ifdef CONFIG_SDIO_SUSPEND
+int sdio_create_sysfs_file(struct sdio_func *func);
+void sdio_remove_sysfs_file(struct sdio_func *func);
+#endif
 #endif
 
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ce1d288..521cf2e 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -68,6 +68,16 @@ config MMC_SDHCI_PCI
 
 	  If unsure, say N.
 
+config MMC_SDHCI_MRST_EMMC
+	tristate "Enable eMMC device on MRST"
+	depends on MMC_SDHCI && PCI
+	help
+	  This enables eMMC device for MRST platform.
+
+	  If you're using eMMC device on Moorestown, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_RICOH_MMC
 	tristate "Ricoh MMC Controller Disabler  (EXPERIMENTAL)"
 	depends on MMC_SDHCI_PCI
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 5c3a176..53f3719 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -38,6 +38,8 @@
 
 #define MAX_SLOTS			8
 
+static struct mutex port_mutex;
+
 struct sdhci_pci_chip;
 struct sdhci_pci_slot;
 
@@ -364,6 +366,17 @@ static const struct sdhci_pci_fixes sdhci_via = {
 	.probe		= via_probe,
 };
 
+/*
+ * ADMA operation is disabled for Moorestown platform.
+ */
+static const struct sdhci_pci_fixes sdhci_intel_mrst = {
+	.quirks		= SDHCI_QUIRK_BROKEN_ADMA |
+#ifdef CONFIG_MMC_SDHCI_MRST_EMMC
+			  SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+#endif
+			  SDHCI_QUIRK_MRST_RESTRICTION,
+};
+
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
 		.vendor		= PCI_VENDOR_ID_RICOH,
@@ -445,6 +458,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 		.driver_data	= (kernel_ulong_t)&sdhci_via,
 	},
 
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MRST_SD0,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mrst,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MRST_SD1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mrst,
+	},
+
 	{	/* Generic SD host controller */
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 	},
@@ -469,11 +498,14 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
 	slot = sdhci_priv(host);
 	pdev = slot->chip->pdev;
 
-	if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
-		((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
-		(host->flags & SDHCI_USE_SDMA)) {
-		dev_warn(&pdev->dev, "Will use DMA mode even though HW "
-			"doesn't fully claim to support it.\n");
+	if (!(host->quirks & SDHCI_QUIRK_MRST_RESTRICTION)) {
+		if (((pdev->class & 0xFFFF00) ==
+			 (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
+			((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
+			(host->flags & SDHCI_USE_SDMA)) {
+			dev_warn(&pdev->dev, "Will use DMA mode even though HW "
+				"doesn't fully claim to support it.\n");
+		}
 	}
 
 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
@@ -622,6 +654,9 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
 		return ERR_PTR(PTR_ERR(host));
 	}
 
+	if (pdev->device == PCI_DEVICE_ID_INTEL_MRST_SD0)
+		host->mmc->port_mutex = &port_mutex;
+
 	slot = sdhci_priv(host);
 
 	slot->chip = chip;
@@ -712,22 +747,42 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
 	dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
 		 (int)pdev->vendor, (int)pdev->device, (int)rev);
 
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
-	if (ret)
-		return ret;
+	/*
+	 * slots number is fixed to 2 by Moorestown architecture
+	 */
+	if (pdev->device == PCI_DEVICE_ID_INTEL_MRST_SD0) {
+		slots = 2;
+		mutex_init(&port_mutex);
+	} else if (pdev->device == PCI_DEVICE_ID_INTEL_MRST_SD1)
+		slots = 1;
+	else {
+		ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
+
+		if (ret)
+			return ret;
+
+		slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
+	}
 
-	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
 	dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
 	if (slots == 0)
 		return -ENODEV;
 
 	BUG_ON(slots > MAX_SLOTS);
 
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
-	if (ret)
-		return ret;
+	/*
+	 * first BAR is fixed to 0 by Moorestown architecture
+	 */
+	if (pdev->device == PCI_DEVICE_ID_INTEL_MRST_SD0 ||
+		pdev->device == PCI_DEVICE_ID_INTEL_MRST_SD1) {
+		first_bar = 0;
+	} else {
+		ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+		if (ret)
+			return ret;
 
-	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+		first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+	}
 
 	if (first_bar > 5) {
 		dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c279fbc..ff26db0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -161,9 +161,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 	/* hw clears the bit when it's done */
 	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
 		if (timeout == 0) {
+#ifndef CONFIG_MRST_LNW_A2_WR
 			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
 				mmc_hostname(host->mmc), (int)mask);
 			sdhci_dumpregs(host);
+#endif
 			return;
 		}
 		timeout--;
@@ -176,13 +178,25 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
 static void sdhci_init(struct sdhci_host *host)
 {
+	u32 intmask;
+
+	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+	sdhci_writel(host,
+		intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
+		SDHCI_INT_STATUS);
+
+#ifndef CONFIG_MRST_LNW_A2_WR
 	sdhci_reset(host, SDHCI_RESET_ALL);
+#endif
 
 	sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
 		SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
 		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
 		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
 		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+
+	/* disable wakeup signal during initialization */
+	sdhci_writeb(host, 0x0, SDHCI_WAKE_UP_CONTROL);
 }
 
 static void sdhci_reinit(struct sdhci_host *host)
@@ -465,6 +479,54 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 			len -= offset;
 		}
 
+#if defined(CONFIG_MRST_LNW_A1_WR) || defined(CONFIG_MRST_LNW_A2_WR)
+		if (len != 65536) {
+			desc[7] = (addr >> 24) & 0xff;
+			desc[6] = (addr >> 16) & 0xff;
+			desc[5] = (addr >> 8) & 0xff;
+			desc[4] = (addr >> 0) & 0xff;
+
+			BUG_ON(len > 65536);
+
+			desc[3] = (len >> 8) & 0xff;
+			desc[2] = (len >> 0) & 0xff;
+
+			desc[1] = 0x00;
+			desc[0] = 0x21; /* tran, valid */
+
+			desc += 8;
+		} else {
+			desc[7] = (addr >> 24) & 0xff;
+			desc[6] = (addr >> 16) & 0xff;
+			desc[5] = (addr >> 8) & 0xff;
+			desc[4] = (addr >> 0) & 0xff;
+
+			desc[3] = (32768 >> 8) & 0xff;
+			desc[2] = (32768 >> 0) & 0xff;
+
+			desc[1] = 0x00;
+			desc[0] = 0x21; /* tran, valid */
+
+			desc += 8;
+
+			/* 2nd */
+			addr += 32768;
+
+			desc[7] = (addr >> 24) & 0xff;
+			desc[6] = (addr >> 16) & 0xff;
+			desc[5] = (addr >> 8) & 0xff;
+			desc[4] = (addr >> 0) & 0xff;
+
+			desc[3] = (32768 >> 8) & 0xff;
+			desc[2] = (32768 >> 0) & 0xff;
+
+			desc[1] = 0x00;
+			desc[0] = 0x21; /* tran, valid */
+
+			desc += 8;
+		}
+#else
+
 		desc[7] = (addr >> 24) & 0xff;
 		desc[6] = (addr >> 16) & 0xff;
 		desc[5] = (addr >> 8) & 0xff;
@@ -479,7 +541,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 		desc[0] = 0x21; /* tran, valid */
 
 		desc += 8;
-
+#endif
 		/*
 		 * If this triggers then we have a calculation bug
 		 * somewhere. :/
@@ -487,6 +549,11 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 		WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
 	}
 
+
+#if defined(CONFIG_MRST_LNW_A1_WR) || defined(CONFIG_MRST_LNW_A2_WR)
+	desc -= 8;
+	desc[0] = 0x23;
+#else
 	/*
 	 * Add a terminating entry.
 	 */
@@ -500,7 +567,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
 	desc[1] = 0x00;
 	desc[0] = 0x03; /* nop, end, valid */
-
+#endif
 	/*
 	 * Resync align buffer as we might have changed it.
 	 */
@@ -613,11 +680,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 			break;
 	}
 
-	if (count >= 0xF) {
-		printk(KERN_WARNING "%s: Too large timeout requested!\n",
-			mmc_hostname(host->mmc));
+	if (count >= 0xF)
 		count = 0xE;
-	}
 
 	return count;
 }
@@ -928,6 +992,30 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	if (cmd->data)
 		flags |= SDHCI_CMD_DATA;
 
+	if (host->quirks & SDHCI_QUIRK_MRST_RESTRICTION) {
+		u16 clk;
+
+		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+		clk |= SDHCI_CLOCK_CARD_EN;
+		sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+		/* Wait max 10 ms */
+		timeout = 10;
+		while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+			& SDHCI_CLOCK_INT_STABLE)) {
+			if (timeout == 0) {
+				printk(KERN_ERR "%s: Internal clock never "
+					"stabilised.\n",
+					mmc_hostname(host->mmc));
+				sdhci_dumpregs(host);
+				return;
+			}
+			timeout--;
+			mdelay(1);
+		}
+	}
+
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
 
@@ -1147,14 +1235,22 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
-	if (ios->bus_width == MMC_BUS_WIDTH_4)
+	if (ios->bus_width == MMC_BUS_WIDTH_8) {
+		ctrl |= SDHCI_CTRL_8BITBUS;
 		ctrl |= SDHCI_CTRL_4BITBUS;
-	else
+	} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+		ctrl &= ~SDHCI_CTRL_8BITBUS;
+		ctrl |= SDHCI_CTRL_4BITBUS;
+	} else {
+		ctrl &= ~SDHCI_CTRL_8BITBUS;
 		ctrl &= ~SDHCI_CTRL_4BITBUS;
+	}
 
-	if (ios->timing == MMC_TIMING_SD_HS)
+#ifndef CONFIG_MRST_LNW_A2_WR
+	if (ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS)
 		ctrl |= SDHCI_CTRL_HISPD;
 	else
+#endif
 		ctrl &= ~SDHCI_CTRL_HISPD;
 
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
@@ -1354,6 +1450,10 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 	BUG_ON(intmask == 0);
 
 	if (!host->cmd) {
+		if (host->quirks & SDHCI_QUIRK_MRST_RESTRICTION &&
+			!(strncmp(mmc_hostname(host->mmc), "mmc1", 4)))
+			return;
+
 		printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
 			"though no command operation was in progress.\n",
 			mmc_hostname(host->mmc), (unsigned)intmask);
@@ -1667,7 +1767,9 @@ int sdhci_add_host(struct sdhci_host *host)
 	if (debug_quirks)
 		host->quirks = debug_quirks;
 
+#ifndef CONFIG_MRST_LNW_A2_WR
 	sdhci_reset(host, SDHCI_RESET_ALL);
+#endif
 
 	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
 	host->version = (host->version & SDHCI_SPEC_VER_MASK)
@@ -1787,7 +1889,7 @@ int sdhci_add_host(struct sdhci_host *host)
 		mmc->caps |= MMC_CAP_4_BIT_DATA;
 
 	if (caps & SDHCI_CAN_DO_HISPD)
-		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
 	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
@@ -1845,7 +1947,8 @@ int sdhci_add_host(struct sdhci_host *host)
 	} else {
 		mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
 				SDHCI_MAX_BLOCK_SHIFT;
-		if (mmc->max_blk_size >= 3) {
+		if ((mmc->max_blk_size >= 3) &&
+			!(host->quirks & SDHCI_QUIRK_MRST_RESTRICTION)) {
 			printk(KERN_WARNING "%s: Invalid maximum block size, "
 				"assuming 512 bytes\n", mmc_hostname(mmc));
 			mmc->max_blk_size = 0;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 842f46f..f7ba4a2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -67,6 +67,7 @@
 #define  SDHCI_CTRL_LED		0x01
 #define  SDHCI_CTRL_4BITBUS	0x02
 #define  SDHCI_CTRL_HISPD	0x04
+#define  SDHCI_CTRL_8BITBUS	0x20
 #define  SDHCI_CTRL_DMA_MASK	0x18
 #define   SDHCI_CTRL_SDMA	0x00
 #define   SDHCI_CTRL_ADMA1	0x08
@@ -236,6 +237,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_DELAY_AFTER_POWER			(1<<23)
 /* Controller uses SDCLK instead of TMCLK for data timeouts */
 #define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK		(1<<24)
+/* Controller of Moorestown specific restriction */
+#define SDHCI_QUIRK_MRST_RESTRICTION			(1<<25)
 
 	int			irq;		/* Device IRQ */
 	void __iomem *		ioaddr;		/* Mapped address */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 2ee22e8..731f984 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -97,6 +97,7 @@ struct mmc_card {
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
 #define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
+#define MMC_STATE_SUSPENDED	(1<<4)		/* card uses block-addressing */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 
@@ -109,6 +110,7 @@ struct mmc_card {
 	struct sd_scr		scr;		/* extra SD information */
 	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
 
+	/* sdio related info */
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
 	struct sdio_cccr	cccr;		/* common card info */
 	struct sdio_cis		cis;		/* common tuple info */
@@ -118,6 +120,10 @@ struct mmc_card {
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
 
 	struct dentry		*debugfs_root;
+
+#ifdef CONFIG_SDIO_SUSPEND
+	struct mutex		pm_mutex;
+#endif
 };
 
 #define mmc_card_mmc(c)		((c)->type == MMC_TYPE_MMC)
@@ -128,6 +134,7 @@ struct mmc_card {
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_suspended(c)	((c)->state & MMC_STATE_SUSPENDED)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -139,6 +146,11 @@ static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 	return c->quirks & MMC_QUIRK_LENIENT_FN0;
 }
 
+#ifdef CONFIG_SDIO_SUSPEND
+#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
+#define mmc_card_clear_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+#endif
+
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		(dev_name(&(c)->dev))
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index eaf3636..814450a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -203,6 +203,8 @@ struct mmc_host {
 
 	struct dentry		*debugfs_root;
 
+	struct mutex		*port_mutex;
+
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index ac3ab68..a863a9a 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -50,6 +50,7 @@ struct sdio_func {
 
 	unsigned int		state;		/* function state */
 #define SDIO_STATE_PRESENT	(1<<0)		/* present in sysfs */
+#define SDIO_STATE_SUSPENDED	(1<<1)		/* present in sysfs */
 
 	u8			tmpbuf[4];	/* DMA:able scratch buffer */
 
@@ -60,9 +61,13 @@ struct sdio_func {
 };
 
 #define sdio_func_present(f)	((f)->state & SDIO_STATE_PRESENT)
+#define sdio_func_suspended(f)  ((f)->state & SDIO_STATE_SUSPENDED)
 
 #define sdio_func_set_present(f) ((f)->state |= SDIO_STATE_PRESENT)
 
+#define sdio_func_set_suspended(f)      ((f)->state |= SDIO_STATE_SUSPENDED)
+#define sdio_func_clear_suspended(f)    ((f)->state &= ~SDIO_STATE_SUSPENDED)
+
 #define sdio_func_id(f)		(dev_name(&(f)->dev))
 
 #define sdio_get_drvdata(f)	dev_get_drvdata(&(f)->dev)
@@ -78,6 +83,11 @@ struct sdio_driver {
 
 	int (*probe)(struct sdio_func *, const struct sdio_device_id *);
 	void (*remove)(struct sdio_func *);
+	int (*suspend)(struct sdio_func *, pm_message_t);
+	int (*resume)(struct sdio_func *);
+
+	int (*pre_reset)(struct sdio_func *);
+	int (*post_reset)(struct sdio_func *);
 
 	struct device_driver drv;
 };
@@ -153,5 +163,9 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func,
 extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
 	unsigned int addr, int *err_ret);
 
+extern int sdio_reset_device(struct mmc_card *card);
+
+extern int sdio_suspend_host(struct mmc_card *card, pm_message_t msg);
+extern int sdio_resume_host(struct mmc_card *card);
 #endif
 
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index cca8a04..2ec7f6c 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2396,6 +2396,8 @@
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
+#define PCI_DEVICE_ID_INTEL_MRST_SD0	0x0807
+#define PCI_DEVICE_ID_INTEL_MRST_SD1	0x0808
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_8257X_SOL	0x1062
-- 
1.6.2.5

