From febcb7168ba8b9d8e5038bc36a5ee4f0c9ee067e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 21 Apr 2012 16:42:05 +0000 Subject: cns3xxx: remove 2.6.31 support git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31418 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../patches-2.6.31/204-cns3xxx_mmc_support.patch | 2663 -------------------- 1 file changed, 2663 deletions(-) delete mode 100644 target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch (limited to 'target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch') 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 deleted file mode 100644 index 3f81ad81eb..0000000000 --- a/target/linux/cns3xxx/patches-2.6.31/204-cns3xxx_mmc_support.patch +++ /dev/null @@ -1,2663 +0,0 @@ ---- 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 -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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 - #include -@@ -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 -+#include - - #include - -@@ -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 -- cgit v1.2.3