aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch')
-rw-r--r--target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch2663
1 files changed, 2663 insertions, 0 deletions
diff --git a/target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch b/target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch
new file mode 100644
index 0000000000..3f81ad81eb
--- /dev/null
+++ b/target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch
@@ -0,0 +1,2663 @@
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -130,7 +130,7 @@ mmc_blk_getgeo(struct block_device *bdev
+ return 0;
+ }
+
+-static struct block_device_operations mmc_bdops = {
++static const struct block_device_operations mmc_bdops = {
+ .open = mmc_blk_open,
+ .release = mmc_blk_release,
+ .getgeo = mmc_blk_getgeo,
+@@ -392,13 +392,9 @@ static int mmc_blk_issue_rq(struct mmc_q
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(cmd.resp[0]) == 7));
+
+-#if 0
+ if (cmd.resp[0] & ~0x00000900)
+ printk(KERN_ERR "%s: status = %08x\n",
+ req->rq_disk->disk_name, cmd.resp[0]);
+- if (mmc_decode_status(cmd.resp))
+- goto cmd_err;
+-#endif
+ }
+
+ if (brq.cmd.error || brq.stop.error || brq.data.error) {
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -37,6 +37,9 @@
+ #include "sd_ops.h"
+ #include "sdio_ops.h"
+
++/* scott.trace */
++//#define MMC_DEBUG
++
+ static struct workqueue_struct *workqueue;
+
+ /*
+@@ -90,17 +93,30 @@ void mmc_request_done(struct mmc_host *h
+ cmd->error = 0;
+ host->ops->request(host, mrq);
+ } else {
++#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+ led_trigger_event(host->led, LED_OFF);
++#endif
+
+ pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), cmd->opcode, err,
+ cmd->resp[0], cmd->resp[1],
+ cmd->resp[2], cmd->resp[3]);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
++ mmc_hostname(host), cmd->opcode, err,
++ cmd->resp[0], cmd->resp[1],
++ cmd->resp[2], cmd->resp[3]);
++#endif
+
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: %d bytes transferred: %d\n",
++ mmc_hostname(host),
++ mrq->data->bytes_xfered, mrq->data->error);
++#endif
+ }
+
+ if (mrq->stop) {
+@@ -109,6 +125,13 @@ void mmc_request_done(struct mmc_host *h
+ mrq->stop->error,
+ mrq->stop->resp[0], mrq->stop->resp[1],
+ mrq->stop->resp[2], mrq->stop->resp[3]);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: (CMD%u): %d: %08x %08x %08x %08x\n",
++ mmc_hostname(host), mrq->stop->opcode,
++ mrq->stop->error,
++ mrq->stop->resp[0], mrq->stop->resp[1],
++ mrq->stop->resp[2], mrq->stop->resp[3]);
++#endif
+ }
+
+ if (mrq->done)
+@@ -129,6 +152,11 @@ mmc_start_request(struct mmc_host *host,
+ pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->cmd->opcode,
+ mrq->cmd->arg, mrq->cmd->flags);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: starting CMD%u arg %08x flags %08x\n",
++ mmc_hostname(host), mrq->cmd->opcode,
++ mrq->cmd->arg, mrq->cmd->flags);
++#endif
+
+ if (mrq->data) {
+ pr_debug("%s: blksz %d blocks %d flags %08x "
+@@ -137,17 +165,32 @@ mmc_start_request(struct mmc_host *host,
+ mrq->data->blocks, mrq->data->flags,
+ mrq->data->timeout_ns / 1000000,
+ mrq->data->timeout_clks);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: blksz %d blocks %d flags %08x "
++ "tsac %d ms nsac %d\n",
++ mmc_hostname(host), mrq->data->blksz,
++ mrq->data->blocks, mrq->data->flags,
++ mrq->data->timeout_ns / 1000000,
++ mrq->data->timeout_clks);
++#endif
+ }
+
+ if (mrq->stop) {
+ pr_debug("%s: CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->stop->opcode,
+ mrq->stop->arg, mrq->stop->flags);
++#ifdef MMC_DEBUG
++ printk("[MMC_DEBUG] %s: CMD%u arg %08x flags %08x\n",
++ mmc_hostname(host), mrq->stop->opcode,
++ mrq->stop->arg, mrq->stop->flags);
++#endif
+ }
+
+ WARN_ON(!host->claimed);
+
++#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+ led_trigger_event(host->led, LED_FULL);
++#endif
+
+ mrq->cmd->error = 0;
+ mrq->cmd->mrq = mrq;
+@@ -286,9 +329,9 @@ void mmc_set_data_timeout(struct mmc_dat
+ * The limit is really 250 ms, but that is
+ * insufficient for some crappy cards.
+ */
+- limit_us = 300000;
++ limit_us = 500000;
+ else
+- limit_us = 100000;
++ limit_us = 200000;
+
+ /*
+ * SDHC cards always use these fixed values.
+@@ -344,6 +387,101 @@ unsigned int mmc_align_data_size(struct
+ EXPORT_SYMBOL(mmc_align_data_size);
+
+ /**
++ * mmc_host_enable - enable a host.
++ * @host: mmc host to enable
++ *
++ * Hosts that support power saving can use the 'enable' and 'disable'
++ * methods to exit and enter power saving states. For more information
++ * see comments for struct mmc_host_ops.
++ */
++int mmc_host_enable(struct mmc_host *host)
++{
++ if (!(host->caps & MMC_CAP_DISABLE))
++ return 0;
++
++ if (host->en_dis_recurs)
++ return 0;
++
++ if (host->nesting_cnt++)
++ return 0;
++
++ cancel_delayed_work_sync(&host->disable);
++
++ if (host->enabled)
++ return 0;
++
++ if (host->ops->enable) {
++ int err;
++
++ host->en_dis_recurs = 1;
++ err = host->ops->enable(host);
++ host->en_dis_recurs = 0;
++
++ if (err) {
++ pr_debug("%s: enable error %d\n",
++ mmc_hostname(host), err);
++ return err;
++ }
++ }
++ host->enabled = 1;
++ return 0;
++}
++EXPORT_SYMBOL(mmc_host_enable);
++
++static int mmc_host_do_disable(struct mmc_host *host, int lazy)
++{
++ if (host->ops->disable) {
++ int err;
++
++ host->en_dis_recurs = 1;
++ err = host->ops->disable(host, lazy);
++ host->en_dis_recurs = 0;
++
++ if (err < 0) {
++ pr_debug("%s: disable error %d\n",
++ mmc_hostname(host), err);
++ return err;
++ }
++ if (err > 0) {
++ unsigned long delay = msecs_to_jiffies(err);
++
++ mmc_schedule_delayed_work(&host->disable, delay);
++ }
++ }
++ host->enabled = 0;
++ return 0;
++}
++
++/**
++ * mmc_host_disable - disable a host.
++ * @host: mmc host to disable
++ *
++ * Hosts that support power saving can use the 'enable' and 'disable'
++ * methods to exit and enter power saving states. For more information
++ * see comments for struct mmc_host_ops.
++ */
++int mmc_host_disable(struct mmc_host *host)
++{
++ int err;
++
++ if (!(host->caps & MMC_CAP_DISABLE))
++ return 0;
++
++ if (host->en_dis_recurs)
++ return 0;
++
++ if (--host->nesting_cnt)
++ return 0;
++
++ if (!host->enabled)
++ return 0;
++
++ err = mmc_host_do_disable(host, 0);
++ return err;
++}
++EXPORT_SYMBOL(mmc_host_disable);
++
++/**
+ * __mmc_claim_host - exclusively claim a host
+ * @host: mmc host to claim
+ * @abort: whether or not the operation should be aborted
+@@ -366,25 +504,111 @@ int __mmc_claim_host(struct mmc_host *ho
+ while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ stop = abort ? atomic_read(abort) : 0;
+- if (stop || !host->claimed)
++ if (stop || !host->claimed || host->claimer == current)
+ break;
+ spin_unlock_irqrestore(&host->lock, flags);
+ schedule();
+ spin_lock_irqsave(&host->lock, flags);
+ }
+ set_current_state(TASK_RUNNING);
+- if (!stop)
++ if (!stop) {
+ host->claimed = 1;
+- else
++ host->claimer = current;
++ host->claim_cnt += 1;
++ } else
+ wake_up(&host->wq);
+ spin_unlock_irqrestore(&host->lock, flags);
+ remove_wait_queue(&host->wq, &wait);
++ if (!stop)
++ mmc_host_enable(host);
+ return stop;
+ }
+
+ 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);
++ return claimed_host;
++}
++EXPORT_SYMBOL(mmc_try_claim_host);
++
++static void mmc_do_release_host(struct mmc_host *host)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++ if (--host->claim_cnt) {
++ /* Release for nested claim */
++ spin_unlock_irqrestore(&host->lock, flags);
++ } else {
++ host->claimed = 0;
++ host->claimer = NULL;
++ spin_unlock_irqrestore(&host->lock, flags);
++ wake_up(&host->wq);
++ }
++}
++
++void mmc_host_deeper_disable(struct work_struct *work)
++{
++ struct mmc_host *host =
++ container_of(work, struct mmc_host, disable.work);
++
++ /* If the host is claimed then we do not want to disable it anymore */
++ if (!mmc_try_claim_host(host))
++ return;
++ mmc_host_do_disable(host, 1);
++ mmc_do_release_host(host);
++}
++
++/**
++ * mmc_host_lazy_disable - lazily disable a host.
++ * @host: mmc host to disable
++ *
++ * Hosts that support power saving can use the 'enable' and 'disable'
++ * methods to exit and enter power saving states. For more information
++ * see comments for struct mmc_host_ops.
++ */
++int mmc_host_lazy_disable(struct mmc_host *host)
++{
++ if (!(host->caps & MMC_CAP_DISABLE))
++ return 0;
++
++ if (host->en_dis_recurs)
++ return 0;
++
++ if (--host->nesting_cnt)
++ return 0;
++
++ if (!host->enabled)
++ return 0;
++
++ if (host->disable_delay) {
++ mmc_schedule_delayed_work(&host->disable,
++ msecs_to_jiffies(host->disable_delay));
++ return 0;
++ } else
++ return mmc_host_do_disable(host, 1);
++}
++EXPORT_SYMBOL(mmc_host_lazy_disable);
++
++/**
+ * mmc_release_host - release a host
+ * @host: mmc host to release
+ *
+@@ -393,15 +617,11 @@ EXPORT_SYMBOL(__mmc_claim_host);
+ */
+ void mmc_release_host(struct mmc_host *host)
+ {
+- unsigned long flags;
+-
+ WARN_ON(!host->claimed);
+
+- spin_lock_irqsave(&host->lock, flags);
+- host->claimed = 0;
+- spin_unlock_irqrestore(&host->lock, flags);
++ mmc_host_lazy_disable(host);
+
+- wake_up(&host->wq);
++ mmc_do_release_host(host);
+ }
+
+ EXPORT_SYMBOL(mmc_release_host);
+@@ -687,7 +907,13 @@ void mmc_set_timing(struct mmc_host *hos
+ */
+ static void mmc_power_up(struct mmc_host *host)
+ {
+- int bit = fls(host->ocr_avail) - 1;
++ int bit;
++
++ /* 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)) {
+@@ -947,6 +1173,8 @@ void mmc_stop_host(struct mmc_host *host
+ spin_unlock_irqrestore(&host->lock, flags);
+ #endif
+
++ if (host->caps & MMC_CAP_DISABLE)
++ cancel_delayed_work(&host->disable);
+ cancel_delayed_work(&host->detect);
+ mmc_flush_scheduled_work();
+
+@@ -958,6 +1186,8 @@ void mmc_stop_host(struct mmc_host *host
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
++ mmc_bus_put(host);
++ return;
+ }
+ mmc_bus_put(host);
+
+@@ -966,6 +1196,80 @@ void mmc_stop_host(struct mmc_host *host
+ mmc_power_off(host);
+ }
+
++void mmc_power_save_host(struct mmc_host *host)
++{
++ mmc_bus_get(host);
++
++ if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
++ mmc_bus_put(host);
++ return;
++ }
++
++ if (host->bus_ops->power_save)
++ host->bus_ops->power_save(host);
++
++ mmc_bus_put(host);
++
++ mmc_power_off(host);
++}
++EXPORT_SYMBOL(mmc_power_save_host);
++
++void mmc_power_restore_host(struct mmc_host *host)
++{
++ mmc_bus_get(host);
++
++ if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
++ mmc_bus_put(host);
++ return;
++ }
++
++ mmc_power_up(host);
++ host->bus_ops->power_restore(host);
++
++ mmc_bus_put(host);
++}
++EXPORT_SYMBOL(mmc_power_restore_host);
++
++int mmc_card_awake(struct mmc_host *host)
++{
++ int err = -ENOSYS;
++
++ mmc_bus_get(host);
++
++ if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
++ err = host->bus_ops->awake(host);
++
++ mmc_bus_put(host);
++
++ return err;
++}
++EXPORT_SYMBOL(mmc_card_awake);
++
++int mmc_card_sleep(struct mmc_host *host)
++{
++ int err = -ENOSYS;
++
++ mmc_bus_get(host);
++
++ if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
++ err = host->bus_ops->sleep(host);
++
++ mmc_bus_put(host);
++
++ return err;
++}
++EXPORT_SYMBOL(mmc_card_sleep);
++
++int mmc_card_can_sleep(struct mmc_host *host)
++{
++ struct mmc_card *card = host->card;
++
++ if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
++ return 1;
++ return 0;
++}
++EXPORT_SYMBOL(mmc_card_can_sleep);
++
+ #ifdef CONFIG_PM
+
+ /**
+@@ -975,27 +1279,36 @@ void mmc_stop_host(struct mmc_host *host
+ */
+ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+ {
++ int err = 0;
++
++ if (host->caps & MMC_CAP_DISABLE)
++ cancel_delayed_work(&host->disable);
+ cancel_delayed_work(&host->detect);
+ mmc_flush_scheduled_work();
+
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops->suspend)
+- host->bus_ops->suspend(host);
+- if (!host->bus_ops->resume) {
++ err = host->bus_ops->suspend(host);
++ if (err == -ENOSYS || !host->bus_ops->resume) {
++ /*
++ * We simply "remove" the card in this case.
++ * It will be redetected on resume.
++ */
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+-
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
++ err = 0;
+ }
+ }
+ mmc_bus_put(host);
+
+- mmc_power_off(host);
++ if (!err)
++ mmc_power_off(host);
+
+- return 0;
++ return err;
+ }
+
+ EXPORT_SYMBOL(mmc_suspend_host);
+@@ -1006,12 +1319,26 @@ EXPORT_SYMBOL(mmc_suspend_host);
+ */
+ int mmc_resume_host(struct mmc_host *host)
+ {
++ int err = 0;
++
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ BUG_ON(!host->bus_ops->resume);
+- host->bus_ops->resume(host);
++ err = host->bus_ops->resume(host);
++ if (err) {
++ printk(KERN_WARNING "%s: error %d during resume "
++ "(card was removed?)\n",
++ mmc_hostname(host), err);
++ if (host->bus_ops->remove)
++ host->bus_ops->remove(host);
++ mmc_claim_host(host);
++ mmc_detach_bus(host);
++ mmc_release_host(host);
++ /* no need to bother upper layers */
++ err = 0;
++ }
+ }
+ mmc_bus_put(host);
+
+@@ -1021,7 +1348,7 @@ int mmc_resume_host(struct mmc_host *hos
+ */
+ mmc_detect_change(host, 1);
+
+- return 0;
++ return err;
+ }
+
+ EXPORT_SYMBOL(mmc_resume_host);
+--- a/drivers/mmc/core/core.h
++++ b/drivers/mmc/core/core.h
+@@ -16,10 +16,14 @@
+ #define MMC_CMD_RETRIES 3
+
+ struct mmc_bus_ops {
++ int (*awake)(struct mmc_host *);
++ int (*sleep)(struct mmc_host *);
+ void (*remove)(struct mmc_host *);
+ void (*detect)(struct mmc_host *);
+- void (*suspend)(struct mmc_host *);
+- void (*resume)(struct mmc_host *);
++ int (*suspend)(struct mmc_host *);
++ int (*resume)(struct mmc_host *);
++ void (*power_save)(struct mmc_host *);
++ void (*power_restore)(struct mmc_host *);
+ };
+
+ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
+--- a/drivers/mmc/core/debugfs.c
++++ b/drivers/mmc/core/debugfs.c
+@@ -240,7 +240,7 @@ static int mmc_ext_csd_release(struct in
+ return 0;
+ }
+
+-static struct file_operations mmc_dbg_ext_csd_fops = {
++static const struct file_operations mmc_dbg_ext_csd_fops = {
+ .open = mmc_ext_csd_open,
+ .read = mmc_ext_csd_read,
+ .release = mmc_ext_csd_release,
+--- a/drivers/mmc/core/host.c
++++ b/drivers/mmc/core/host.c
+@@ -83,6 +83,7 @@ struct mmc_host *mmc_alloc_host(int extr
+ spin_lock_init(&host->lock);
+ init_waitqueue_head(&host->wq);
+ INIT_DELAYED_WORK(&host->detect, mmc_rescan);
++ INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
+
+ /*
+ * By default, hosts do not support SGIO or large requests.
+--- a/drivers/mmc/core/host.h
++++ b/drivers/mmc/core/host.h
+@@ -14,5 +14,7 @@
+ int mmc_register_host_class(void);
+ void mmc_unregister_host_class(void);
+
++void mmc_host_deeper_disable(struct work_struct *work);
++
+ #endif
+
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_c
+ {
+ int err;
+ u8 *ext_csd;
+- unsigned int ext_csd_struct;
+
+ BUG_ON(!card);
+
+@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_c
+ goto out;
+ }
+
+- ext_csd_struct = ext_csd[EXT_CSD_REV];
+- if (ext_csd_struct > 3) {
++ card->ext_csd.rev = ext_csd[EXT_CSD_REV];
++ if (card->ext_csd.rev > 3) {
+ printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+ "version %d\n", mmc_hostname(card->host),
+- ext_csd_struct);
++ card->ext_csd.rev);
+ err = -EINVAL;
+ goto out;
+ }
+
+- if (ext_csd_struct >= 2) {
++ if (card->ext_csd.rev >= 2) {
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+@@ -241,6 +240,15 @@ static int mmc_read_ext_csd(struct mmc_c
+ goto out;
+ }
+
++ if (card->ext_csd.rev >= 3) {
++ u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
++
++ /* Sleep / awake timeout in 100ns units */
++ if (sa_shift > 0 && sa_shift <= 0x17)
++ card->ext_csd.sa_timeout =
++ 1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
++ }
++
+ out:
+ kfree(ext_csd);
+
+@@ -276,7 +284,7 @@ static struct attribute_group mmc_std_at
+ .attrs = mmc_std_attrs,
+ };
+
+-static struct attribute_group *mmc_attr_groups[] = {
++static const struct attribute_group *mmc_attr_groups[] = {
+ &mmc_std_attr_group,
+ NULL,
+ };
+@@ -408,12 +416,17 @@ static int mmc_init_card(struct mmc_host
+ (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 1);
+- if (err)
++ if (err && err != -EBADMSG)
+ goto free_card;
+
+- mmc_card_set_highspeed(card);
+-
+- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
++ if (err) {
++ printk(KERN_WARNING "%s: switch to highspeed failed\n",
++ mmc_hostname(card->host));
++ err = 0;
++ } else {
++ mmc_card_set_highspeed(card);
++ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
++ }
+ }
+
+ /*
+@@ -448,10 +461,17 @@ static int mmc_init_card(struct mmc_host
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, ext_csd_bit);
+
+- if (err)
++ if (err && err != -EBADMSG)
+ goto free_card;
+
+- mmc_set_bus_width(card->host, bus_width);
++ if (err) {
++ printk(KERN_WARNING "%s: switch to bus width %d "
++ "failed\n", mmc_hostname(card->host),
++ 1 << bus_width);
++ err = 0;
++ } else {
++ mmc_set_bus_width(card->host, bus_width);
++ }
+ }
+
+ if (!oldcard)
+@@ -507,12 +527,10 @@ static void mmc_detect(struct mmc_host *
+ }
+ }
+
+-#ifdef CONFIG_MMC_UNSAFE_RESUME
+-
+ /*
+ * Suspend callback from host.
+ */
+-static void mmc_suspend(struct mmc_host *host)
++static int mmc_suspend(struct mmc_host *host)
+ {
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+@@ -522,6 +540,8 @@ static void mmc_suspend(struct mmc_host
+ mmc_deselect_cards(host);
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_release_host(host);
++
++ return 0;
+ }
+
+ /*
+@@ -530,7 +550,7 @@ static void mmc_suspend(struct mmc_host
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+-static void mmc_resume(struct mmc_host *host)
++static int mmc_resume(struct mmc_host *host)
+ {
+ int err;
+
+@@ -541,30 +561,99 @@ static void mmc_resume(struct mmc_host *
+ err = mmc_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+
+- if (err) {
+- mmc_remove(host);
++ return err;
++}
+
+- mmc_claim_host(host);
+- mmc_detach_bus(host);
+- mmc_release_host(host);
++static void mmc_power_restore(struct mmc_host *host)
++{
++ host->card->state &= ~MMC_STATE_HIGHSPEED;
++ mmc_claim_host(host);
++ mmc_init_card(host, host->ocr, host->card);
++ mmc_release_host(host);
++}
++
++static int mmc_sleep(struct mmc_host *host)
++{
++ struct mmc_card *card = host->card;
++ int err = -ENOSYS;
++
++ if (card && card->ext_csd.rev >= 3) {
++ err = mmc_card_sleepawake(host, 1);
++ if (err < 0)
++ pr_debug("%s: Error %d while putting card into sleep",
++ mmc_hostname(host), err);
+ }
+
++ return err;
+ }
+
+-#else
++static int mmc_awake(struct mmc_host *host)
++{
++ struct mmc_card *card = host->card;
++ int err = -ENOSYS;
+
+-#define mmc_suspend NULL
+-#define mmc_resume NULL
++ if (card && card->ext_csd.rev >= 3) {
++ err = mmc_card_sleepawake(host, 0);
++ if (err < 0)
++ pr_debug("%s: Error %d while awaking sleeping card",
++ mmc_hostname(host), err);
++ }
+
+-#endif
++ return err;
++}
++
++#ifdef CONFIG_MMC_UNSAFE_RESUME
++
++static const struct mmc_bus_ops mmc_ops = {
++ .awake = mmc_awake,
++ .sleep = mmc_sleep,
++ .remove = mmc_remove,
++ .detect = mmc_detect,
++ .suspend = mmc_suspend,
++ .resume = mmc_resume,
++ .power_restore = mmc_power_restore,
++};
++
++static void mmc_attach_bus_ops(struct mmc_host *host)
++{
++ mmc_attach_bus(host, &mmc_ops);
++}
++
++#else
+
+ static const struct mmc_bus_ops mmc_ops = {
++ .awake = mmc_awake,
++ .sleep = mmc_sleep,
++ .remove = mmc_remove,
++ .detect = mmc_detect,
++ .suspend = NULL,
++ .resume = NULL,
++ .power_restore = mmc_power_restore,
++};
++
++static const struct mmc_bus_ops mmc_ops_unsafe = {
++ .awake = mmc_awake,
++ .sleep = mmc_sleep,
+ .remove = mmc_remove,
+ .detect = mmc_detect,
+ .suspend = mmc_suspend,
+ .resume = mmc_resume,
++ .power_restore = mmc_power_restore,
+ };
+
++static void mmc_attach_bus_ops(struct mmc_host *host)
++{
++ const struct mmc_bus_ops *bus_ops;
++
++ if (host->caps & MMC_CAP_NONREMOVABLE)
++ bus_ops = &mmc_ops_unsafe;
++ else
++ bus_ops = &mmc_ops;
++ mmc_attach_bus(host, bus_ops);
++}
++
++#endif
++
+ /*
+ * Starting point for MMC card init.
+ */
+@@ -575,7 +664,7 @@ int mmc_attach_mmc(struct mmc_host *host
+ BUG_ON(!host);
+ WARN_ON(!host->claimed);
+
+- mmc_attach_bus(host, &mmc_ops);
++ mmc_attach_bus_ops(host);
+
+ /*
+ * We need to get OCR a different way for SPI.
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -57,6 +57,42 @@ int mmc_deselect_cards(struct mmc_host *
+ return _mmc_select_card(host, NULL);
+ }
+
++int mmc_card_sleepawake(struct mmc_host *host, int sleep)
++{
++ struct mmc_command cmd;
++ struct mmc_card *card = host->card;
++ int err;
++
++ if (sleep)
++ mmc_deselect_cards(host);
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SLEEP_AWAKE;
++ cmd.arg = card->rca << 16;
++ if (sleep)
++ cmd.arg |= 1 << 15;
++
++ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
++ err = mmc_wait_for_cmd(host, &cmd, 0);
++ if (err)
++ return err;
++
++ /*
++ * If the host does not wait while the card signals busy, then we will
++ * will have to wait the sleep/awake timeout. Note, we cannot use the
++ * SEND_STATUS command to poll the status because that command (and most
++ * others) is invalid while the card sleeps.
++ */
++ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
++ mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
++
++ if (!sleep)
++ err = mmc_select_card(card);
++
++ return err;
++}
++
+ int mmc_go_idle(struct mmc_host *host)
+ {
+ int err;
+@@ -354,6 +390,7 @@ int mmc_switch(struct mmc_card *card, u8
+ {
+ int err;
+ struct mmc_command cmd;
++ u32 status;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+@@ -371,6 +408,28 @@ int mmc_switch(struct mmc_card *card, u8
+ if (err)
+ return err;
+
++ /* Must check status to be sure of no errors */
++ do {
++ 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;
++ } while (R1_CURRENT_STATE(status) == 7);
++
++ if (mmc_host_is_spi(card->host)) {
++ if (status & R1_SPI_ILLEGAL_COMMAND)
++ return -EBADMSG;
++ } else {
++ if (status & 0xFDFFA000)
++ printk(KERN_WARNING "%s: unexpected status %#x after "
++ "switch", mmc_hostname(card->host), status);
++ if (status & R1_SWITCH_ERROR)
++ return -EBADMSG;
++ }
++
+ return 0;
+ }
+
+--- a/drivers/mmc/core/mmc_ops.h
++++ b/drivers/mmc/core/mmc_ops.h
+@@ -25,6 +25,7 @@ int mmc_send_status(struct mmc_card *car
+ int mmc_send_cid(struct mmc_host *host, u32 *cid);
+ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
+ int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
++int mmc_card_sleepawake(struct mmc_host *host, int sleep);
+
+ #endif
+
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -314,7 +314,7 @@ static struct attribute_group sd_std_att
+ .attrs = sd_std_attrs,
+ };
+
+-static struct attribute_group *sd_attr_groups[] = {
++static const struct attribute_group *sd_attr_groups[] = {
+ &sd_std_attr_group,
+ NULL,
+ };
+@@ -561,12 +561,10 @@ static void mmc_sd_detect(struct mmc_hos
+ }
+ }
+
+-#ifdef CONFIG_MMC_UNSAFE_RESUME
+-
+ /*
+ * Suspend callback from host.
+ */
+-static void mmc_sd_suspend(struct mmc_host *host)
++static int mmc_sd_suspend(struct mmc_host *host)
+ {
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+@@ -576,6 +574,8 @@ static void mmc_sd_suspend(struct mmc_ho
+ mmc_deselect_cards(host);
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_release_host(host);
++
++ return 0;
+ }
+
+ /*
+@@ -584,7 +584,7 @@ static void mmc_sd_suspend(struct mmc_ho
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+-static void mmc_sd_resume(struct mmc_host *host)
++static int mmc_sd_resume(struct mmc_host *host)
+ {
+ int err;
+
+@@ -595,30 +595,63 @@ static void mmc_sd_resume(struct mmc_hos
+ err = mmc_sd_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+
+- if (err) {
+- mmc_sd_remove(host);
+-
+- mmc_claim_host(host);
+- mmc_detach_bus(host);
+- mmc_release_host(host);
+- }
++ return err;
++}
+
++static void mmc_sd_power_restore(struct mmc_host *host)
++{
++ host->card->state &= ~MMC_STATE_HIGHSPEED;
++ mmc_claim_host(host);
++ mmc_sd_init_card(host, host->ocr, host->card);
++ mmc_release_host(host);
+ }
+
+-#else
++#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+-#define mmc_sd_suspend NULL
+-#define mmc_sd_resume NULL
++static const struct mmc_bus_ops mmc_sd_ops = {
++ .remove = mmc_sd_remove,
++ .detect = mmc_sd_detect,
++ .suspend = mmc_sd_suspend,
++ .resume = mmc_sd_resume,
++ .power_restore = mmc_sd_power_restore,
++};
+
+-#endif
++static void mmc_sd_attach_bus_ops(struct mmc_host *host)
++{
++ mmc_attach_bus(host, &mmc_sd_ops);
++}
++
++#else
+
+ static const struct mmc_bus_ops mmc_sd_ops = {
+ .remove = mmc_sd_remove,
+ .detect = mmc_sd_detect,
++ .suspend = NULL,
++ .resume = NULL,
++ .power_restore = mmc_sd_power_restore,
++};
++
++static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
++ .remove = mmc_sd_remove,
++ .detect = mmc_sd_detect,
+ .suspend = mmc_sd_suspend,
+ .resume = mmc_sd_resume,
++ .power_restore = mmc_sd_power_restore,
+ };
+
++static void mmc_sd_attach_bus_ops(struct mmc_host *host)
++{
++ const struct mmc_bus_ops *bus_ops;
++
++ if (host->caps & MMC_CAP_NONREMOVABLE)
++ bus_ops = &mmc_sd_ops_unsafe;
++ else
++ bus_ops = &mmc_sd_ops;
++ mmc_attach_bus(host, bus_ops);
++}
++
++#endif
++
+ /*
+ * Starting point for SD card init.
+ */
+@@ -629,7 +662,7 @@ int mmc_attach_sd(struct mmc_host *host,
+ BUG_ON(!host);
+ WARN_ON(!host->claimed);
+
+- mmc_attach_bus(host, &mmc_sd_ops);
++ mmc_sd_attach_bus_ops(host);
+
+ /*
+ * We need to get OCR a different way for SPI.
+--- a/drivers/mmc/core/sdio_bus.c
++++ b/drivers/mmc/core/sdio_bus.c
+@@ -20,9 +20,6 @@
+ #include "sdio_cis.h"
+ #include "sdio_bus.h"
+
+-#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
+-#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+-
+ /* show configuration fields */
+ #define sdio_config_attr(field, format_string) \
+ static ssize_t \
+@@ -251,12 +248,15 @@ int sdio_add_func(struct sdio_func *func
+ /*
+ * Unregister a SDIO function with the driver model, and
+ * (eventually) free it.
++ * This function can be called through error paths where sdio_add_func() was
++ * never executed (because a failure occurred at an earlier point).
+ */
+ void sdio_remove_func(struct sdio_func *func)
+ {
+- if (sdio_func_present(func))
+- device_del(&func->dev);
++ if (!sdio_func_present(func))
++ return;
+
++ device_del(&func->dev);
+ put_device(&func->dev);
+ }
+
+--- a/drivers/mmc/core/sdio.c
++++ b/drivers/mmc/core/sdio.c
+@@ -165,6 +165,29 @@ static int sdio_enable_wide(struct mmc_c
+ }
+
+ /*
++ * If desired, disconnect the pull-up resistor on CD/DAT[3] (pin 1)
++ * of the card. This may be required on certain setups of boards,
++ * controllers and embedded sdio device which do not need the card's
++ * pull-up. As a result, card detection is disabled and power is saved.
++ */
++static int sdio_disable_cd(struct mmc_card *card)
++{
++ int ret;
++ u8 ctrl;
++
++ if (!card->cccr.disable_cd)
++ return 0;
++
++ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
++ if (ret)
++ return ret;
++
++ ctrl |= SDIO_BUS_CD_DISABLE;
++
++ return mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
++}
++
++/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+ static int sdio_enable_hs(struct mmc_card *card)
+@@ -195,6 +218,135 @@ static int sdio_enable_hs(struct mmc_car
+ }
+
+ /*
++ * Handle the detection and initialisation of a card.
++ *
++ * In the case of a resume, "oldcard" will contain the card
++ * we're trying to reinitialise.
++ */
++static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
++ struct mmc_card *oldcard)
++{
++ struct mmc_card *card;
++ int err;
++
++ BUG_ON(!host);
++ WARN_ON(!host->claimed);
++
++ /*
++ * Inform the card of the voltage
++ */
++ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
++ if (err)
++ goto err;
++
++ /*
++ * For SPI, enable CRC as appropriate.
++ */
++ if (mmc_host_is_spi(host)) {
++ err = mmc_spi_set_crc(host, use_spi_crc);
++ if (err)
++ goto err;
++ }
++
++ /*
++ * Allocate card structure.
++ */
++ card = mmc_alloc_card(host, NULL);
++ if (IS_ERR(card)) {
++ err = PTR_ERR(card);
++ goto err;
++ }
++
++ card->type = MMC_TYPE_SDIO;
++
++ /*
++ * For native busses: set card RCA and quit open drain mode.
++ */
++ 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 registers.
++ */
++ err = sdio_read_cccr(card);
++ if (err)
++ goto remove;
++
++ /*
++ * Read the common CIS tuples.
++ */
++ err = sdio_read_common_cis(card);
++ if (err)
++ goto remove;
++
++ if (oldcard) {
++ int same = (card->cis.vendor == oldcard->cis.vendor &&
++ card->cis.device == oldcard->cis.device);
++ mmc_remove_card(card);
++ if (!same) {
++ err = -ENOENT;
++ goto err;
++ }
++ card = oldcard;
++ return 0;
++ }
++
++ /*
++ * Switch to high-speed (if supported).
++ */
++ err = sdio_enable_hs(card);
++ if (err)
++ goto remove;
++
++ /*
++ * Change to the card's maximum speed.
++ */
++ if (mmc_card_highspeed(card)) {
++ /*
++ * The SDIO specification doesn't mention how
++ * the CIS transfer speed register relates to
++ * high-speed, but it seems that 50 MHz is
++ * mandatory.
++ */
++ mmc_set_clock(host, 50000000);
++ } else {
++ mmc_set_clock(host, card->cis.max_dtr);
++ }
++
++ /*
++ * Switch to wider bus (if supported).
++ */
++ err = sdio_enable_wide(card);
++ if (err)
++ goto remove;
++
++ if (!oldcard)
++ host->card = card;
++ return 0;
++
++remove:
++ if (!oldcard)
++ mmc_remove_card(card);
++
++err:
++ return err;
++}
++
++/*
+ * Host is being removed. Free up the current card.
+ */
+ static void mmc_sdio_remove(struct mmc_host *host)
+@@ -243,10 +395,77 @@ static void mmc_sdio_detect(struct mmc_h
+ }
+ }
+
++/*
++ * SDIO suspend. We need to suspend all functions separately.
++ * Therefore all registered functions must have drivers with suspend
++ * and resume methods. Failing that we simply remove the whole card.
++ */
++static int mmc_sdio_suspend(struct mmc_host *host)
++{
++ int i, err = 0;
++
++ for (i = 0; i < host->card->sdio_funcs; i++) {
++ struct sdio_func *func = host->card->sdio_func[i];
++ if (func && sdio_func_present(func) && func->dev.driver) {
++ const struct dev_pm_ops *pmops = func->dev.driver->pm;
++ if (!pmops || !pmops->suspend || !pmops->resume) {
++ /* force removal of entire card in that case */
++ err = -ENOSYS;
++ } else
++ err = pmops->suspend(&func->dev);
++ if (err)
++ break;
++ }
++ }
++ while (err && --i >= 0) {
++ struct sdio_func *func = host->card->sdio_func[i];
++ if (func && sdio_func_present(func) && func->dev.driver) {
++ const struct dev_pm_ops *pmops = func->dev.driver->pm;
++ pmops->resume(&func->dev);
++ }
++ }
++
++ return err;
++}
++
++static int mmc_sdio_resume(struct mmc_host *host)
++{
++ int i, err;
++
++ BUG_ON(!host);
++ BUG_ON(!host->card);
++
++ /* Basic card reinitialization. */
++ mmc_claim_host(host);
++ err = mmc_sdio_init_card(host, host->ocr, host->card);
++ mmc_release_host(host);
++
++ /*
++ * If the card looked to be the same as before suspending, then
++ * we proceed to resume all card functions. If one of them returns
++ * an error then we simply return that error to the core and the
++ * card will be redetected as new. It is the responsibility of
++ * the function driver to perform further tests with the extra
++ * knowledge it has of the card to confirm the card is indeed the
++ * same as before suspending (same MAC address for network cards,
++ * etc.) and return an error otherwise.
++ */
++ for (i = 0; !err && i < host->card->sdio_funcs; i++) {
++ struct sdio_func *func = host->card->sdio_func[i];
++ if (func && sdio_func_present(func) && func->dev.driver) {
++ const struct dev_pm_ops *pmops = func->dev.driver->pm;
++ err = pmops->resume(&func->dev);
++ }
++ }
++
++ return err;
++}
+
+ static const struct mmc_bus_ops mmc_sdio_ops = {
+ .remove = mmc_sdio_remove,
+ .detect = mmc_sdio_detect,
++ .suspend = mmc_sdio_suspend,
++ .resume = mmc_sdio_resume,
+ };
+
+
+@@ -275,13 +494,6 @@ int mmc_attach_sdio(struct mmc_host *hos
+ ocr &= ~0x7F;
+ }
+
+- if (ocr & MMC_VDD_165_195) {
+- printk(KERN_WARNING "%s: SDIO 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);
+
+ /*
+@@ -293,108 +505,31 @@ int mmc_attach_sdio(struct mmc_host *hos
+ }
+
+ /*
+- * Inform the card of the voltage
++ * Detect and init the card.
+ */
+- err = mmc_send_io_op_cond(host, host->ocr, &ocr);
++ err = mmc_sdio_init_card(host, host->ocr, NULL);
+ if (err)
+ goto err;
+-
+- /*
+- * For SPI, enable CRC as appropriate.
+- */
+- if (mmc_host_is_spi(host)) {
+- err = mmc_spi_set_crc(host, use_spi_crc);
+- if (err)
+- goto err;
+- }
++ card = host->card;
+
+ /*
+ * The number of functions on the card is encoded inside
+ * the ocr.
+ */
+ funcs = (ocr & 0x70000000) >> 28;
++ card->sdio_funcs = 0;
+
+ /*
+- * Allocate card structure.
+- */
+- card = mmc_alloc_card(host, NULL);
+- if (IS_ERR(card)) {
+- err = PTR_ERR(card);
+- goto err;
+- }
+-
+- card->type = MMC_TYPE_SDIO;
+- card->sdio_funcs = funcs;
+-
+- host->card = card;
+-
+- /*
+- * For native busses: set card RCA and quit open drain mode.
++ * If needed, disconnect card detection pull-up resistor.
+ */
+- 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 registers.
+- */
+- err = sdio_read_cccr(card);
+- if (err)
+- goto remove;
+-
+- /*
+- * Read the common CIS tuples.
+- */
+- err = sdio_read_common_cis(card);
+- if (err)
+- goto remove;
+-
+- /*
+- * Switch to high-speed (if supported).
+- */
+- err = sdio_enable_hs(card);
+- if (err)
+- goto remove;
+-
+- /*
+- * Change to the card's maximum speed.
+- */
+- if (mmc_card_highspeed(card)) {
+- /*
+- * The SDIO specification doesn't mention how
+- * the CIS transfer speed register relates to
+- * high-speed, but it seems that 50 MHz is
+- * mandatory.
+- */
+- mmc_set_clock(host, 50000000);
+- } else {
+- mmc_set_clock(host, card->cis.max_dtr);
+- }
+-
+- /*
+- * Switch to wider bus (if supported).
+- */
+- err = sdio_enable_wide(card);
++ err = sdio_disable_cd(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Initialize (but don't add) all present functions.
+ */
+- for (i = 0;i < funcs;i++) {
++ for (i = 0; i < funcs; i++, card->sdio_funcs++) {
+ err = sdio_init_func(host->card, i + 1);
+ if (err)
+ goto remove;
+--- a/drivers/mmc/core/sdio_cis.c
++++ b/drivers/mmc/core/sdio_cis.c
+@@ -29,6 +29,8 @@ static int cistpl_vers_1(struct mmc_card
+ unsigned i, nr_strings;
+ char **buffer, *string;
+
++ /* Find all null-terminated (including zero length) strings in
++ the TPLLV1_INFO field. Trailing garbage is ignored. */
+ buf += 2;
+ size -= 2;
+
+@@ -39,11 +41,8 @@ static int cistpl_vers_1(struct mmc_card
+ if (buf[i] == 0)
+ nr_strings++;
+ }
+-
+- if (buf[i-1] != '\0') {
+- printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
++ if (nr_strings == 0)
+ return 0;
+- }
+
+ size = i;
+
+@@ -98,6 +97,22 @@ static const unsigned char speed_val[16]
+ static const unsigned int speed_unit[8] =
+ { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+
++/* FUNCE tuples with these types get passed to SDIO drivers */
++static const unsigned char funce_type_whitelist[] = {
++ 4 /* CISTPL_FUNCE_LAN_NODE_ID used in Broadcom cards */
++};
++
++static int cistpl_funce_whitelisted(unsigned char type)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(funce_type_whitelist); i++) {
++ if (funce_type_whitelist[i] == type)
++ return 1;
++ }
++ return 0;
++}
++
+ static int cistpl_funce_common(struct mmc_card *card,
+ const unsigned char *buf, unsigned size)
+ {
+@@ -120,6 +135,10 @@ static int cistpl_funce_func(struct sdio
+ unsigned vsn;
+ unsigned min_size;
+
++ /* let SDIO drivers take care of whitelisted FUNCE tuples */
++ if (cistpl_funce_whitelisted(buf[0]))
++ return -EILSEQ;
++
+ vsn = func->card->cccr.sdio_vsn;
+ min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
+
+@@ -154,13 +173,12 @@ static int cistpl_funce(struct mmc_card
+ else
+ ret = cistpl_funce_common(card, buf, size);
+
+- if (ret) {
++ if (ret && ret != -EILSEQ) {
+ printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
+ "type %u\n", mmc_hostname(card->host), size, buf[0]);
+- return ret;
+ }
+
+- return 0;
++ return ret;
+ }
+
+ typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
+@@ -253,21 +271,12 @@ static int sdio_read_cis(struct mmc_card
+ for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
+ if (cis_tpl_list[i].code == tpl_code)
+ break;
+- if (i >= ARRAY_SIZE(cis_tpl_list)) {
+- /* this tuple is unknown to the core */
+- this->next = NULL;
+- this->code = tpl_code;
+- this->size = tpl_link;
+- *prev = this;
+- prev = &this->next;
+- printk(KERN_DEBUG
+- "%s: queuing CIS tuple 0x%02x length %u\n",
+- mmc_hostname(card->host), tpl_code, tpl_link);
+- } else {
++ if (i < ARRAY_SIZE(cis_tpl_list)) {
+ const struct cis_tpl *tpl = cis_tpl_list + i;
+ if (tpl_link < tpl->min_size) {
+ printk(KERN_ERR
+- "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
++ "%s: bad CIS tuple 0x%02x"
++ " (length = %u, expected >= %u)\n",
+ mmc_hostname(card->host),
+ tpl_code, tpl_link, tpl->min_size);
+ ret = -EINVAL;
+@@ -275,7 +284,30 @@ static int sdio_read_cis(struct mmc_card
+ ret = tpl->parse(card, func,
+ this->data, tpl_link);
+ }
+- kfree(this);
++ /*
++ * We don't need the tuple anymore if it was
++ * successfully parsed by the SDIO core or if it is
++ * not going to be parsed by SDIO drivers.
++ */
++ if (!ret || ret != -EILSEQ)
++ kfree(this);
++ } else {
++ /* unknown tuple */
++ ret = -EILSEQ;
++ }
++
++ if (ret == -EILSEQ) {
++ /* this tuple is unknown to the core or whitelisted */
++ this->next = NULL;
++ this->code = tpl_code;
++ this->size = tpl_link;
++ *prev = this;
++ prev = &this->next;
++ printk(KERN_DEBUG
++ "%s: queuing CIS tuple 0x%02x length %u\n",
++ mmc_hostname(card->host), tpl_code, tpl_link);
++ /* keep on analyzing tuples */
++ ret = 0;
+ }
+
+ ptr += tpl_link;
+--- a/drivers/mmc/core/sdio_io.c
++++ b/drivers/mmc/core/sdio_io.c
+@@ -624,7 +624,7 @@ void sdio_f0_writeb(struct sdio_func *fu
+
+ BUG_ON(!func);
+
+- if (addr < 0xF0 || addr > 0xFF) {
++ if ((addr < 0xF0 || addr > 0xFF) && (!mmc_card_lenient_fn0(func->card))) {
+ if (err_ret)
+ *err_ret = -EINVAL;
+ return;
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -55,6 +55,17 @@ config MMC_SDHCI_PCI
+
+ If unsure, say N.
+
++config MMC_SDHCI_CNS3XXX
++ tristate "SDHCI support on CNS3XXX"
++ depends on MMC_SDHCI && ARCH_CNS3XXX
++ help
++ This selects the Secure Digital Host Controller Interface (SDHCI)
++ in Cavium Networks CNS3XXX SOCs.
++
++ If you have a controller with this interface, say Y or M here.
++
++ If unsure, say N.
++
+ config MMC_RICOH_MMC
+ tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ depends on MMC_SDHCI_PCI
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_MMC_IMX) += imxmmc.o
+ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
+ obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
++obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
+ obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
+ obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
+ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -27,6 +27,15 @@
+
+ #define DRIVER_NAME "sdhci"
+
++#define SDHCI_DEBUG
++#undef SDHCI_DEBUG
++
++#ifdef SDHCI_DEBUG
++#define sd_printk(x...) printk(x)
++#else
++#define sd_printk(x...) do { } while(0)
++#endif
++
+ #define DBG(f, x...) \
+ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+
+@@ -43,6 +52,39 @@ static void sdhci_finish_data(struct sdh
+ static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
+ static void sdhci_finish_command(struct sdhci_host *);
+
++static void sdhci_dumpallregs(struct sdhci_host *host)
++{
++#ifdef SDHCI_DEBUG
++ printk(" _______________________________________________\n");
++
++ printk(" 0x00: 0x%08x | 0x04: 0x%08x\n", sdhci_readl(host, 0x00), sdhci_readl(host, 0x04));
++ printk(" 0x08: 0x%08x | 0x0C: 0x%08x\n", sdhci_readl(host, 0x08), sdhci_readl(host, 0x0C));
++ printk(" 0x10: 0x%08x | 0x14: 0x%08x\n", sdhci_readl(host, 0x10), sdhci_readl(host, 0x14));
++ printk(" 0x18: 0x%08x | 0x1C: 0x%08x\n", sdhci_readl(host, 0x18), sdhci_readl(host, 0x1C));
++ printk(" -----------------| 0x24: 0x%08x\n", sdhci_readl(host, 0x24));
++ printk(" 0x28: 0x%08x | 0x2C: 0x%08x\n", sdhci_readl(host, 0x28), sdhci_readl(host, 0x2C));
++ printk(" 0x30: 0x%08x | 0x34: 0x%08x\n", sdhci_readl(host, 0x30), sdhci_readl(host, 0x34));
++ printk(" 0x38: 0x%08x | 0x3C: 0x%08x\n", sdhci_readl(host, 0x38), sdhci_readl(host, 0x3C));
++ printk(" 0x40: 0x%08x | 0x44: 0x%08x\n", sdhci_readl(host, 0x40), sdhci_readl(host, 0x44));
++ printk(" 0x48: 0x%08x | 0x4C: 0x%08x\n", sdhci_readl(host, 0x48), sdhci_readl(host, 0x4C));
++ printk(" 0x50: 0x%08x | 0xFC: 0x%08x\n", sdhci_readl(host, 0x50), sdhci_readl(host, 0xFC));
++//#else
++ printk(KERN_DEBUG " _______________________________________________\n");
++
++ printk(KERN_DEBUG " 0x00: 0x%08x | 0x04: 0x%08x\n", sdhci_readl(host, 0x00), sdhci_readl(host, 0x04));
++ printk(KERN_DEBUG " 0x08: 0x%08x | 0x0C: 0x%08x\n", sdhci_readl(host, 0x08), sdhci_readl(host, 0x0C));
++ printk(KERN_DEBUG " 0x10: 0x%08x | 0x14: 0x%08x\n", sdhci_readl(host, 0x10), sdhci_readl(host, 0x14));
++ printk(KERN_DEBUG " 0x18: 0x%08x | 0x1C: 0x%08x\n", sdhci_readl(host, 0x18), sdhci_readl(host, 0x1C));
++ printk(KERN_DEBUG " -----------------| 0x24: 0x%08x\n", sdhci_readl(host, 0x24));
++ printk(KERN_DEBUG " 0x28: 0x%08x | 0x2C: 0x%08x\n", sdhci_readl(host, 0x28), sdhci_readl(host, 0x2C));
++ printk(KERN_DEBUG " 0x30: 0x%08x | 0x34: 0x%08x\n", sdhci_readl(host, 0x30), sdhci_readl(host, 0x34));
++ printk(KERN_DEBUG " 0x38: 0x%08x | 0x3C: 0x%08x\n", sdhci_readl(host, 0x38), sdhci_readl(host, 0x3C));
++ printk(KERN_DEBUG " 0x40: 0x%08x | 0x44: 0x%08x\n", sdhci_readl(host, 0x40), sdhci_readl(host, 0x44));
++ printk(KERN_DEBUG " 0x48: 0x%08x | 0x4C: 0x%08x\n", sdhci_readl(host, 0x48), sdhci_readl(host, 0x4C));
++ printk(KERN_DEBUG " 0x50: 0x%08x | 0xFC: 0x%08x\n", sdhci_readl(host, 0x50), sdhci_readl(host, 0xFC));
++#endif
++}
++
+ static void sdhci_dumpregs(struct sdhci_host *host)
+ {
+ printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+@@ -591,6 +633,9 @@ static u8 sdhci_calc_timeout(struct sdhc
+ target_timeout = data->timeout_ns / 1000 +
+ data->timeout_clks / host->clock;
+
++ if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
++ host->timeout_clk = host->clock / 1000;
++
+ /*
+ * Figure out needed cycles.
+ * We do this in steps in order to fit inside a 32 bit int.
+@@ -622,7 +667,7 @@ static u8 sdhci_calc_timeout(struct sdhc
+ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
+ {
+ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
+- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
++ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ACMD12ERR | SDHCI_INT_ADMA_ERROR;
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+@@ -652,7 +697,7 @@ static void sdhci_prepare_data(struct sd
+ count = sdhci_calc_timeout(host, data);
+ sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+
+- if (host->flags & SDHCI_USE_DMA)
++ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
+ host->flags |= SDHCI_REQ_USE_DMA;
+
+ /*
+@@ -736,11 +781,21 @@ static void sdhci_prepare_data(struct sd
+ } else {
+ int sg_cnt;
+
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), mmc_dev(host->mmc) = %p \n", mmc_dev(host->mmc));
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), data->sg = %p \n", data->sg);
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), data->sg_len = %d \n", data->sg_len);
+ sg_cnt = dma_map_sg(mmc_dev(host->mmc),
+ data->sg, data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE :
+ DMA_TO_DEVICE);
++ if (data->sg == NULL) {
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), data->sg = (NULL) \n");
++ return;
++ }
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), data->sg = %p \n", data->sg);
++ sd_printk("[SDHCI_DEBUG] dma_map_sg(), sg_cnt = %d \n", sg_cnt);
++
+ if (sg_cnt == 0) {
+ /*
+ * This only happens when someone fed
+@@ -750,6 +805,7 @@ static void sdhci_prepare_data(struct sd
+ host->flags &= ~SDHCI_REQ_USE_DMA;
+ } else {
+ WARN_ON(sg_cnt != 1);
++ sd_printk("[SDHCI_DEBUG] sg_dma_address() => %08x \n", sg_dma_address(data->sg));
+ sdhci_writel(host, sg_dma_address(data->sg),
+ SDHCI_DMA_ADDRESS);
+ }
+@@ -763,14 +819,32 @@ static void sdhci_prepare_data(struct sd
+ */
+ if (host->version >= SDHCI_SPEC_200) {
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
++#ifdef SDHCI_USE_LEDS_CLASS
++ ctrl |= SDHCI_CTRL_LED;
++#else
++ ctrl &= ~SDHCI_CTRL_LED;
++#endif
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if ((host->flags & SDHCI_REQ_USE_DMA) &&
+ (host->flags & SDHCI_USE_ADMA))
+ ctrl |= SDHCI_CTRL_ADMA32;
+ else
+ ctrl |= SDHCI_CTRL_SDMA;
++
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+- }
++ } else if (host->version == SDHCI_SPEC_100) {
++ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
++#ifdef SDHCI_USE_LEDS_CLASS
++ ctrl |= SDHCI_CTRL_LED;
++#else
++ ctrl &= ~SDHCI_CTRL_LED;
++#endif
++ ctrl &= ~SDHCI_CTRL_DMA_MASK;
++ if (host->flags & SDHCI_REQ_USE_DMA)
++ ctrl |= SDHCI_CTRL_SDMA;
++
++ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
++ }
+
+ if (!(host->flags & SDHCI_REQ_USE_DMA)) {
+ int flags;
+@@ -795,15 +869,26 @@ static void sdhci_set_transfer_mode(stru
+ struct mmc_data *data)
+ {
+ u16 mode;
++ u8 bgctrl;
+
+ if (data == NULL)
+ return;
+
+ WARN_ON(!host->data);
+
++ bgctrl = sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL);
++ if (host->quirks & SDHCI_QUIRK_READ_WAIT_CTRL)
++ bgctrl |= SDHCI_READ_WAIT_CTRL;
++ sdhci_writeb(host, bgctrl, SDHCI_BLOCK_GAP_CONTROL);
++
+ mode = SDHCI_TRNS_BLK_CNT_EN;
+- if (data->blocks > 1)
++
++ if (data->blocks > 1) {
+ mode |= SDHCI_TRNS_MULTI;
++
++ if (host->quirks & SDHCI_QUIRK_AUTO_CMD12)
++ mode |= SDHCI_TRNS_ACMD12;
++ }
+ if (data->flags & MMC_DATA_READ)
+ mode |= SDHCI_TRNS_READ;
+ if (host->flags & SDHCI_REQ_USE_DMA)
+@@ -812,6 +897,20 @@ static void sdhci_set_transfer_mode(stru
+ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
+ }
+
++static void shdci_check_dma_overrun(struct sdhci_host *host, struct mmc_data *data)
++{
++ u32 dma_pos = sdhci_readl(host, SDHCI_DMA_ADDRESS);
++ u32 dma_start = sg_dma_address(data->sg);
++ u32 dma_end = dma_start + data->sg->length;
++
++ /* Test whether we ended up moving more data than was originally requested. */
++ if (dma_pos <= dma_end)
++ return;
++
++ printk(KERN_ERR "%s: dma overrun, dma %08x, req %08x..%08x\n",
++ mmc_hostname(host->mmc), dma_pos, dma_start, dma_end);
++}
++
+ static void sdhci_finish_data(struct sdhci_host *host)
+ {
+ struct mmc_data *data;
+@@ -825,6 +924,9 @@ static void sdhci_finish_data(struct sdh
+ if (host->flags & SDHCI_USE_ADMA)
+ sdhci_adma_table_post(host, data);
+ else {
++ shdci_check_dma_overrun(host, data);
++
++ sd_printk("[SDHCI_DEBUG] dma_unmap_sg(), data->sg_len = %d \n", data->sg_len);
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+@@ -866,12 +968,16 @@ static void sdhci_send_command(struct sd
+
+ WARN_ON(host->cmd);
+
++ sd_printk("[SDHCI_DEBUG] sdhci_send_command() \n");
++
+ /* Wait max 10 ms */
+ timeout = 10;
+
+ mask = SDHCI_CMD_INHIBIT;
+ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+ mask |= SDHCI_DATA_INHIBIT;
++ if ((cmd->data != NULL))
++ mask |= SDHCI_DATA_INHIBIT;
+
+ /* We shouldn't wait for data inihibit for stop commands, even
+ though they might use busy signaling */
+@@ -925,7 +1031,11 @@ static void sdhci_send_command(struct sd
+ if (cmd->data)
+ flags |= SDHCI_CMD_DATA;
+
++ sd_printk("[SDHCI_DEBUG] sdhci_send_command() => %08x \n", SDHCI_MAKE_CMD(cmd->opcode, flags));
++ sdhci_dumpallregs(host);
+ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
++ sd_printk("[SDHCI_DEBUG] sdhci_send_command(): After issue command \n");
++ sdhci_dumpallregs(host);
+ }
+
+ static void sdhci_finish_command(struct sdhci_host *host)
+@@ -934,6 +1044,8 @@ static void sdhci_finish_command(struct
+
+ BUG_ON(host->cmd == NULL);
+
++ sd_printk("[SDHCI_DEBUG] sdhci_finish_command() \n");
++
+ if (host->cmd->flags & MMC_RSP_PRESENT) {
+ if (host->cmd->flags & MMC_RSP_136) {
+ /* CRC is stripped so we need to do some shifting. */
+@@ -991,8 +1103,8 @@ static void sdhci_set_clock(struct sdhci
+ clk |= SDHCI_CLOCK_INT_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+- /* Wait max 10 ms */
+- timeout = 10;
++ /* Wait max 20 ms */
++ timeout = 20;
+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
+@@ -1154,6 +1266,12 @@ static void sdhci_set_ios(struct mmc_hos
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+
++#ifdef SDHCI_USE_LEDS_CLASS
++ ctrl |= SDHCI_CTRL_LED;
++#else
++ ctrl &= ~SDHCI_CTRL_LED;
++#endif
++
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ /*
+@@ -1321,7 +1439,11 @@ static void sdhci_timeout_timer(unsigned
+ if (host->mrq) {
+ printk(KERN_ERR "%s: Timeout waiting for hardware "
+ "interrupt.\n", mmc_hostname(host->mmc));
++#ifdef SDHCI_DEBUG
++ sdhci_dumpallregs(host);
++#else
+ sdhci_dumpregs(host);
++#endif
+
+ if (host->data) {
+ host->data->error = -ETIMEDOUT;
+@@ -1508,6 +1630,10 @@ static irqreturn_t sdhci_irq(int irq, vo
+ DBG("*** %s got interrupt: 0x%08x\n",
+ mmc_hostname(host->mmc), intmask);
+
++#ifdef SDHCI_DEBUG
++ printk("*** %s got interrupt: 0x%08x\n", mmc_hostname(host->mmc), intmask);
++#endif
++
+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+@@ -1597,7 +1723,7 @@ int sdhci_resume_host(struct sdhci_host
+ {
+ int ret;
+
+- if (host->flags & SDHCI_USE_DMA) {
++ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma)
+ host->ops->enable_dma(host);
+ }
+@@ -1678,23 +1804,20 @@ int sdhci_add_host(struct sdhci_host *ho
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+
+ if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
+- host->flags |= SDHCI_USE_DMA;
+- else if (!(caps & SDHCI_CAN_DO_DMA))
+- DBG("Controller doesn't have DMA capability\n");
++ host->flags |= SDHCI_USE_SDMA;
++ else if (!(caps & SDHCI_CAN_DO_SDMA))
++ DBG("Controller doesn't have SDMA capability\n");
+ else
+- host->flags |= SDHCI_USE_DMA;
++ host->flags |= SDHCI_USE_SDMA;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+- (host->flags & SDHCI_USE_DMA)) {
++ (host->flags & SDHCI_USE_SDMA)) {
+ DBG("Disabling DMA as it is marked broken\n");
+- host->flags &= ~SDHCI_USE_DMA;
++ host->flags &= ~SDHCI_USE_SDMA;
+ }
+
+- if (host->flags & SDHCI_USE_DMA) {
+- if ((host->version >= SDHCI_SPEC_200) &&
+- (caps & SDHCI_CAN_DO_ADMA2))
+- host->flags |= SDHCI_USE_ADMA;
+- }
++ if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
++ host->flags |= SDHCI_USE_ADMA;
+
+ if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
+ (host->flags & SDHCI_USE_ADMA)) {
+@@ -1702,13 +1825,14 @@ int sdhci_add_host(struct sdhci_host *ho
+ host->flags &= ~SDHCI_USE_ADMA;
+ }
+
+- if (host->flags & SDHCI_USE_DMA) {
++ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma) {
+ if (host->ops->enable_dma(host)) {
+ printk(KERN_WARNING "%s: No suitable DMA "
+ "available. Falling back to PIO.\n",
+ mmc_hostname(mmc));
+- host->flags &= ~(SDHCI_USE_DMA | SDHCI_USE_ADMA);
++ host->flags &=
++ ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
+ }
+ }
+ }
+@@ -1736,7 +1860,7 @@ int sdhci_add_host(struct sdhci_host *ho
+ * mask, but PIO does not need the hw shim so we set a new
+ * mask here in that case.
+ */
+- if (!(host->flags & SDHCI_USE_DMA)) {
++ if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
+ host->dma_mask = DMA_BIT_MASK(64);
+ mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
+ }
+@@ -1757,13 +1881,15 @@ int sdhci_add_host(struct sdhci_host *ho
+ host->timeout_clk =
+ (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+ if (host->timeout_clk == 0) {
+- if (!host->ops->get_timeout_clock) {
++ if (host->ops->get_timeout_clock) {
++ host->timeout_clk = host->ops->get_timeout_clock(host);
++ } else if (!(host->quirks &
++ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+ printk(KERN_ERR
+ "%s: Hardware doesn't specify timeout clock "
+ "frequency.\n", mmc_hostname(mmc));
+ return -ENODEV;
+ }
+- host->timeout_clk = host->ops->get_timeout_clock(host);
+ }
+ if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+ host->timeout_clk *= 1000;
+@@ -1772,7 +1898,8 @@ int sdhci_add_host(struct sdhci_host *ho
+ * Set host parameters.
+ */
+ mmc->ops = &sdhci_ops;
+- if (host->ops->get_min_clock)
++ if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK &&
++ host->ops->set_clock && host->ops->get_min_clock)
+ mmc->f_min = host->ops->get_min_clock(host);
+ else
+ mmc->f_min = host->max_clk / 256;
+@@ -1810,7 +1937,7 @@ int sdhci_add_host(struct sdhci_host *ho
+ */
+ if (host->flags & SDHCI_USE_ADMA)
+ mmc->max_hw_segs = 128;
+- else if (host->flags & SDHCI_USE_DMA)
++ else if (host->flags & SDHCI_USE_SDMA)
+ mmc->max_hw_segs = 1;
+ else /* PIO */
+ mmc->max_hw_segs = 128;
+@@ -1893,10 +2020,10 @@ int sdhci_add_host(struct sdhci_host *ho
+
+ mmc_add_host(mmc);
+
+- printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s%s\n",
++ printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n",
+ mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
+- (host->flags & SDHCI_USE_ADMA)?"A":"",
+- (host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
++ (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
++ (host->flags & SDHCI_USE_SDMA) ? "SDMA" : "PIO");
+
+ sdhci_enable_card_detection(host);
+
+--- /dev/null
++++ b/drivers/mmc/host/sdhci-cns3xxx.c
+@@ -0,0 +1,313 @@
++/*******************************************************************************
++ *
++ * drivers/mmc/host/sdhci-cns3xxx.c
++ *
++ * SDHCI support for the CNS3XXX SOCs
++ *
++ * Author: Scott Shu
++ *
++ * Copyright (c) 2008 Cavium Networks
++ *
++ * This file is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, Version 2, as
++ * published by the Free Software Foundation.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
++ * NONINFRINGEMENT. See the GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this file; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or
++ * visit http://www.gnu.org/licenses/.
++ *
++ * This file may also be available under a different license from Cavium.
++ * Contact Cavium Networks for more information
++ *
++ ******************************************************************************/
++
++#include <linux/delay.h>
++#include <linux/highmem.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++
++#include <linux/mmc/host.h>
++
++#include <asm/scatterlist.h>
++#include <asm/io.h>
++#include <linux/interrupt.h>
++
++#include <mach/sdhci.h>
++#include <mach/pm.h>
++
++#include "sdhci.h"
++
++//#define DEBUG
++
++#define MAX_BUS_CLK (4)
++
++static unsigned __initdata use_dma = 0;
++
++struct sdhci_cns3xxx {
++ struct sdhci_host *host;
++ struct platform_device *pdev;
++ struct resource *ioarea;
++ struct cns3xxx_sdhci_platdata *pdata;
++ struct clk *clk_io;
++ struct clk *clk_bus[MAX_BUS_CLK];
++};
++
++static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host)
++{
++ int clk = 50000000;
++
++ return clk;
++}
++
++static unsigned int sdhci_cns3xxx_get_timeout_clk(struct sdhci_host *host)
++{
++ return sdhci_cns3xxx_get_max_clk(host) / 100000;
++}
++
++/*
++ * sdhci_cns3xxx_set_clock - callback on clock change
++ *
++ * When the card's clock is going to be changed, look at the new frequency
++ * and find the best clock source to go with it.
++ */
++static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
++{
++ u16 clk;
++ unsigned long timeout;
++
++ if (clock == host->clock)
++ return;
++
++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
++
++ if (clock == 0)
++ goto out;
++#if 1
++ clk = 0x03 << SDHCI_DIVIDER_SHIFT; /* base clock divided by 3 */
++#else
++ /* high speed mode or normal speed mode */
++ if (0x4 & sdhci_readw(host, 0x28)) {
++ clk = 0x03 << SDHCI_DIVIDER_SHIFT; /* base clock divided by 3 */
++ } else {
++ clk = 0x02 << SDHCI_DIVIDER_SHIFT; /* base clock divided by 4 */
++ }
++#endif
++ clk |= SDHCI_CLOCK_INT_EN;
++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
++
++ timeout = 10;
++ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
++ & SDHCI_CLOCK_INT_STABLE)) {
++ if (timeout == 0) {
++ return;
++ }
++ timeout--;
++ mdelay(1);
++ }
++
++ clk |= SDHCI_CLOCK_CARD_EN;
++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
++
++ host->timeout_clk = sdhci_cns3xxx_get_timeout_clk(host);
++out:
++ host->clock = clock;
++}
++
++static struct sdhci_ops sdhci_cns3xxx_ops = {
++ .get_max_clock = sdhci_cns3xxx_get_max_clk,
++ .get_timeout_clock = sdhci_cns3xxx_get_timeout_clk,
++ .set_clock = sdhci_cns3xxx_set_clock,
++};
++
++static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev)
++{
++ struct cns3xxx_sdhci_platdata *pdata = pdev->dev.platform_data;
++ struct device *dev = &pdev->dev;
++ struct sdhci_host *host;
++ struct sdhci_cns3xxx *sc;
++ struct resource *res;
++ int ret, irq;
++
++ if (!pdata) {
++ dev_err(dev, "no device data specified\n");
++ return -ENOENT;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "no irq specified\n");
++ return irq;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(dev, "no memory specified\n");
++ return -ENOENT;
++ }
++
++ host = sdhci_alloc_host(dev, sizeof(*sc));
++ if (IS_ERR(host)) {
++ dev_err(dev, "sdhci_alloc_host() failed\n");
++ return PTR_ERR(host);
++ }
++
++ sc = sdhci_priv(host);
++
++ sc->host = host;
++ sc->pdev = pdev;
++ sc->pdata = pdata;
++
++ platform_set_drvdata(pdev, host);
++
++ sc->ioarea = request_mem_region(res->start, resource_size(res), mmc_hostname(host->mmc));
++ if (!sc->ioarea) {
++ dev_err(dev, "failed to reserve register area\n");
++ ret = -ENXIO;
++ goto err_req_regs;
++ }
++
++ host->ioaddr = ioremap_nocache(res->start, resource_size(res));
++ if (!host->ioaddr) {
++ dev_err(dev, "failed to map registers\n");
++ ret = -ENXIO;
++ goto err_req_regs;
++ }
++
++ host->hw_name = "cns3xxx";
++ host->ops = &sdhci_cns3xxx_ops;
++ host->quirks = 0;
++ host->irq = irq;
++
++ if (use_dma != 1) {
++ host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
++ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
++ } else {
++ host->quirks |= SDHCI_QUIRK_FORCE_DMA;
++ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
++ host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE);
++ host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
++ //host->quirks |= SDHCI_QUIRK_FORCE_BLK_SZ_2048;
++ //host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
++ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
++ host->quirks |= SDHCI_QUIRK_AUTO_CMD12;
++ host->quirks |= SDHCI_QUIRK_READ_WAIT_CTRL;
++ }
++
++ //host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
++
++ host->quirks |= SDHCI_QUIRK_NONSTANDARD_CLOCK;
++
++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
++
++ ret = sdhci_add_host(host);
++ if (ret) {
++ dev_err(dev, "sdhci_add_host() failed (%d)\n", ret);
++ goto err_add_host;
++ }
++
++ return 0;
++
++err_add_host:
++ free_irq(host->irq, host);
++ iounmap(host->ioaddr);
++ release_resource(sc->ioarea);
++ kfree(sc->ioarea);
++
++err_req_regs:
++ sdhci_free_host(host);
++
++ return ret;
++}
++
++static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct sdhci_host *host = dev_get_drvdata(dev);
++ struct resource *res;
++
++ pr_debug("%s: remove=%p\n", __func__, pdev);
++
++ sdhci_remove_host(host, 0);
++ sdhci_free_host(host);
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(res->start, resource_size(res));
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++
++static int sdhci_cns3xxx_suspend(struct platform_device *dev, pm_message_t state)
++{
++
++ return 0;
++}
++
++static int sdhci_cns3xxx_resume(struct platform_device *dev)
++{
++
++ return 0;
++}
++
++#else
++#define sdhci_cns3xxx_suspend NULL
++#define sdhci_cns3xxx_resume NULL
++#endif /* CONFIG_PM */
++
++static struct platform_driver sdhci_cns3xxx_driver = {
++ .probe = sdhci_cns3xxx_probe,
++ .remove = __devexit_p(sdhci_cns3xxx_remove),
++ .suspend = sdhci_cns3xxx_suspend,
++ .resume = sdhci_cns3xxx_resume,
++ .driver = {
++ .name = "cns3xxx-sdhci",
++ .owner = THIS_MODULE,
++ },
++};
++
++static char banner[] __initdata = KERN_INFO "cns3xxx-sdhci, (c) 2009 Cavium Networks\n";
++
++static int __init sdhci_cns3xxx_init(void)
++{
++#ifdef CONFIG_SILICON
++ unsigned long gpioapin = __raw_readl((void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0014));;
++#else
++ unsigned long status = __raw_readl((void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0700));
++#endif
++
++ printk(banner);
++
++#ifdef CONFIG_SILICON
++ /* MMC/SD pins share with GPIOA */
++ __raw_writel(gpioapin | (0x1fff0004), (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0014));
++ cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
++ cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
++#else
++ /* insert a delay on SDIO output interface (only for FPGA mode & high-speed mode) */
++ __raw_writel(status | (1 << 4), (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0700));
++#endif
++ return platform_driver_register(&sdhci_cns3xxx_driver);
++}
++
++static void __exit sdhci_cns3xxx_exit(void)
++{
++ platform_driver_unregister(&sdhci_cns3xxx_driver);
++}
++
++module_init(sdhci_cns3xxx_init);
++module_exit(sdhci_cns3xxx_exit);
++
++module_param(use_dma, uint, 0);
++
++MODULE_AUTHOR("Scott Shu");
++MODULE_DESCRIPTION("Cavium Networks CNS3XXX SDHCI glue");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:cns3xxx-sdhci");
++
++MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 0");
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -8,6 +8,8 @@
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
++#ifndef __SDHCI_H
++#define __SDHCI_H
+
+ #include <linux/scatterlist.h>
+ #include <linux/compiler.h>
+@@ -78,6 +80,7 @@
+ #define SDHCI_POWER_330 0x0E
+
+ #define SDHCI_BLOCK_GAP_CONTROL 0x2A
++#define SDHCI_READ_WAIT_CTRL 0x04
+
+ #define SDHCI_WAKE_UP_CONTROL 0x2B
+
+@@ -143,7 +146,7 @@
+ #define SDHCI_CAN_DO_ADMA2 0x00080000
+ #define SDHCI_CAN_DO_ADMA1 0x00100000
+ #define SDHCI_CAN_DO_HISPD 0x00200000
+-#define SDHCI_CAN_DO_DMA 0x00400000
++#define SDHCI_CAN_DO_SDMA 0x00400000
+ #define SDHCI_CAN_VDD_330 0x01000000
+ #define SDHCI_CAN_VDD_300 0x02000000
+ #define SDHCI_CAN_VDD_180 0x04000000
+@@ -232,6 +235,12 @@ struct sdhci_host {
+ #define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22)
+ /* Controller needs 10ms delay between applying power and clock */
+ #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 uses Auto CMD12 */
++#define SDHCI_QUIRK_AUTO_CMD12 (1<<25)
++/* Controller uses read wait control protocol */
++#define SDHCI_QUIRK_READ_WAIT_CTRL (1<<26)
+
+ int irq; /* Device IRQ */
+ void __iomem * ioaddr; /* Mapped address */
+@@ -250,7 +259,7 @@ struct sdhci_host {
+ spinlock_t lock; /* Mutex */
+
+ int flags; /* Host attributes */
+-#define SDHCI_USE_DMA (1<<0) /* Host is DMA capable */
++#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
+ #define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */
+ #define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
+ #define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
+@@ -406,3 +415,5 @@ extern void sdhci_remove_host(struct sdh
+ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
+ extern int sdhci_resume_host(struct sdhci_host *host);
+ #endif
++
++#endif /* __SDHCI_H */
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -40,6 +40,8 @@ struct mmc_csd {
+ };
+
+ struct mmc_ext_csd {
++ u8 rev;
++ unsigned int sa_timeout; /* Units: 100ns */
+ unsigned int hs_max_dtr;
+ unsigned int sectors;
+ };
+@@ -62,7 +64,8 @@ struct sdio_cccr {
+ low_speed:1,
+ wide_bus:1,
+ high_power:1,
+- high_speed:1;
++ high_speed:1,
++ disable_cd:1;
+ };
+
+ struct sdio_cis {
+@@ -94,6 +97,8 @@ 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 */
++ unsigned int quirks; /* card quirks */
++#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
+
+ u32 raw_cid[4]; /* raw card CID */
+ u32 raw_csd[4]; /* raw card CSD */
+@@ -129,6 +134,11 @@ struct mmc_card {
+ #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+ #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+
++static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
++{
++ return c->quirks & MMC_QUIRK_LENIENT_FN0;
++}
++
+ #define mmc_card_name(c) ((c)->cid.prod_name)
+ #define mmc_card_id(c) (dev_name(&(c)->dev))
+
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -139,6 +139,7 @@ extern unsigned int mmc_align_data_size(
+
+ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
+ extern void mmc_release_host(struct mmc_host *host);
++extern int mmc_try_claim_host(struct mmc_host *host);
+
+ /**
+ * mmc_claim_host - exclusively claim a host
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -11,6 +11,7 @@
+ #define LINUX_MMC_HOST_H
+
+ #include <linux/leds.h>
++#include <linux/sched.h>
+
+ #include <linux/mmc/core.h>
+
+@@ -51,6 +52,35 @@ struct mmc_ios {
+ };
+
+ struct mmc_host_ops {
++ /*
++ * Hosts that support power saving can use the 'enable' and 'disable'
++ * methods to exit and enter power saving states. 'enable' is called
++ * when the host is claimed and 'disable' is called (or scheduled with
++ * a delay) when the host is released. The 'disable' is scheduled if
++ * the disable delay set by 'mmc_set_disable_delay()' is non-zero,
++ * otherwise 'disable' is called immediately. 'disable' may be
++ * scheduled repeatedly, to permit ever greater power saving at the
++ * expense of ever greater latency to re-enable. Rescheduling is
++ * determined by the return value of the 'disable' method. A positive
++ * value gives the delay in milliseconds.
++ *
++ * In the case where a host function (like set_ios) may be called
++ * with or without the host claimed, enabling and disabling can be
++ * done directly and will nest correctly. Call 'mmc_host_enable()' and
++ * 'mmc_host_lazy_disable()' for this purpose, but note that these
++ * functions must be paired.
++ *
++ * Alternatively, 'mmc_host_enable()' may be paired with
++ * 'mmc_host_disable()' which calls 'disable' immediately. In this
++ * case the 'disable' method will be called with 'lazy' set to 0.
++ * This is mainly useful for error paths.
++ *
++ * Because lazy disable may be called from a work queue, the 'disable'
++ * method must claim the host when 'lazy' != 0, which will work
++ * correctly because recursion is detected and handled.
++ */
++ int (*enable)(struct mmc_host *host);
++ int (*disable)(struct mmc_host *host, int lazy);
+ void (*request)(struct mmc_host *host, struct mmc_request *req);
+ /*
+ * Avoid calling these three functions too often or in a "fast path",
+@@ -118,6 +148,9 @@ struct mmc_host {
+ #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
+ #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
+ #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
++#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
++#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
++#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
+
+ /* host specific block data */
+ unsigned int max_seg_size; /* see blk_queue_max_segment_size */
+@@ -142,9 +175,18 @@ struct mmc_host {
+ unsigned int removed:1; /* host is being removed */
+ #endif
+
++ /* Only used with MMC_CAP_DISABLE */
++ int enabled; /* host is enabled */
++ int nesting_cnt; /* "enable" nesting count */
++ int en_dis_recurs; /* detect recursion */
++ unsigned int disable_delay; /* disable delay in msecs */
++ struct delayed_work disable; /* disabling work */
++
+ struct mmc_card *card; /* device attached to this host */
+
+ wait_queue_head_t wq;
++ struct task_struct *claimer; /* task that has host claimed */
++ int claim_cnt; /* "claim" nesting count */
+
+ struct delayed_work detect;
+
+@@ -183,6 +225,9 @@ static inline void *mmc_priv(struct mmc_
+ extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
+ extern int mmc_resume_host(struct mmc_host *);
+
++extern void mmc_power_save_host(struct mmc_host *host);
++extern void mmc_power_restore_host(struct mmc_host *host);
++
+ extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
+ extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
+
+@@ -197,5 +242,19 @@ struct regulator;
+ int mmc_regulator_get_ocrmask(struct regulator *supply);
+ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+
++int mmc_card_awake(struct mmc_host *host);
++int mmc_card_sleep(struct mmc_host *host);
++int mmc_card_can_sleep(struct mmc_host *host);
++
++int mmc_host_enable(struct mmc_host *host);
++int mmc_host_disable(struct mmc_host *host);
++int mmc_host_lazy_disable(struct mmc_host *host);
++
++static inline void mmc_set_disable_delay(struct mmc_host *host,
++ unsigned int disable_delay)
++{
++ host->disable_delay = disable_delay;
++}
++
+ #endif
+
+--- a/include/linux/mmc/mmc.h
++++ b/include/linux/mmc/mmc.h
+@@ -31,6 +31,7 @@
+ #define MMC_ALL_SEND_CID 2 /* bcr R2 */
+ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
+ #define MMC_SET_DSR 4 /* bc [31:16] RCA */
++#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
+ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */
+ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */
+@@ -127,6 +128,7 @@
+ #define R1_STATUS(x) (x & 0xFFFFE000)
+ #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */
++#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
+ #define R1_APP_CMD (1 << 5) /* sr, c */
+
+ /*
+@@ -254,6 +256,7 @@ struct _mmc_csd {
+ #define EXT_CSD_CARD_TYPE 196 /* RO */
+ #define EXT_CSD_REV 192 /* RO */
+ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
++#define EXT_CSD_S_A_TIMEOUT 217
+
+ /*
+ * EXT_CSD field definitions
+--- a/include/linux/mmc/sdio_func.h
++++ b/include/linux/mmc/sdio_func.h
+@@ -67,6 +67,7 @@ struct sdio_func {
+
+ #define sdio_get_drvdata(f) dev_get_drvdata(&(f)->dev)
+ #define sdio_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d)
++#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
+
+ /*
+ * SDIO function device driver
+@@ -81,6 +82,8 @@ struct sdio_driver {
+ struct device_driver drv;
+ };
+
++#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
++
+ /**
+ * SDIO_DEVICE - macro used to describe a specific SDIO device
+ * @vend: the 16 bit manufacturer code
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -22,6 +22,12 @@
+ /*
+ * Vendors and devices. Sort key: vendor first, device next.
+ */
++#define SDIO_VENDOR_ID_INTEL 0x0089
++#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
++#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403
++#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
++#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405
++#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406
+
+ #define SDIO_VENDOR_ID_MARVELL 0x02df
+ #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103