diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-mmc-driver-1.0.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-mmc-driver-1.0.patch | 1367 |
1 files changed, 1367 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-mmc-driver-1.0.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-mmc-driver-1.0.patch new file mode 100644 index 000000000..b93f76a8e --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-mmc-driver-1.0.patch @@ -0,0 +1,1367 @@ +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, ®); ++ ++ 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 + |