Jelajahi Sumber

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (66 commits)
  mmc: add new sdhci-pxa driver for Marvell SoCs
  mmc: make number of mmcblk minors configurable
  mmc_spi: Recover from CRC errors for r/w operation over SPI.
  mmc: sdhci-pltfm: add -pltfm driver for imx35/51
  mmc: sdhci-of-esdhc: factor out common stuff
  mmc: sdhci_pltfm: pass more data on custom init call
  mmc: sdhci: introduce get_ro private write-protect hook
  mmc: sdhci-pltfm: move .h file into appropriate subdir
  mmc: sdhci-pltfm: Add structure for host-specific data
  mmc: fix cb710 kconfig dependency warning
  mmc: cb710: remove debugging printk (info duplicated from mmc-core)
  mmc: cb710: clear irq handler on init() error path
  mmc: cb710: remove unnecessary msleep()
  mmc: cb710: implement get_cd() callback
  mmc: cb710: partially demystify clock selection
  mmc: add a file to debugfs for changing host clock at runtime
  mmc: sdhci: allow for eMMC 74 clock generation by controller
  mmc: sdhci: highspeed: check for mmc as well as sd cards
  mmc: sdhci: Add Moorestown device support
  mmc: sdhci: Intel Medfield support
  ...
Linus Torvalds 14 tahun lalu
induk
melakukan
00ebb6382b
60 mengubah file dengan 2535 tambahan dan 565 penghapusan
  1. 6 0
      Documentation/devices.txt
  2. 32 0
      arch/arm/plat-pxa/include/plat/sdhci.h
  3. 1 3
      drivers/mmc/Makefile
  4. 17 0
      drivers/mmc/card/Kconfig
  5. 0 4
      drivers/mmc/card/Makefile
  6. 36 25
      drivers/mmc/card/block.c
  7. 392 77
      drivers/mmc/card/mmc_test.c
  8. 8 6
      drivers/mmc/card/queue.c
  9. 0 4
      drivers/mmc/core/Makefile
  10. 48 10
      drivers/mmc/core/bus.c
  11. 1 1
      drivers/mmc/core/bus.h
  12. 116 63
      drivers/mmc/core/core.c
  13. 4 3
      drivers/mmc/core/core.h
  14. 33 2
      drivers/mmc/core/debugfs.c
  15. 1 2
      drivers/mmc/core/host.c
  16. 48 10
      drivers/mmc/core/mmc.c
  17. 7 3
      drivers/mmc/core/sd.c
  18. 45 9
      drivers/mmc/core/sdio.c
  19. 83 2
      drivers/mmc/core/sdio_bus.c
  20. 37 0
      drivers/mmc/host/Kconfig
  21. 3 4
      drivers/mmc/host/Makefile
  22. 5 6
      drivers/mmc/host/at91_mci.c
  23. 2 3
      drivers/mmc/host/atmel-mci.c
  24. 2 2
      drivers/mmc/host/au1xmmc.c
  25. 1 1
      drivers/mmc/host/bfin_sdh.c
  26. 25 29
      drivers/mmc/host/cb710-mmc.c
  27. 3 5
      drivers/mmc/host/davinci_mmc.c
  28. 1 2
      drivers/mmc/host/imxmmc.c
  29. 1 2
      drivers/mmc/host/jz4740_mmc.c
  30. 22 2
      drivers/mmc/host/mmc_spi.c
  31. 19 12
      drivers/mmc/host/mmci.c
  32. 1 2
      drivers/mmc/host/msm_sdcc.c
  33. 1 2
      drivers/mmc/host/mvsdio.c
  34. 1 2
      drivers/mmc/host/mxcmmc.c
  35. 1 2
      drivers/mmc/host/omap.c
  36. 14 10
      drivers/mmc/host/omap_hsmmc.c
  37. 34 9
      drivers/mmc/host/pxamci.c
  38. 1 2
      drivers/mmc/host/s3cmci.c
  39. 1 1
      drivers/mmc/host/sdhci-cns3xxx.c
  40. 143 0
      drivers/mmc/host/sdhci-esdhc-imx.c
  41. 83 0
      drivers/mmc/host/sdhci-esdhc.h
  42. 8 62
      drivers/mmc/host/sdhci-of-esdhc.c
  43. 89 0
      drivers/mmc/host/sdhci-pci.c
  44. 37 7
      drivers/mmc/host/sdhci-pltfm.c
  45. 9 1
      drivers/mmc/host/sdhci-pltfm.h
  46. 253 0
      drivers/mmc/host/sdhci-pxa.c
  47. 57 29
      drivers/mmc/host/sdhci.c
  48. 21 129
      drivers/mmc/host/sdhci.h
  49. 1 2
      drivers/mmc/host/sh_mmcif.c
  50. 1 2
      drivers/mmc/host/tifm_sd.c
  51. 566 0
      drivers/mmc/host/ushc.c
  52. 1 2
      drivers/mmc/host/via-sdmmc.c
  53. 1 2
      drivers/mmc/host/wbsd.c
  54. 6 0
      include/linux/mmc/card.h
  55. 2 0
      include/linux/mmc/core.h
  56. 43 5
      include/linux/mmc/host.h
  57. 9 1
      include/linux/mmc/mmc.h
  58. 1 1
      include/linux/mmc/sdhci-pltfm.h
  59. 144 0
      include/linux/mmc/sdhci.h
  60. 7 0
      include/linux/pci_ids.h

+ 6 - 0
Documentation/devices.txt

@@ -2520,6 +2520,12 @@ Your cooperation is appreciated.
 		  8 = /dev/mmcblk1      Second SD/MMC card
 		  8 = /dev/mmcblk1      Second SD/MMC card
 		    ...
 		    ...
 
 
+		The start of next SD/MMC card can be configured with
+		CONFIG_MMC_BLOCK_MINORS, or overridden at boot/modprobe
+		time using the mmcblk.perdev_minors option. That would
+		bump the offset between each card to be the configured
+		value instead of the default 8.
+
 179 char	CCube DVXChip-based PCI products
 179 char	CCube DVXChip-based PCI products
 		  0 = /dev/dvxirq0	First DVX device
 		  0 = /dev/dvxirq0	First DVX device
 		  1 = /dev/dvxirq1	Second DVX device
 		  1 = /dev/dvxirq1	Second DVX device

+ 32 - 0
arch/arm/plat-pxa/include/plat/sdhci.h

@@ -0,0 +1,32 @@
+/* linux/arch/arm/plat-pxa/include/plat/sdhci.h
+ *
+ * Copyright 2010 Marvell
+ *	Zhangfei Gao <zhangfei.gao@marvell.com>
+ *
+ * PXA Platform - SDHCI platform data definitions
+ *
+ * This program 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.
+ */
+
+#ifndef __PLAT_PXA_SDHCI_H
+#define __PLAT_PXA_SDHCI_H
+
+/* pxa specific flag */
+/* Require clock free running */
+#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
+
+/*
+ * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
+ * @max_speed: the maximum speed supported
+ * @quirks: quirks of specific device
+ * @flags: flags for platform requirement
+ */
+struct sdhci_pxa_platdata {
+	unsigned int	max_speed;
+	unsigned int	quirks;
+	unsigned int	flags;
+};
+
+#endif /* __PLAT_PXA_SDHCI_H */

+ 1 - 3
drivers/mmc/Makefile

@@ -2,9 +2,7 @@
 # Makefile for the kernel mmc device drivers.
 # Makefile for the kernel mmc device drivers.
 #
 #
 
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-	EXTRA_CFLAGS		+= -DDEBUG
-endif
+subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
 
 
 obj-$(CONFIG_MMC)		+= core/
 obj-$(CONFIG_MMC)		+= core/
 obj-$(CONFIG_MMC)		+= card/
 obj-$(CONFIG_MMC)		+= card/

+ 17 - 0
drivers/mmc/card/Kconfig

@@ -14,6 +14,23 @@ config MMC_BLOCK
 	  mount the filesystem. Almost everyone wishing MMC support
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 	  should say Y or M here.
 
 
+config MMC_BLOCK_MINORS
+	int "Number of minors per block device"
+	range 4 256
+	default 8
+	help
+	  Number of minors per block device. One is needed for every
+	  partition on the disk (plus one for the whole disk).
+
+	  Number of total MMC minors available is 256, so your number
+	  of supported block devices will be limited to 256 divided
+	  by this number.
+
+	  Default is 8 to be backwards compatible with previous
+	  hardwired device numbering.
+
+	  If unsure, say 8 here.
+
 config MMC_BLOCK_BOUNCE
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
 	depends on MMC_BLOCK

+ 0 - 4
drivers/mmc/card/Makefile

@@ -2,10 +2,6 @@
 # Makefile for MMC/SD card drivers
 # Makefile for MMC/SD card drivers
 #
 #
 
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-	EXTRA_CFLAGS		+= -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
 obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
 mmc_block-objs			:= block.o queue.o
 mmc_block-objs			:= block.o queue.o
 obj-$(CONFIG_MMC_TEST)		+= mmc_test.o
 obj-$(CONFIG_MMC_TEST)		+= mmc_test.o

+ 36 - 25
drivers/mmc/card/block.c

@@ -43,15 +43,27 @@
 #include "queue.h"
 #include "queue.h"
 
 
 MODULE_ALIAS("mmc:block");
 MODULE_ALIAS("mmc:block");
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "mmcblk."
+
+static DEFINE_MUTEX(block_mutex);
 
 
 /*
 /*
- * max 8 partitions per card
+ * The defaults come from config options but can be overriden by module
+ * or bootarg options.
  */
  */
-#define MMC_SHIFT	3
-#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)
+static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
 
 
-static DEFINE_MUTEX(block_mutex);
-static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
+/*
+ * We've only got one major, so number of mmcblk devices is
+ * limited to 256 / number of minors per device.
+ */
+static int max_devices;
+
+/* 256 minors, so at most 256 separate devices */
+static DECLARE_BITMAP(dev_use, 256);
 
 
 /*
 /*
  * There is one mmc_blk_data per slot.
  * There is one mmc_blk_data per slot.
@@ -67,6 +79,9 @@ struct mmc_blk_data {
 
 
 static DEFINE_MUTEX(open_lock);
 static DEFINE_MUTEX(open_lock);
 
 
+module_param(perdev_minors, int, 0444);
+MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
 {
 	struct mmc_blk_data *md;
 	struct mmc_blk_data *md;
@@ -88,10 +103,10 @@ static void mmc_blk_put(struct mmc_blk_data *md)
 	md->usage--;
 	md->usage--;
 	if (md->usage == 0) {
 	if (md->usage == 0) {
 		int devmaj = MAJOR(disk_devt(md->disk));
 		int devmaj = MAJOR(disk_devt(md->disk));
-		int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
+		int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
 
 
 		if (!devmaj)
 		if (!devmaj)
-			devidx = md->disk->first_minor >> MMC_SHIFT;
+			devidx = md->disk->first_minor / perdev_minors;
 
 
 		blk_cleanup_queue(md->queue.queue);
 		blk_cleanup_queue(md->queue.queue);
 
 
@@ -373,7 +388,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 			readcmd = MMC_READ_SINGLE_BLOCK;
 			readcmd = MMC_READ_SINGLE_BLOCK;
 			writecmd = MMC_WRITE_BLOCK;
 			writecmd = MMC_WRITE_BLOCK;
 		}
 		}
-
 		if (rq_data_dir(req) == READ) {
 		if (rq_data_dir(req) == READ) {
 			brq.cmd.opcode = readcmd;
 			brq.cmd.opcode = readcmd;
 			brq.data.flags |= MMC_DATA_READ;
 			brq.data.flags |= MMC_DATA_READ;
@@ -567,8 +581,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	struct mmc_blk_data *md;
 	struct mmc_blk_data *md;
 	int devidx, ret;
 	int devidx, ret;
 
 
-	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-	if (devidx >= MMC_NUM_MINORS)
+	devidx = find_first_zero_bit(dev_use, max_devices);
+	if (devidx >= max_devices)
 		return ERR_PTR(-ENOSPC);
 		return ERR_PTR(-ENOSPC);
 	__set_bit(devidx, dev_use);
 	__set_bit(devidx, dev_use);
 
 
@@ -585,7 +599,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 */
 	 */
 	md->read_only = mmc_blk_readonly(card);
 	md->read_only = mmc_blk_readonly(card);
 
 
-	md->disk = alloc_disk(1 << MMC_SHIFT);
+	md->disk = alloc_disk(perdev_minors);
 	if (md->disk == NULL) {
 	if (md->disk == NULL) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err_kfree;
 		goto err_kfree;
@@ -602,7 +616,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	md->queue.data = md;
 	md->queue.data = md;
 
 
 	md->disk->major	= MMC_BLOCK_MAJOR;
 	md->disk->major	= MMC_BLOCK_MAJOR;
-	md->disk->first_minor = devidx << MMC_SHIFT;
+	md->disk->first_minor = devidx * perdev_minors;
 	md->disk->fops = &mmc_bdops;
 	md->disk->fops = &mmc_bdops;
 	md->disk->private_data = md;
 	md->disk->private_data = md;
 	md->disk->queue = md->queue.queue;
 	md->disk->queue = md->queue.queue;
@@ -620,7 +634,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 * messages to tell when the card is present.
 	 * messages to tell when the card is present.
 	 */
 	 */
 
 
-	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+		"mmcblk%d", devidx);
 
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
 	blk_queue_logical_block_size(md->queue.queue, 512);
 
 
@@ -651,23 +666,15 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 static int
 static int
 mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 {
 {
-	struct mmc_command cmd;
 	int err;
 	int err;
 
 
-	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-	if (mmc_card_blockaddr(card))
-		return 0;
-
 	mmc_claim_host(card->host);
 	mmc_claim_host(card->host);
-	cmd.opcode = MMC_SET_BLOCKLEN;
-	cmd.arg = 512;
-	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-	err = mmc_wait_for_cmd(card->host, &cmd, 5);
+	err = mmc_set_blocklen(card, 512);
 	mmc_release_host(card->host);
 	mmc_release_host(card->host);
 
 
 	if (err) {
 	if (err) {
-		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-			md->disk->disk_name, cmd.arg, err);
+		printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
+			md->disk->disk_name, err);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -678,7 +685,6 @@ static int mmc_blk_probe(struct mmc_card *card)
 {
 {
 	struct mmc_blk_data *md;
 	struct mmc_blk_data *md;
 	int err;
 	int err;
-
 	char cap_str[10];
 	char cap_str[10];
 
 
 	/*
 	/*
@@ -768,6 +774,11 @@ static int __init mmc_blk_init(void)
 {
 {
 	int res;
 	int res;
 
 
+	if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
+		pr_info("mmcblk: using %d minors per device\n", perdev_minors);
+
+	max_devices = 256 / perdev_minors;
+
 	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
 	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
 	if (res)
 	if (res)
 		goto out;
 		goto out;

+ 392 - 77
drivers/mmc/card/mmc_test.c

@@ -17,6 +17,11 @@
 
 
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/swap.h>		/* For nr_free_buffer_pages() */
 #include <linux/swap.h>		/* For nr_free_buffer_pages() */
+#include <linux/list.h>
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
 
 
 #define RESULT_OK		0
 #define RESULT_OK		0
 #define RESULT_FAIL		1
 #define RESULT_FAIL		1
@@ -56,7 +61,9 @@ struct mmc_test_mem {
  * struct mmc_test_area - information for performance tests.
  * struct mmc_test_area - information for performance tests.
  * @max_sz: test area size (in bytes)
  * @max_sz: test area size (in bytes)
  * @dev_addr: address on card at which to do performance tests
  * @dev_addr: address on card at which to do performance tests
- * @max_segs: maximum segments in scatterlist @sg
+ * @max_tfr: maximum transfer size allowed by driver (in bytes)
+ * @max_segs: maximum segments allowed by driver in scatterlist @sg
+ * @max_seg_sz: maximum segment size allowed by driver
  * @blocks: number of (512 byte) blocks currently mapped by @sg
  * @blocks: number of (512 byte) blocks currently mapped by @sg
  * @sg_len: length of currently mapped scatterlist @sg
  * @sg_len: length of currently mapped scatterlist @sg
  * @mem: allocated memory
  * @mem: allocated memory
@@ -65,13 +72,59 @@ struct mmc_test_mem {
 struct mmc_test_area {
 struct mmc_test_area {
 	unsigned long max_sz;
 	unsigned long max_sz;
 	unsigned int dev_addr;
 	unsigned int dev_addr;
+	unsigned int max_tfr;
 	unsigned int max_segs;
 	unsigned int max_segs;
+	unsigned int max_seg_sz;
 	unsigned int blocks;
 	unsigned int blocks;
 	unsigned int sg_len;
 	unsigned int sg_len;
 	struct mmc_test_mem *mem;
 	struct mmc_test_mem *mem;
 	struct scatterlist *sg;
 	struct scatterlist *sg;
 };
 };
 
 
+/**
+ * struct mmc_test_transfer_result - transfer results for performance tests.
+ * @link: double-linked list
+ * @count: amount of group of sectors to check
+ * @sectors: amount of sectors to check in one group
+ * @ts: time values of transfer
+ * @rate: calculated transfer rate
+ */
+struct mmc_test_transfer_result {
+	struct list_head link;
+	unsigned int count;
+	unsigned int sectors;
+	struct timespec ts;
+	unsigned int rate;
+};
+
+/**
+ * struct mmc_test_general_result - results for tests.
+ * @link: double-linked list
+ * @card: card under test
+ * @testcase: number of test case
+ * @result: result of test run
+ * @tr_lst: transfer measurements if any as mmc_test_transfer_result
+ */
+struct mmc_test_general_result {
+	struct list_head link;
+	struct mmc_card *card;
+	int testcase;
+	int result;
+	struct list_head tr_lst;
+};
+
+/**
+ * struct mmc_test_dbgfs_file - debugfs related file.
+ * @link: double-linked list
+ * @card: card under test
+ * @file: file created under debugfs
+ */
+struct mmc_test_dbgfs_file {
+	struct list_head link;
+	struct mmc_card *card;
+	struct dentry *file;
+};
+
 /**
 /**
  * struct mmc_test_card - test information.
  * struct mmc_test_card - test information.
  * @card: card under test
  * @card: card under test
@@ -79,6 +132,7 @@ struct mmc_test_area {
  * @buffer: transfer buffer
  * @buffer: transfer buffer
  * @highmem: buffer for highmem tests
  * @highmem: buffer for highmem tests
  * @area: information for performance tests
  * @area: information for performance tests
+ * @gr: pointer to results of current testcase
  */
  */
 struct mmc_test_card {
 struct mmc_test_card {
 	struct mmc_card	*card;
 	struct mmc_card	*card;
@@ -88,7 +142,8 @@ struct mmc_test_card {
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_HIGHMEM
 	struct page	*highmem;
 	struct page	*highmem;
 #endif
 #endif
-	struct mmc_test_area area;
+	struct mmc_test_area		area;
+	struct mmc_test_general_result	*gr;
 };
 };
 
 
 /*******************************************************************/
 /*******************************************************************/
@@ -100,17 +155,7 @@ struct mmc_test_card {
  */
  */
 static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
 static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
 {
 {
-	struct mmc_command cmd;
-	int ret;
-
-	cmd.opcode = MMC_SET_BLOCKLEN;
-	cmd.arg = size;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-	ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
-	if (ret)
-		return ret;
-
-	return 0;
+	return mmc_set_blocklen(test->card, size);
 }
 }
 
 
 /*
 /*
@@ -245,27 +290,38 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
 
 
 /*
 /*
  * Allocate a lot of memory, preferrably max_sz but at least min_sz.  In case
  * Allocate a lot of memory, preferrably max_sz but at least min_sz.  In case
- * there isn't much memory do not exceed 1/16th total lowmem pages.
+ * there isn't much memory do not exceed 1/16th total lowmem pages.  Also do
+ * not exceed a maximum number of segments and try not to make segments much
+ * bigger than maximum segment size.
  */
  */
 static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
 static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
-					       unsigned long max_sz)
+					       unsigned long max_sz,
+					       unsigned int max_segs,
+					       unsigned int max_seg_sz)
 {
 {
 	unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
 	unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
 	unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
 	unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
+	unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
 	unsigned long page_cnt = 0;
 	unsigned long page_cnt = 0;
 	unsigned long limit = nr_free_buffer_pages() >> 4;
 	unsigned long limit = nr_free_buffer_pages() >> 4;
 	struct mmc_test_mem *mem;
 	struct mmc_test_mem *mem;
 
 
 	if (max_page_cnt > limit)
 	if (max_page_cnt > limit)
 		max_page_cnt = limit;
 		max_page_cnt = limit;
-	if (max_page_cnt < min_page_cnt)
-		max_page_cnt = min_page_cnt;
+	if (min_page_cnt > max_page_cnt)
+		min_page_cnt = max_page_cnt;
+
+	if (max_seg_page_cnt > max_page_cnt)
+		max_seg_page_cnt = max_page_cnt;
+
+	if (max_segs > max_page_cnt)
+		max_segs = max_page_cnt;
 
 
 	mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
 	mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
 	if (!mem)
 	if (!mem)
 		return NULL;
 		return NULL;
 
 
-	mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt,
+	mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
 			   GFP_KERNEL);
 			   GFP_KERNEL);
 	if (!mem->arr)
 	if (!mem->arr)
 		goto out_free;
 		goto out_free;
@@ -276,7 +332,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
 		gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
 		gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
 				__GFP_NORETRY;
 				__GFP_NORETRY;
 
 
-		order = get_order(max_page_cnt << PAGE_SHIFT);
+		order = get_order(max_seg_page_cnt << PAGE_SHIFT);
 		while (1) {
 		while (1) {
 			page = alloc_pages(flags, order);
 			page = alloc_pages(flags, order);
 			if (page || !order)
 			if (page || !order)
@@ -295,6 +351,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
 			break;
 			break;
 		max_page_cnt -= 1UL << order;
 		max_page_cnt -= 1UL << order;
 		page_cnt += 1UL << order;
 		page_cnt += 1UL << order;
+		if (mem->cnt >= max_segs) {
+			if (page_cnt < min_page_cnt)
+				goto out_free;
+			break;
+		}
 	}
 	}
 
 
 	return mem;
 	return mem;
@@ -310,7 +371,8 @@ out_free:
  */
  */
 static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
 static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
 			   struct scatterlist *sglist, int repeat,
 			   struct scatterlist *sglist, int repeat,
-			   unsigned int max_segs, unsigned int *sg_len)
+			   unsigned int max_segs, unsigned int max_seg_sz,
+			   unsigned int *sg_len)
 {
 {
 	struct scatterlist *sg = NULL;
 	struct scatterlist *sg = NULL;
 	unsigned int i;
 	unsigned int i;
@@ -322,8 +384,10 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
 		for (i = 0; i < mem->cnt; i++) {
 		for (i = 0; i < mem->cnt; i++) {
 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
 
-			if (sz < len)
+			if (len > sz)
 				len = sz;
 				len = sz;
+			if (len > max_seg_sz)
+				len = max_seg_sz;
 			if (sg)
 			if (sg)
 				sg = sg_next(sg);
 				sg = sg_next(sg);
 			else
 			else
@@ -355,6 +419,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
 				       unsigned long sz,
 				       unsigned long sz,
 				       struct scatterlist *sglist,
 				       struct scatterlist *sglist,
 				       unsigned int max_segs,
 				       unsigned int max_segs,
+				       unsigned int max_seg_sz,
 				       unsigned int *sg_len)
 				       unsigned int *sg_len)
 {
 {
 	struct scatterlist *sg = NULL;
 	struct scatterlist *sg = NULL;
@@ -365,7 +430,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
 	sg_init_table(sglist, max_segs);
 	sg_init_table(sglist, max_segs);
 
 
 	*sg_len = 0;
 	*sg_len = 0;
-	while (sz && i) {
+	while (sz) {
 		base = page_address(mem->arr[--i].page);
 		base = page_address(mem->arr[--i].page);
 		cnt = 1 << mem->arr[i].order;
 		cnt = 1 << mem->arr[i].order;
 		while (sz && cnt) {
 		while (sz && cnt) {
@@ -374,7 +439,9 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
 				continue;
 				continue;
 			last_addr = addr;
 			last_addr = addr;
 			len = PAGE_SIZE;
 			len = PAGE_SIZE;
-			if (sz < len)
+			if (len > max_seg_sz)
+				len = max_seg_sz;
+			if (len > sz)
 				len = sz;
 				len = sz;
 			if (sg)
 			if (sg)
 				sg = sg_next(sg);
 				sg = sg_next(sg);
@@ -386,6 +453,8 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
 			sz -= len;
 			sz -= len;
 			*sg_len += 1;
 			*sg_len += 1;
 		}
 		}
+		if (i == 0)
+			i = mem->cnt;
 	}
 	}
 
 
 	if (sg)
 	if (sg)
@@ -420,6 +489,30 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
 	return bytes;
 	return bytes;
 }
 }
 
 
+/*
+ * Save transfer results for future usage
+ */
+static void mmc_test_save_transfer_result(struct mmc_test_card *test,
+	unsigned int count, unsigned int sectors, struct timespec ts,
+	unsigned int rate)
+{
+	struct mmc_test_transfer_result *tr;
+
+	if (!test->gr)
+		return;
+
+	tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+	if (!tr)
+		return;
+
+	tr->count = count;
+	tr->sectors = sectors;
+	tr->ts = ts;
+	tr->rate = rate;
+
+	list_add_tail(&tr->link, &test->gr->tr_lst);
+}
+
 /*
 /*
  * Print the transfer rate.
  * Print the transfer rate.
  */
  */
@@ -436,8 +529,10 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
 	printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
 	printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
 			 "seconds (%u kB/s, %u KiB/s)\n",
 			 "seconds (%u kB/s, %u KiB/s)\n",
 			 mmc_hostname(test->card->host), sectors, sectors >> 1,
 			 mmc_hostname(test->card->host), sectors, sectors >> 1,
-			 (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
+			 (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
 			 (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
 			 (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+
+	mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
 }
 }
 
 
 /*
 /*
@@ -458,9 +553,11 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
 			 mmc_hostname(test->card->host), count, sectors, count,
 			 mmc_hostname(test->card->host), count, sectors, count,
-			 sectors >> 1, (sectors == 1 ? ".5" : ""),
+			 sectors >> 1, (sectors & 1 ? ".5" : ""),
 			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
 			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
 			 rate / 1000, rate / 1024);
 			 rate / 1000, rate / 1024);
+
+	mmc_test_save_transfer_result(test, count, sectors, ts, rate);
 }
 }
 
 
 /*
 /*
@@ -1215,16 +1312,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
 			     int max_scatter)
 			     int max_scatter)
 {
 {
 	struct mmc_test_area *t = &test->area;
 	struct mmc_test_area *t = &test->area;
+	int err;
 
 
 	t->blocks = sz >> 9;
 	t->blocks = sz >> 9;
 
 
 	if (max_scatter) {
 	if (max_scatter) {
-		return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
-						   t->max_segs, &t->sg_len);
-	} else {
-		return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+		err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
+						  t->max_segs, t->max_seg_sz,
 				       &t->sg_len);
 				       &t->sg_len);
+	} else {
+		err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+				      t->max_seg_sz, &t->sg_len);
 	}
 	}
+	if (err)
+		printk(KERN_INFO "%s: Failed to map sg list\n",
+		       mmc_hostname(test->card->host));
+	return err;
 }
 }
 
 
 /*
 /*
@@ -1249,6 +1352,22 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
 	struct timespec ts1, ts2;
 	struct timespec ts1, ts2;
 	int ret;
 	int ret;
 
 
+	/*
+	 * In the case of a maximally scattered transfer, the maximum transfer
+	 * size is further limited by using PAGE_SIZE segments.
+	 */
+	if (max_scatter) {
+		struct mmc_test_area *t = &test->area;
+		unsigned long max_tfr;
+
+		if (t->max_seg_sz >= PAGE_SIZE)
+			max_tfr = t->max_segs * PAGE_SIZE;
+		else
+			max_tfr = t->max_segs * t->max_seg_sz;
+		if (sz > max_tfr)
+			sz = max_tfr;
+	}
+
 	ret = mmc_test_area_map(test, sz, max_scatter);
 	ret = mmc_test_area_map(test, sz, max_scatter);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
@@ -1274,7 +1393,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
  */
  */
 static int mmc_test_area_fill(struct mmc_test_card *test)
 static int mmc_test_area_fill(struct mmc_test_card *test)
 {
 {
-	return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+	return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
 				1, 0, 0);
 				1, 0, 0);
 }
 }
 
 
@@ -1328,16 +1447,29 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
 		t->max_sz = TEST_AREA_MAX_SIZE;
 		t->max_sz = TEST_AREA_MAX_SIZE;
 	else
 	else
 		t->max_sz = (unsigned long)test->card->pref_erase << 9;
 		t->max_sz = (unsigned long)test->card->pref_erase << 9;
+
+	t->max_segs = test->card->host->max_segs;
+	t->max_seg_sz = test->card->host->max_seg_size;
+
+	t->max_tfr = t->max_sz;
+	if (t->max_tfr >> 9 > test->card->host->max_blk_count)
+		t->max_tfr = test->card->host->max_blk_count << 9;
+	if (t->max_tfr > test->card->host->max_req_size)
+		t->max_tfr = test->card->host->max_req_size;
+	if (t->max_tfr / t->max_seg_sz > t->max_segs)
+		t->max_tfr = t->max_segs * t->max_seg_sz;
+
 	/*
 	/*
-	 * Try to allocate enough memory for the whole area.  Less is OK
+	 * Try to allocate enough memory for a max. sized transfer.  Less is OK
 	 * because the same memory can be mapped into the scatterlist more than
 	 * because the same memory can be mapped into the scatterlist more than
-	 * once.
+	 * once.  Also, take into account the limits imposed on scatterlist
+	 * segments by the host driver.
 	 */
 	 */
-	t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
+	t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs,
+				    t->max_seg_sz);
 	if (!t->mem)
 	if (!t->mem)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE);
 	t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
 	t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
 	if (!t->sg) {
 	if (!t->sg) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
@@ -1401,7 +1533,7 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
 				     int max_scatter)
 				     int max_scatter)
 {
 {
-	return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+	return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
 				write, max_scatter, 1);
 				write, max_scatter, 1);
 }
 }
 
 
@@ -1446,12 +1578,13 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
 	unsigned int dev_addr;
 	unsigned int dev_addr;
 	int ret;
 	int ret;
 
 
-	for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+	for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
 		dev_addr = test->area.dev_addr + (sz >> 9);
 		dev_addr = test->area.dev_addr + (sz >> 9);
 		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 	}
 	}
+	sz = test->area.max_tfr;
 	dev_addr = test->area.dev_addr;
 	dev_addr = test->area.dev_addr;
 	return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 	return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 }
 }
@@ -1468,7 +1601,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
 	ret = mmc_test_area_erase(test);
 	ret = mmc_test_area_erase(test);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
-	for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+	for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
 		dev_addr = test->area.dev_addr + (sz >> 9);
 		dev_addr = test->area.dev_addr + (sz >> 9);
 		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 		if (ret)
 		if (ret)
@@ -1477,6 +1610,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
 	ret = mmc_test_area_erase(test);
 	ret = mmc_test_area_erase(test);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
+	sz = test->area.max_tfr;
 	dev_addr = test->area.dev_addr;
 	dev_addr = test->area.dev_addr;
 	return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 	return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 }
 }
@@ -1516,29 +1650,63 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
 	return 0;
 	return 0;
 }
 }
 
 
+static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
+{
+	unsigned int dev_addr, i, cnt;
+	struct timespec ts1, ts2;
+	int ret;
+
+	cnt = test->area.max_sz / sz;
+	dev_addr = test->area.dev_addr;
+	getnstimeofday(&ts1);
+	for (i = 0; i < cnt; i++) {
+		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
+		if (ret)
+			return ret;
+		dev_addr += (sz >> 9);
+	}
+	getnstimeofday(&ts2);
+	mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+	return 0;
+}
+
 /*
 /*
  * Consecutive read performance by transfer size.
  * Consecutive read performance by transfer size.
  */
  */
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 {
 {
 	unsigned long sz;
 	unsigned long sz;
+	int ret;
+
+	for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+		ret = mmc_test_seq_read_perf(test, sz);
+		if (ret)
+			return ret;
+	}
+	sz = test->area.max_tfr;
+	return mmc_test_seq_read_perf(test, sz);
+}
+
+static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
+{
 	unsigned int dev_addr, i, cnt;
 	unsigned int dev_addr, i, cnt;
 	struct timespec ts1, ts2;
 	struct timespec ts1, ts2;
 	int ret;
 	int ret;
 
 
-	for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-		cnt = test->area.max_sz / sz;
-		dev_addr = test->area.dev_addr;
-		getnstimeofday(&ts1);
-		for (i = 0; i < cnt; i++) {
-			ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
-			if (ret)
-				return ret;
-			dev_addr += (sz >> 9);
-		}
-		getnstimeofday(&ts2);
-		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+	ret = mmc_test_area_erase(test);
+	if (ret)
+		return ret;
+	cnt = test->area.max_sz / sz;
+	dev_addr = test->area.dev_addr;
+	getnstimeofday(&ts1);
+	for (i = 0; i < cnt; i++) {
+		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
+		if (ret)
+			return ret;
+		dev_addr += (sz >> 9);
 	}
 	}
+	getnstimeofday(&ts2);
+	mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1548,27 +1716,15 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 {
 {
 	unsigned long sz;
 	unsigned long sz;
-	unsigned int dev_addr, i, cnt;
-	struct timespec ts1, ts2;
 	int ret;
 	int ret;
 
 
-	for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-		ret = mmc_test_area_erase(test);
+	for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+		ret = mmc_test_seq_write_perf(test, sz);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-		cnt = test->area.max_sz / sz;
-		dev_addr = test->area.dev_addr;
-		getnstimeofday(&ts1);
-		for (i = 0; i < cnt; i++) {
-			ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
-			if (ret)
-				return ret;
-			dev_addr += (sz >> 9);
-		}
-		getnstimeofday(&ts2);
-		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
 	}
 	}
-	return 0;
+	sz = test->area.max_tfr;
+	return mmc_test_seq_write_perf(test, sz);
 }
 }
 
 
 /*
 /*
@@ -1853,6 +2009,8 @@ static const struct mmc_test_case mmc_test_cases[] = {
 
 
 static DEFINE_MUTEX(mmc_test_lock);
 static DEFINE_MUTEX(mmc_test_lock);
 
 
+static LIST_HEAD(mmc_test_result);
+
 static void mmc_test_run(struct mmc_test_card *test, int testcase)
 static void mmc_test_run(struct mmc_test_card *test, int testcase)
 {
 {
 	int i, ret;
 	int i, ret;
@@ -1863,6 +2021,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
 	mmc_claim_host(test->card->host);
 	mmc_claim_host(test->card->host);
 
 
 	for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
 	for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+		struct mmc_test_general_result *gr;
+
 		if (testcase && ((i + 1) != testcase))
 		if (testcase && ((i + 1) != testcase))
 			continue;
 			continue;
 
 
@@ -1881,6 +2041,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
 			}
 			}
 		}
 		}
 
 
+		gr = kzalloc(sizeof(struct mmc_test_general_result),
+			GFP_KERNEL);
+		if (gr) {
+			INIT_LIST_HEAD(&gr->tr_lst);
+
+			/* Assign data what we know already */
+			gr->card = test->card;
+			gr->testcase = i;
+
+			/* Append container to global one */
+			list_add_tail(&gr->link, &mmc_test_result);
+
+			/*
+			 * Save the pointer to created container in our private
+			 * structure.
+			 */
+			test->gr = gr;
+		}
+
 		ret = mmc_test_cases[i].run(test);
 		ret = mmc_test_cases[i].run(test);
 		switch (ret) {
 		switch (ret) {
 		case RESULT_OK:
 		case RESULT_OK:
@@ -1906,6 +2085,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
 				mmc_hostname(test->card->host), ret);
 				mmc_hostname(test->card->host), ret);
 		}
 		}
 
 
+		/* Save the result */
+		if (gr)
+			gr->result = ret;
+
 		if (mmc_test_cases[i].cleanup) {
 		if (mmc_test_cases[i].cleanup) {
 			ret = mmc_test_cases[i].cleanup(test);
 			ret = mmc_test_cases[i].cleanup(test);
 			if (ret) {
 			if (ret) {
@@ -1923,30 +2106,95 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
 		mmc_hostname(test->card->host));
 		mmc_hostname(test->card->host));
 }
 }
 
 
-static ssize_t mmc_test_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+static void mmc_test_free_result(struct mmc_card *card)
 {
 {
+	struct mmc_test_general_result *gr, *grs;
+
 	mutex_lock(&mmc_test_lock);
 	mutex_lock(&mmc_test_lock);
+
+	list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
+		struct mmc_test_transfer_result *tr, *trs;
+
+		if (card && gr->card != card)
+			continue;
+
+		list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
+			list_del(&tr->link);
+			kfree(tr);
+		}
+
+		list_del(&gr->link);
+		kfree(gr);
+	}
+
+	mutex_unlock(&mmc_test_lock);
+}
+
+static LIST_HEAD(mmc_test_file_test);
+
+static int mtf_test_show(struct seq_file *sf, void *data)
+{
+	struct mmc_card *card = (struct mmc_card *)sf->private;
+	struct mmc_test_general_result *gr;
+
+	mutex_lock(&mmc_test_lock);
+
+	list_for_each_entry(gr, &mmc_test_result, link) {
+		struct mmc_test_transfer_result *tr;
+
+		if (gr->card != card)
+			continue;
+
+		seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
+
+		list_for_each_entry(tr, &gr->tr_lst, link) {
+			seq_printf(sf, "%u %d %lu.%09lu %u\n",
+				tr->count, tr->sectors,
+				(unsigned long)tr->ts.tv_sec,
+				(unsigned long)tr->ts.tv_nsec,
+				tr->rate);
+		}
+	}
+
 	mutex_unlock(&mmc_test_lock);
 	mutex_unlock(&mmc_test_lock);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static ssize_t mmc_test_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t count)
+static int mtf_test_open(struct inode *inode, struct file *file)
 {
 {
-	struct mmc_card *card;
+	return single_open(file, mtf_test_show, inode->i_private);
+}
+
+static ssize_t mtf_test_write(struct file *file, const char __user *buf,
+	size_t count, loff_t *pos)
+{
+	struct seq_file *sf = (struct seq_file *)file->private_data;
+	struct mmc_card *card = (struct mmc_card *)sf->private;
 	struct mmc_test_card *test;
 	struct mmc_test_card *test;
-	int testcase;
+	char lbuf[12];
+	long testcase;
 
 
-	card = container_of(dev, struct mmc_card, dev);
+	if (count >= sizeof(lbuf))
+		return -EINVAL;
 
 
-	testcase = simple_strtol(buf, NULL, 10);
+	if (copy_from_user(lbuf, buf, count))
+		return -EFAULT;
+	lbuf[count] = '\0';
+
+	if (strict_strtol(lbuf, 10, &testcase))
+		return -EINVAL;
 
 
 	test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
 	test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
 	if (!test)
 	if (!test)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	/*
+	 * Remove all test cases associated with given card. Thus we have only
+	 * actual data of the last run.
+	 */
+	mmc_test_free_result(card);
+
 	test->card = card;
 	test->card = card;
 
 
 	test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
 	test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
@@ -1973,16 +2221,78 @@ static ssize_t mmc_test_store(struct device *dev,
 	return count;
 	return count;
 }
 }
 
 
-static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
+static const struct file_operations mmc_test_fops_test = {
+	.open		= mtf_test_open,
+	.read		= seq_read,
+	.write		= mtf_test_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void mmc_test_free_file_test(struct mmc_card *card)
+{
+	struct mmc_test_dbgfs_file *df, *dfs;
+
+	mutex_lock(&mmc_test_lock);
+
+	list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) {
+		if (card && df->card != card)
+			continue;
+		debugfs_remove(df->file);
+		list_del(&df->link);
+		kfree(df);
+	}
+
+	mutex_unlock(&mmc_test_lock);
+}
+
+static int mmc_test_register_file_test(struct mmc_card *card)
+{
+	struct dentry *file = NULL;
+	struct mmc_test_dbgfs_file *df;
+	int ret = 0;
+
+	mutex_lock(&mmc_test_lock);
+
+	if (card->debugfs_root)
+		file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
+			card->debugfs_root, card, &mmc_test_fops_test);
+
+	if (IS_ERR_OR_NULL(file)) {
+		dev_err(&card->dev,
+			"Can't create file. Perhaps debugfs is disabled.\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
+	if (!df) {
+		debugfs_remove(file);
+		dev_err(&card->dev,
+			"Can't allocate memory for internal usage.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	df->card = card;
+	df->file = file;
+
+	list_add(&df->link, &mmc_test_file_test);
+
+err:
+	mutex_unlock(&mmc_test_lock);
+
+	return ret;
+}
 
 
 static int mmc_test_probe(struct mmc_card *card)
 static int mmc_test_probe(struct mmc_card *card)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
+	if (!mmc_card_mmc(card) && !mmc_card_sd(card))
 		return -ENODEV;
 		return -ENODEV;
 
 
-	ret = device_create_file(&card->dev, &dev_attr_test);
+	ret = mmc_test_register_file_test(card);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
@@ -1993,7 +2303,8 @@ static int mmc_test_probe(struct mmc_card *card)
 
 
 static void mmc_test_remove(struct mmc_card *card)
 static void mmc_test_remove(struct mmc_card *card)
 {
 {
-	device_remove_file(&card->dev, &dev_attr_test);
+	mmc_test_free_result(card);
+	mmc_test_free_file_test(card);
 }
 }
 
 
 static struct mmc_driver mmc_driver = {
 static struct mmc_driver mmc_driver = {
@@ -2011,6 +2322,10 @@ static int __init mmc_test_init(void)
 
 
 static void __exit mmc_test_exit(void)
 static void __exit mmc_test_exit(void)
 {
 {
+	/* Clear stalled data if card is still plugged */
+	mmc_test_free_result(NULL);
+	mmc_test_free_file_test(NULL);
+
 	mmc_unregister_driver(&mmc_driver);
 	mmc_unregister_driver(&mmc_driver);
 }
 }
 
 

+ 8 - 6
drivers/mmc/card/queue.c

@@ -146,7 +146,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 	}
 	}
 
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
-	if (host->max_hw_segs == 1) {
+	if (host->max_segs == 1) {
 		unsigned int bouncesz;
 		unsigned int bouncesz;
 
 
 		bouncesz = MMC_QUEUE_BOUNCESZ;
 		bouncesz = MMC_QUEUE_BOUNCESZ;
@@ -196,21 +196,23 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_max_hw_sectors(mq->queue,
 		blk_queue_max_hw_sectors(mq->queue,
 			min(host->max_blk_count, host->max_req_size / 512));
 			min(host->max_blk_count, host->max_req_size / 512));
-		blk_queue_max_segments(mq->queue, host->max_hw_segs);
+		blk_queue_max_segments(mq->queue, host->max_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
 
 		mq->sg = kmalloc(sizeof(struct scatterlist) *
 		mq->sg = kmalloc(sizeof(struct scatterlist) *
-			host->max_phys_segs, GFP_KERNEL);
+			host->max_segs, GFP_KERNEL);
 		if (!mq->sg) {
 		if (!mq->sg) {
 			ret = -ENOMEM;
 			ret = -ENOMEM;
 			goto cleanup_queue;
 			goto cleanup_queue;
 		}
 		}
-		sg_init_table(mq->sg, host->max_phys_segs);
+		sg_init_table(mq->sg, host->max_segs);
 	}
 	}
 
 
-	init_MUTEX(&mq->thread_sem);
+	sema_init(&mq->thread_sem, 1);
+
+	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d",
+		host->index);
 
 
-	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
 	if (IS_ERR(mq->thread)) {
 	if (IS_ERR(mq->thread)) {
 		ret = PTR_ERR(mq->thread);
 		ret = PTR_ERR(mq->thread);
 		goto free_bounce_sg;
 		goto free_bounce_sg;

+ 0 - 4
drivers/mmc/core/Makefile

@@ -2,10 +2,6 @@
 # Makefile for the kernel mmc core.
 # Makefile for the kernel mmc core.
 #
 #
 
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-	EXTRA_CFLAGS		+= -DDEBUG
-endif
-
 obj-$(CONFIG_MMC)		+= mmc_core.o
 obj-$(CONFIG_MMC)		+= mmc_core.o
 mmc_core-y			:= core.o bus.o host.o \
 mmc_core-y			:= core.o bus.o host.o \
 				   mmc.o mmc_ops.o sd.o sd_ops.o \
 				   mmc.o mmc_ops.o sd.o sd_ops.o \

+ 48 - 10
drivers/mmc/core/bus.c

@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
@@ -22,13 +23,12 @@
 #include "sdio_cis.h"
 #include "sdio_cis.h"
 #include "bus.h"
 #include "bus.h"
 
 
-#define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
 #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
 
 
 static ssize_t mmc_type_show(struct device *dev,
 static ssize_t mmc_type_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 	struct device_attribute *attr, char *buf)
 {
 {
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 
 
 	switch (card->type) {
 	switch (card->type) {
 	case MMC_TYPE_MMC:
 	case MMC_TYPE_MMC:
@@ -62,7 +62,7 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
 static int
 static int
 mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 {
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 	const char *type;
 	const char *type;
 	int retval = 0;
 	int retval = 0;
 
 
@@ -105,7 +105,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 static int mmc_bus_probe(struct device *dev)
 static int mmc_bus_probe(struct device *dev)
 {
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 
 
 	return drv->probe(card);
 	return drv->probe(card);
 }
 }
@@ -113,7 +113,7 @@ static int mmc_bus_probe(struct device *dev)
 static int mmc_bus_remove(struct device *dev)
 static int mmc_bus_remove(struct device *dev)
 {
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 
 
 	drv->remove(card);
 	drv->remove(card);
 
 
@@ -123,7 +123,7 @@ static int mmc_bus_remove(struct device *dev)
 static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 {
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 	int ret = 0;
 	int ret = 0;
 
 
 	if (dev->driver && drv->suspend)
 	if (dev->driver && drv->suspend)
@@ -134,7 +134,7 @@ static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 static int mmc_bus_resume(struct device *dev)
 static int mmc_bus_resume(struct device *dev)
 {
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 	int ret = 0;
 	int ret = 0;
 
 
 	if (dev->driver && drv->resume)
 	if (dev->driver && drv->resume)
@@ -142,6 +142,41 @@ static int mmc_bus_resume(struct device *dev)
 	return ret;
 	return ret;
 }
 }
 
 
+#ifdef CONFIG_PM_RUNTIME
+
+static int mmc_runtime_suspend(struct device *dev)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+
+	return mmc_power_save_host(card->host);
+}
+
+static int mmc_runtime_resume(struct device *dev)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+
+	return mmc_power_restore_host(card->host);
+}
+
+static int mmc_runtime_idle(struct device *dev)
+{
+	return pm_runtime_suspend(dev);
+}
+
+static const struct dev_pm_ops mmc_bus_pm_ops = {
+	.runtime_suspend	= mmc_runtime_suspend,
+	.runtime_resume		= mmc_runtime_resume,
+	.runtime_idle		= mmc_runtime_idle,
+};
+
+#define MMC_PM_OPS_PTR	(&mmc_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define MMC_PM_OPS_PTR	NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type mmc_bus_type = {
 static struct bus_type mmc_bus_type = {
 	.name		= "mmc",
 	.name		= "mmc",
 	.dev_attrs	= mmc_dev_attrs,
 	.dev_attrs	= mmc_dev_attrs,
@@ -151,6 +186,7 @@ static struct bus_type mmc_bus_type = {
 	.remove		= mmc_bus_remove,
 	.remove		= mmc_bus_remove,
 	.suspend	= mmc_bus_suspend,
 	.suspend	= mmc_bus_suspend,
 	.resume		= mmc_bus_resume,
 	.resume		= mmc_bus_resume,
+	.pm		= MMC_PM_OPS_PTR,
 };
 };
 
 
 int mmc_register_bus(void)
 int mmc_register_bus(void)
@@ -189,7 +225,7 @@ EXPORT_SYMBOL(mmc_unregister_driver);
 
 
 static void mmc_release_card(struct device *dev)
 static void mmc_release_card(struct device *dev)
 {
 {
-	struct mmc_card *card = dev_to_mmc_card(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
 
 
 	sdio_free_common_cis(card);
 	sdio_free_common_cis(card);
 
 
@@ -254,14 +290,16 @@ int mmc_add_card(struct mmc_card *card)
 	}
 	}
 
 
 	if (mmc_host_is_spi(card->host)) {
 	if (mmc_host_is_spi(card->host)) {
-		printk(KERN_INFO "%s: new %s%s card on SPI\n",
+		printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
 			mmc_hostname(card->host),
 			mmc_hostname(card->host),
 			mmc_card_highspeed(card) ? "high speed " : "",
 			mmc_card_highspeed(card) ? "high speed " : "",
+			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 			type);
 	} else {
 	} else {
-		printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_hostname(card->host),
 			mmc_card_highspeed(card) ? "high speed " : "",
 			mmc_card_highspeed(card) ? "high speed " : "",
+			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type, card->rca);
 			type, card->rca);
 	}
 	}
 
 

+ 1 - 1
drivers/mmc/core/bus.h

@@ -14,7 +14,7 @@
 #define MMC_DEV_ATTR(name, fmt, args...)					\
 #define MMC_DEV_ATTR(name, fmt, args...)					\
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
 {										\
 {										\
-	struct mmc_card *card = container_of(dev, struct mmc_card, dev);	\
+	struct mmc_card *card = mmc_dev_to_card(dev);				\
 	return sprintf(buf, fmt, args);						\
 	return sprintf(buf, fmt, args);						\
 }										\
 }										\
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)

+ 116 - 63
drivers/mmc/core/core.c

@@ -58,6 +58,7 @@ int mmc_assume_removable;
 #else
 #else
 int mmc_assume_removable = 1;
 int mmc_assume_removable = 1;
 #endif
 #endif
+EXPORT_SYMBOL(mmc_assume_removable);
 module_param_named(removable, mmc_assume_removable, bool, 0644);
 module_param_named(removable, mmc_assume_removable, bool, 0644);
 MODULE_PARM_DESC(
 MODULE_PARM_DESC(
 	removable,
 	removable,
@@ -650,14 +651,24 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 }
 }
 
 
 /*
 /*
- * Change data bus width of a host.
+ * Change data bus width and DDR mode of a host.
  */
  */
-void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+			   unsigned int ddr)
 {
 {
 	host->ios.bus_width = width;
 	host->ios.bus_width = width;
+	host->ios.ddr = ddr;
 	mmc_set_ios(host);
 	mmc_set_ios(host);
 }
 }
 
 
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+	mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+}
+
 /**
 /**
  * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
  * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
  * @vdd:	voltage (mV)
  * @vdd:	voltage (mV)
@@ -771,8 +782,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
 
 
 /**
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @mmc: the host to regulate
  * @supply: regulator to use
  * @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
  *
  *
  * Returns zero on success, else negative errno.
  * Returns zero on success, else negative errno.
  *
  *
@@ -780,15 +792,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
  * a particular supply voltage.  This would normally be called from the
  * a particular supply voltage.  This would normally be called from the
  * set_ios() method.
  * set_ios() method.
  */
  */
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+			struct regulator *supply,
+			unsigned short vdd_bit)
 {
 {
 	int			result = 0;
 	int			result = 0;
 	int			min_uV, max_uV;
 	int			min_uV, max_uV;
-	int			enabled;
-
-	enabled = regulator_is_enabled(supply);
-	if (enabled < 0)
-		return enabled;
 
 
 	if (vdd_bit) {
 	if (vdd_bit) {
 		int		tmp;
 		int		tmp;
@@ -819,17 +828,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
 		else
 		else
 			result = 0;
 			result = 0;
 
 
-		if (result == 0 && !enabled)
+		if (result == 0 && !mmc->regulator_enabled) {
 			result = regulator_enable(supply);
 			result = regulator_enable(supply);
-	} else if (enabled) {
+			if (!result)
+				mmc->regulator_enabled = true;
+		}
+	} else if (mmc->regulator_enabled) {
 		result = regulator_disable(supply);
 		result = regulator_disable(supply);
+		if (result == 0)
+			mmc->regulator_enabled = false;
 	}
 	}
 
 
+	if (result)
+		dev_err(mmc_dev(mmc),
+			"could not set regulator OCR (%d)\n", result);
 	return result;
 	return result;
 }
 }
 EXPORT_SYMBOL(mmc_regulator_set_ocr);
 EXPORT_SYMBOL(mmc_regulator_set_ocr);
 
 
-#endif
+#endif /* CONFIG_REGULATOR */
 
 
 /*
 /*
  * Mask off any voltages we don't support and select
  * Mask off any voltages we don't support and select
@@ -907,12 +924,7 @@ static void mmc_power_up(struct mmc_host *host)
 	 */
 	 */
 	mmc_delay(10);
 	mmc_delay(10);
 
 
-	if (host->f_min > 400000) {
-		pr_warning("%s: Minimum clock frequency too high for "
-				"identification mode\n", mmc_hostname(host));
-		host->ios.clock = host->f_min;
-	} else
-		host->ios.clock = 400000;
+	host->ios.clock = host->f_init;
 
 
 	host->ios.power_mode = MMC_POWER_ON;
 	host->ios.power_mode = MMC_POWER_ON;
 	mmc_set_ios(host);
 	mmc_set_ios(host);
@@ -1397,6 +1409,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 }
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
 
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
+{
+	struct mmc_command cmd;
+
+	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+		return 0;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	cmd.opcode = MMC_SET_BLOCKLEN;
+	cmd.arg = blocklen;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blocklen);
+
 void mmc_rescan(struct work_struct *work)
 void mmc_rescan(struct work_struct *work)
 {
 {
 	struct mmc_host *host =
 	struct mmc_host *host =
@@ -1404,6 +1431,8 @@ void mmc_rescan(struct work_struct *work)
 	u32 ocr;
 	u32 ocr;
 	int err;
 	int err;
 	unsigned long flags;
 	unsigned long flags;
+	int i;
+	const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
 
 	spin_lock_irqsave(&host->lock, flags);
 	spin_lock_irqsave(&host->lock, flags);
 
 
@@ -1443,55 +1472,71 @@ void mmc_rescan(struct work_struct *work)
 	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
 	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
 		goto out;
 		goto out;
 
 
-	mmc_claim_host(host);
+	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+		mmc_claim_host(host);
 
 
-	mmc_power_up(host);
-	sdio_reset(host);
-	mmc_go_idle(host);
+		if (freqs[i] >= host->f_min)
+			host->f_init = freqs[i];
+		else if (!i || freqs[i-1] > host->f_min)
+			host->f_init = host->f_min;
+		else {
+			mmc_release_host(host);
+			goto out;
+		}
+#ifdef CONFIG_MMC_DEBUG
+		pr_info("%s: %s: trying to init card at %u Hz\n",
+			mmc_hostname(host), __func__, host->f_init);
+#endif
+		mmc_power_up(host);
+		sdio_reset(host);
+		mmc_go_idle(host);
 
 
-	mmc_send_if_cond(host, host->ocr_avail);
+		mmc_send_if_cond(host, host->ocr_avail);
 
 
-	/*
-	 * First we search for SDIO...
-	 */
-	err = mmc_send_io_op_cond(host, 0, &ocr);
-	if (!err) {
-		if (mmc_attach_sdio(host, ocr)) {
-			mmc_claim_host(host);
-			/* try SDMEM (but not MMC) even if SDIO is broken */
-			if (mmc_send_app_op_cond(host, 0, &ocr))
-				goto out_fail;
+		/*
+		 * First we search for SDIO...
+		 */
+		err = mmc_send_io_op_cond(host, 0, &ocr);
+		if (!err) {
+			if (mmc_attach_sdio(host, ocr)) {
+				mmc_claim_host(host);
+				/*
+				 * Try SDMEM (but not MMC) even if SDIO
+				 * is broken.
+				 */
+				if (mmc_send_app_op_cond(host, 0, &ocr))
+					goto out_fail;
+
+				if (mmc_attach_sd(host, ocr))
+					mmc_power_off(host);
+			}
+			goto out;
+		}
 
 
+		/*
+		 * ...then normal SD...
+		 */
+		err = mmc_send_app_op_cond(host, 0, &ocr);
+		if (!err) {
 			if (mmc_attach_sd(host, ocr))
 			if (mmc_attach_sd(host, ocr))
 				mmc_power_off(host);
 				mmc_power_off(host);
+			goto out;
 		}
 		}
-		goto out;
-	}
 
 
-	/*
-	 * ...then normal SD...
-	 */
-	err = mmc_send_app_op_cond(host, 0, &ocr);
-	if (!err) {
-		if (mmc_attach_sd(host, ocr))
-			mmc_power_off(host);
-		goto out;
-	}
-
-	/*
-	 * ...and finally MMC.
-	 */
-	err = mmc_send_op_cond(host, 0, &ocr);
-	if (!err) {
-		if (mmc_attach_mmc(host, ocr))
-			mmc_power_off(host);
-		goto out;
-	}
+		/*
+		 * ...and finally MMC.
+		 */
+		err = mmc_send_op_cond(host, 0, &ocr);
+		if (!err) {
+			if (mmc_attach_mmc(host, ocr))
+				mmc_power_off(host);
+			goto out;
+		}
 
 
 out_fail:
 out_fail:
-	mmc_release_host(host);
-	mmc_power_off(host);
-
+		mmc_release_host(host);
+		mmc_power_off(host);
+	}
 out:
 out:
 	if (host->caps & MMC_CAP_NEEDS_POLL)
 	if (host->caps & MMC_CAP_NEEDS_POLL)
 		mmc_schedule_delayed_work(&host->detect, HZ);
 		mmc_schedule_delayed_work(&host->detect, HZ);
@@ -1538,37 +1583,45 @@ void mmc_stop_host(struct mmc_host *host)
 	mmc_power_off(host);
 	mmc_power_off(host);
 }
 }
 
 
-void mmc_power_save_host(struct mmc_host *host)
+int mmc_power_save_host(struct mmc_host *host)
 {
 {
+	int ret = 0;
+
 	mmc_bus_get(host);
 	mmc_bus_get(host);
 
 
 	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
 	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
 		mmc_bus_put(host);
 		mmc_bus_put(host);
-		return;
+		return -EINVAL;
 	}
 	}
 
 
 	if (host->bus_ops->power_save)
 	if (host->bus_ops->power_save)
-		host->bus_ops->power_save(host);
+		ret = host->bus_ops->power_save(host);
 
 
 	mmc_bus_put(host);
 	mmc_bus_put(host);
 
 
 	mmc_power_off(host);
 	mmc_power_off(host);
+
+	return ret;
 }
 }
 EXPORT_SYMBOL(mmc_power_save_host);
 EXPORT_SYMBOL(mmc_power_save_host);
 
 
-void mmc_power_restore_host(struct mmc_host *host)
+int mmc_power_restore_host(struct mmc_host *host)
 {
 {
+	int ret;
+
 	mmc_bus_get(host);
 	mmc_bus_get(host);
 
 
 	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
 	if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
 		mmc_bus_put(host);
 		mmc_bus_put(host);
-		return;
+		return -EINVAL;
 	}
 	}
 
 
 	mmc_power_up(host);
 	mmc_power_up(host);
-	host->bus_ops->power_restore(host);
+	ret = host->bus_ops->power_restore(host);
 
 
 	mmc_bus_put(host);
 	mmc_bus_put(host);
+
+	return ret;
 }
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 EXPORT_SYMBOL(mmc_power_restore_host);
 
 

+ 4 - 3
drivers/mmc/core/core.h

@@ -22,8 +22,8 @@ struct mmc_bus_ops {
 	void (*detect)(struct mmc_host *);
 	void (*detect)(struct mmc_host *);
 	int (*suspend)(struct mmc_host *);
 	int (*suspend)(struct mmc_host *);
 	int (*resume)(struct mmc_host *);
 	int (*resume)(struct mmc_host *);
-	void (*power_save)(struct mmc_host *);
-	void (*power_restore)(struct mmc_host *);
+	int (*power_save)(struct mmc_host *);
+	int (*power_restore)(struct mmc_host *);
 };
 };
 
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -35,6 +35,8 @@ void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+			   unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 
 
@@ -58,7 +60,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
 
 
 /* Module parameters */
 /* Module parameters */
 extern int use_spi_crc;
 extern int use_spi_crc;
-extern int mmc_assume_removable;
 
 
 /* Debugfs information for hosts and cards */
 /* Debugfs information for hosts and cards */
 void mmc_add_host_debugfs(struct mmc_host *host);
 void mmc_add_host_debugfs(struct mmc_host *host);

+ 33 - 2
drivers/mmc/core/debugfs.c

@@ -134,6 +134,33 @@ static const struct file_operations mmc_ios_fops = {
 	.release	= single_release,
 	.release	= single_release,
 };
 };
 
 
+static int mmc_clock_opt_get(void *data, u64 *val)
+{
+	struct mmc_host *host = data;
+
+	*val = host->ios.clock;
+
+	return 0;
+}
+
+static int mmc_clock_opt_set(void *data, u64 val)
+{
+	struct mmc_host *host = data;
+
+	/* We need this check due to input value is u64 */
+	if (val > host->f_max)
+		return -EINVAL;
+
+	mmc_claim_host(host);
+	mmc_set_clock(host, (unsigned int) val);
+	mmc_release_host(host);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
+	"%llu\n");
+
 void mmc_add_host_debugfs(struct mmc_host *host)
 void mmc_add_host_debugfs(struct mmc_host *host)
 {
 {
 	struct dentry *root;
 	struct dentry *root;
@@ -150,11 +177,15 @@ void mmc_add_host_debugfs(struct mmc_host *host)
 	host->debugfs_root = root;
 	host->debugfs_root = root;
 
 
 	if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
 	if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
-		goto err_ios;
+		goto err_node;
+
+	if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+			&mmc_clock_fops))
+		goto err_node;
 
 
 	return;
 	return;
 
 
-err_ios:
+err_node:
 	debugfs_remove_recursive(root);
 	debugfs_remove_recursive(root);
 	host->debugfs_root = NULL;
 	host->debugfs_root = NULL;
 err_root:
 err_root:

+ 1 - 2
drivers/mmc/core/host.c

@@ -94,8 +94,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 	 * By default, hosts do not support SGIO or large requests.
 	 * By default, hosts do not support SGIO or large requests.
 	 * They have to set these according to their abilities.
 	 * They have to set these according to their abilities.
 	 */
 	 */
-	host->max_hw_segs = 1;
-	host->max_phys_segs = 1;
+	host->max_segs = 1;
 	host->max_seg_size = PAGE_CACHE_SIZE;
 	host->max_seg_size = PAGE_CACHE_SIZE;
 
 
 	host->max_req_size = PAGE_CACHE_SIZE;
 	host->max_req_size = PAGE_CACHE_SIZE;

+ 48 - 10
drivers/mmc/core/mmc.c

@@ -258,6 +258,21 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 	}
 	}
 
 
 	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
 	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+	     EXT_CSD_CARD_TYPE_26:
+		card->ext_csd.hs_max_dtr = 52000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+		break;
+	case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+	     EXT_CSD_CARD_TYPE_26:
+		card->ext_csd.hs_max_dtr = 52000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+		break;
+	case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+	     EXT_CSD_CARD_TYPE_26:
+		card->ext_csd.hs_max_dtr = 52000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+		break;
 	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
 	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
 		card->ext_csd.hs_max_dtr = 52000000;
 		card->ext_csd.hs_max_dtr = 52000000;
 		break;
 		break;
@@ -360,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	struct mmc_card *oldcard)
 	struct mmc_card *oldcard)
 {
 {
 	struct mmc_card *card;
 	struct mmc_card *card;
-	int err;
+	int err, ddr = MMC_SDR_MODE;
 	u32 cid[4];
 	u32 cid[4];
 	unsigned int max_dtr;
 	unsigned int max_dtr;
 
 
@@ -503,17 +518,35 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	mmc_set_clock(host, max_dtr);
 	mmc_set_clock(host, max_dtr);
 
 
 	/*
 	/*
-	 * Activate wide bus (if supported).
+	 * Indicate DDR mode (if supported).
+	 */
+	if (mmc_card_highspeed(card)) {
+		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+			&& (host->caps & (MMC_CAP_1_8V_DDR)))
+				ddr = MMC_1_8V_DDR_MODE;
+		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+			&& (host->caps & (MMC_CAP_1_2V_DDR)))
+				ddr = MMC_1_2V_DDR_MODE;
+	}
+
+	/*
+	 * Activate wide bus and DDR (if supported).
 	 */
 	 */
 	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
 	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
 	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
 	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
 		unsigned ext_csd_bit, bus_width;
 		unsigned ext_csd_bit, bus_width;
 
 
 		if (host->caps & MMC_CAP_8_BIT_DATA) {
 		if (host->caps & MMC_CAP_8_BIT_DATA) {
-			ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+			if (ddr)
+				ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
+			else
+				ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
 			bus_width = MMC_BUS_WIDTH_8;
 			bus_width = MMC_BUS_WIDTH_8;
 		} else {
 		} else {
-			ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+			if (ddr)
+				ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
+			else
+				ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
 			bus_width = MMC_BUS_WIDTH_4;
 			bus_width = MMC_BUS_WIDTH_4;
 		}
 		}
 
 
@@ -524,12 +557,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			goto free_card;
 			goto free_card;
 
 
 		if (err) {
 		if (err) {
-			printk(KERN_WARNING "%s: switch to bus width %d "
+			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
 			       "failed\n", mmc_hostname(card->host),
 			       "failed\n", mmc_hostname(card->host),
-			       1 << bus_width);
+			       1 << bus_width, ddr);
 			err = 0;
 			err = 0;
 		} else {
 		} else {
-			mmc_set_bus_width(card->host, bus_width);
+			mmc_card_set_ddr_mode(card);
+			mmc_set_bus_width_ddr(card->host, bus_width, ddr);
 		}
 		}
 	}
 	}
 
 
@@ -623,12 +657,16 @@ static int mmc_resume(struct mmc_host *host)
 	return err;
 	return err;
 }
 }
 
 
-static void mmc_power_restore(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
 {
 {
+	int ret;
+
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	mmc_claim_host(host);
-	mmc_init_card(host, host->ocr, host->card);
+	ret = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 	mmc_release_host(host);
+
+	return ret;
 }
 }
 
 
 static int mmc_sleep(struct mmc_host *host)
 static int mmc_sleep(struct mmc_host *host)
@@ -685,7 +723,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 {
 {
 	const struct mmc_bus_ops *bus_ops;
 	const struct mmc_bus_ops *bus_ops;
 
 
-	if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+	if (!mmc_card_is_removable(host))
 		bus_ops = &mmc_ops_unsafe;
 		bus_ops = &mmc_ops_unsafe;
 	else
 	else
 		bus_ops = &mmc_ops;
 		bus_ops = &mmc_ops;

+ 7 - 3
drivers/mmc/core/sd.c

@@ -722,12 +722,16 @@ static int mmc_sd_resume(struct mmc_host *host)
 	return err;
 	return err;
 }
 }
 
 
-static void mmc_sd_power_restore(struct mmc_host *host)
+static int mmc_sd_power_restore(struct mmc_host *host)
 {
 {
+	int ret;
+
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	mmc_claim_host(host);
-	mmc_sd_init_card(host, host->ocr, host->card);
+	ret = mmc_sd_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 	mmc_release_host(host);
+
+	return ret;
 }
 }
 
 
 static const struct mmc_bus_ops mmc_sd_ops = {
 static const struct mmc_bus_ops mmc_sd_ops = {
@@ -750,7 +754,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
 {
 {
 	const struct mmc_bus_ops *bus_ops;
 	const struct mmc_bus_ops *bus_ops;
 
 
-	if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+	if (!mmc_card_is_removable(host))
 		bus_ops = &mmc_sd_ops_unsafe;
 		bus_ops = &mmc_sd_ops_unsafe;
 	else
 	else
 		bus_ops = &mmc_sd_ops;
 		bus_ops = &mmc_sd_ops;

+ 45 - 9
drivers/mmc/core/sdio.c

@@ -10,6 +10,7 @@
  */
  */
 
 
 #include <linux/err.h>
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>
@@ -456,7 +457,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 			return -ENOENT;
 			return -ENOENT;
 
 
 		card = oldcard;
 		card = oldcard;
-		return 0;
 	}
 	}
 
 
 	if (card->type == MMC_TYPE_SD_COMBO) {
 	if (card->type == MMC_TYPE_SD_COMBO) {
@@ -546,6 +546,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
 	BUG_ON(!host);
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 	BUG_ON(!host->card);
 
 
+	/* Make sure card is powered before detecting it */
+	err = pm_runtime_get_sync(&host->card->dev);
+	if (err < 0)
+		goto out;
+
 	mmc_claim_host(host);
 	mmc_claim_host(host);
 
 
 	/*
 	/*
@@ -555,6 +560,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
 
 
 	mmc_release_host(host);
 	mmc_release_host(host);
 
 
+out:
 	if (err) {
 	if (err) {
 		mmc_sdio_remove(host);
 		mmc_sdio_remove(host);
 
 
@@ -562,6 +568,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
 		mmc_detach_bus(host);
 		mmc_detach_bus(host);
 		mmc_release_host(host);
 		mmc_release_host(host);
 	}
 	}
+
+	/* Tell PM core that we're done */
+	pm_runtime_put(&host->card->dev);
 }
 }
 
 
 /*
 /*
@@ -614,14 +623,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
 	mmc_claim_host(host);
 	mmc_claim_host(host);
 	err = mmc_sdio_init_card(host, host->ocr, host->card,
 	err = mmc_sdio_init_card(host, host->ocr, host->card,
 				 (host->pm_flags & MMC_PM_KEEP_POWER));
 				 (host->pm_flags & MMC_PM_KEEP_POWER));
-	if (!err) {
-		/* We may have switched to 1-bit mode during suspend. */
-		err = sdio_enable_4bit_bus(host->card);
-		if (err > 0) {
-			mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-			err = 0;
-		}
-	}
 	if (!err && host->sdio_irqs)
 	if (!err && host->sdio_irqs)
 		mmc_signal_sdio_irq(host);
 		mmc_signal_sdio_irq(host);
 	mmc_release_host(host);
 	mmc_release_host(host);
@@ -647,11 +648,29 @@ static int mmc_sdio_resume(struct mmc_host *host)
 	return err;
 	return err;
 }
 }
 
 
+static int mmc_sdio_power_restore(struct mmc_host *host)
+{
+	int ret;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+	ret = mmc_sdio_init_card(host, host->ocr, host->card,
+			(host->pm_flags & MMC_PM_KEEP_POWER));
+	if (!ret && host->sdio_irqs)
+		mmc_signal_sdio_irq(host);
+	mmc_release_host(host);
+
+	return ret;
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
 static const struct mmc_bus_ops mmc_sdio_ops = {
 	.remove = mmc_sdio_remove,
 	.remove = mmc_sdio_remove,
 	.detect = mmc_sdio_detect,
 	.detect = mmc_sdio_detect,
 	.suspend = mmc_sdio_suspend,
 	.suspend = mmc_sdio_suspend,
 	.resume = mmc_sdio_resume,
 	.resume = mmc_sdio_resume,
+	.power_restore = mmc_sdio_power_restore,
 };
 };
 
 
 
 
@@ -698,6 +717,18 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
 		goto err;
 		goto err;
 	card = host->card;
 	card = host->card;
 
 
+	/*
+	 * Let runtime PM core know our card is active
+	 */
+	err = pm_runtime_set_active(&card->dev);
+	if (err)
+		goto remove;
+
+	/*
+	 * Enable runtime PM for this card
+	 */
+	pm_runtime_enable(&card->dev);
+
 	/*
 	/*
 	 * The number of functions on the card is encoded inside
 	 * The number of functions on the card is encoded inside
 	 * the ocr.
 	 * the ocr.
@@ -712,6 +743,11 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
 		err = sdio_init_func(host->card, i + 1);
 		err = sdio_init_func(host->card, i + 1);
 		if (err)
 		if (err)
 			goto remove;
 			goto remove;
+
+		/*
+		 * Enable Runtime PM for this func
+		 */
+		pm_runtime_enable(&card->sdio_func[i]->dev);
 	}
 	}
 
 
 	mmc_release_host(host);
 	mmc_release_host(host);

+ 83 - 2
drivers/mmc/core/sdio_bus.c

@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_func.h>
@@ -125,21 +126,46 @@ static int sdio_bus_probe(struct device *dev)
 	if (!id)
 	if (!id)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	/* Unbound SDIO functions are always suspended.
+	 * During probe, the function is set active and the usage count
+	 * is incremented.  If the driver supports runtime PM,
+	 * it should call pm_runtime_put_noidle() in its probe routine and
+	 * pm_runtime_get_noresume() in its remove routine.
+	 */
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0)
+		goto out;
+
 	/* Set the default block size so the driver is sure it's something
 	/* Set the default block size so the driver is sure it's something
 	 * sensible. */
 	 * sensible. */
 	sdio_claim_host(func);
 	sdio_claim_host(func);
 	ret = sdio_set_block_size(func, 0);
 	ret = sdio_set_block_size(func, 0);
 	sdio_release_host(func);
 	sdio_release_host(func);
 	if (ret)
 	if (ret)
-		return ret;
+		goto disable_runtimepm;
+
+	ret = drv->probe(func, id);
+	if (ret)
+		goto disable_runtimepm;
 
 
-	return drv->probe(func, id);
+	return 0;
+
+disable_runtimepm:
+	pm_runtime_put_noidle(dev);
+out:
+	return ret;
 }
 }
 
 
 static int sdio_bus_remove(struct device *dev)
 static int sdio_bus_remove(struct device *dev)
 {
 {
 	struct sdio_driver *drv = to_sdio_driver(dev->driver);
 	struct sdio_driver *drv = to_sdio_driver(dev->driver);
 	struct sdio_func *func = dev_to_sdio_func(dev);
 	struct sdio_func *func = dev_to_sdio_func(dev);
+	int ret;
+
+	/* Make sure card is powered before invoking ->remove() */
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0)
+		goto out;
 
 
 	drv->remove(func);
 	drv->remove(func);
 
 
@@ -151,9 +177,63 @@ static int sdio_bus_remove(struct device *dev)
 		sdio_release_host(func);
 		sdio_release_host(func);
 	}
 	}
 
 
+	/* First, undo the increment made directly above */
+	pm_runtime_put_noidle(dev);
+
+	/* Then undo the runtime PM settings in sdio_bus_probe() */
+	pm_runtime_put_noidle(dev);
+
+out:
+	return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int sdio_bus_pm_prepare(struct device *dev)
+{
+	/*
+	 * Resume an SDIO device which was suspended at run time at this
+	 * point, in order to allow standard SDIO suspend/resume paths
+	 * to keep working as usual.
+	 *
+	 * Ultimately, the SDIO driver itself will decide (in its
+	 * suspend handler, or lack thereof) whether the card should be
+	 * removed or kept, and if kept, at what power state.
+	 *
+	 * At this point, PM core have increased our use count, so it's
+	 * safe to directly resume the device. After system is resumed
+	 * again, PM core will drop back its runtime PM use count, and if
+	 * needed device will be suspended again.
+	 *
+	 * The end result is guaranteed to be a power state that is
+	 * coherent with the device's runtime PM use count.
+	 *
+	 * The return value of pm_runtime_resume is deliberately unchecked
+	 * since there is little point in failing system suspend if a
+	 * device can't be resumed.
+	 */
+	pm_runtime_resume(dev);
+
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct dev_pm_ops sdio_bus_pm_ops = {
+	SET_RUNTIME_PM_OPS(
+		pm_generic_runtime_suspend,
+		pm_generic_runtime_resume,
+		pm_generic_runtime_idle
+	)
+	.prepare = sdio_bus_pm_prepare,
+};
+
+#define SDIO_PM_OPS_PTR	(&sdio_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define SDIO_PM_OPS_PTR	NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type sdio_bus_type = {
 static struct bus_type sdio_bus_type = {
 	.name		= "sdio",
 	.name		= "sdio",
 	.dev_attrs	= sdio_dev_attrs,
 	.dev_attrs	= sdio_dev_attrs,
@@ -161,6 +241,7 @@ static struct bus_type sdio_bus_type = {
 	.uevent		= sdio_bus_uevent,
 	.uevent		= sdio_bus_uevent,
 	.probe		= sdio_bus_probe,
 	.probe		= sdio_bus_probe,
 	.remove		= sdio_bus_remove,
 	.remove		= sdio_bus_remove,
+	.pm		= SDIO_PM_OPS_PTR,
 };
 };
 
 
 int sdio_register_bus(void)
 int sdio_register_bus(void)

+ 37 - 0
drivers/mmc/host/Kconfig

@@ -130,6 +130,16 @@ config MMC_SDHCI_CNS3XXX
 
 
 	  If unsure, say N.
 	  If unsure, say N.
 
 
+config MMC_SDHCI_ESDHC_IMX
+	bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
+	depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
+	select MMC_SDHCI_IO_ACCESSORS
+	help
+	  This selects the Freescale eSDHC controller support on the platform
+	  bus, found on platforms like mx35/51.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_S3C
 config MMC_SDHCI_S3C
 	tristate "SDHCI support on Samsung S3C SoC"
 	tristate "SDHCI support on Samsung S3C SoC"
 	depends on MMC_SDHCI && PLAT_SAMSUNG
 	depends on MMC_SDHCI && PLAT_SAMSUNG
@@ -145,6 +155,18 @@ config MMC_SDHCI_S3C
 
 
 	  If unsure, say N.
 	  If unsure, say N.
 
 
+config MMC_SDHCI_PXA
+	tristate "Marvell PXA168/PXA910/MMP2 SD Host Controller support"
+	depends on ARCH_PXA || ARCH_MMP
+	select MMC_SDHCI
+	select MMC_SDHCI_IO_ACCESSORS
+	help
+	  This selects the Marvell(R) PXA168/PXA910/MMP2 SD Host Controller.
+	  If you have a PXA168/PXA910/MMP2 platform with SD Host Controller
+	  and a card slot, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_SPEAR
 config MMC_SDHCI_SPEAR
 	tristate "SDHCI support on ST SPEAr platform"
 	tristate "SDHCI support on ST SPEAr platform"
 	depends on MMC_SDHCI && PLAT_SPEAR
 	depends on MMC_SDHCI && PLAT_SPEAR
@@ -395,6 +417,7 @@ config MMC_TMIO
 config MMC_CB710
 config MMC_CB710
 	tristate "ENE CB710 MMC/SD Interface support"
 	tristate "ENE CB710 MMC/SD Interface support"
 	depends on PCI
 	depends on PCI
+	select MISC_DEVICES
 	select CB710_CORE
 	select CB710_CORE
 	help
 	help
 	  This option enables support for MMC/SD part of ENE CB710/720 Flash
 	  This option enables support for MMC/SD part of ENE CB710/720 Flash
@@ -451,3 +474,17 @@ config MMC_JZ4740
 	  SoCs.
 	  SoCs.
 	  If you have a board based on such a SoC and with a SD/MMC slot,
 	  If you have a board based on such a SoC and with a SD/MMC slot,
 	  say Y or M here.
 	  say Y or M here.
+
+config MMC_USHC
+	tristate "USB SD Host Controller (USHC) support"
+	depends on USB
+	help
+	  This selects support for USB SD Host Controllers based on
+	  the Cypress Astoria chip with firmware compliant with CSR's
+	  USB SD Host Controller specification (CS-118793-SP).
+
+	  CSR boards with this device include: USB<>SDIO (M1985v2),
+	  and Ultrasira.
+
+	  Note: These controllers only support SDIO cards and do not
+	  support MMC or SD memory cards.

+ 3 - 4
drivers/mmc/host/Makefile

@@ -2,16 +2,13 @@
 # Makefile for MMC/SD host controller drivers
 # Makefile for MMC/SD host controller drivers
 #
 #
 
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-	EXTRA_CFLAGS		+= -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
 obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
 obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
 obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
 obj-$(CONFIG_MMC_MXC)		+= mxcmmc.o
 obj-$(CONFIG_MMC_MXC)		+= mxcmmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
+obj-$(CONFIG_MMC_SDHCI_PXA)	+= sdhci-pxa.o
 obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
@@ -36,10 +33,12 @@ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
+obj-$(CONFIG_MMC_USHC)		+= ushc.o
 
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)			+= sdhci-platform.o
 obj-$(CONFIG_MMC_SDHCI_PLTFM)			+= sdhci-platform.o
 sdhci-platform-y				:= sdhci-pltfm.o
 sdhci-platform-y				:= sdhci-pltfm.o
 sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX)	+= sdhci-cns3xxx.o
 sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX)	+= sdhci-cns3xxx.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
 
 
 obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
 obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
 sdhci-of-y				:= sdhci-of-core.o
 sdhci-of-y				:= sdhci-of-core.o

+ 5 - 6
drivers/mmc/host/at91_mci.c

@@ -928,7 +928,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
 	if (!res)
 	if (!res)
 		return -ENXIO;
 		return -ENXIO;
 
 
-	if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+	if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
 	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
@@ -947,8 +947,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
 	mmc->max_blk_size  = MCI_MAXBLKSIZE;
 	mmc->max_blk_size  = MCI_MAXBLKSIZE;
 	mmc->max_blk_count = MCI_BLKATONCE;
 	mmc->max_blk_count = MCI_BLKATONCE;
 	mmc->max_req_size  = MCI_BUFSIZE;
 	mmc->max_req_size  = MCI_BUFSIZE;
-	mmc->max_phys_segs = MCI_BLKATONCE;
-	mmc->max_hw_segs   = MCI_BLKATONCE;
+	mmc->max_segs      = MCI_BLKATONCE;
 	mmc->max_seg_size  = MCI_BUFSIZE;
 	mmc->max_seg_size  = MCI_BUFSIZE;
 
 
 	host = mmc_priv(mmc);
 	host = mmc_priv(mmc);
@@ -1017,7 +1016,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
 	/*
 	/*
 	 * Map I/O region
 	 * Map I/O region
 	 */
 	 */
-	host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+	host->baseaddr = ioremap(res->start, resource_size(res));
 	if (!host->baseaddr) {
 	if (!host->baseaddr) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto fail1;
 		goto fail1;
@@ -1093,7 +1092,7 @@ fail4b:
 fail5:
 fail5:
 	mmc_free_host(mmc);
 	mmc_free_host(mmc);
 fail6:
 fail6:
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
 	dev_err(&pdev->dev, "probe failed, err %d\n", ret);
 	dev_err(&pdev->dev, "probe failed, err %d\n", ret);
 	return ret;
 	return ret;
 }
 }
@@ -1138,7 +1137,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
 
 
 	iounmap(host->baseaddr);
 	iounmap(host->baseaddr);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
 
 
 	mmc_free_host(mmc);
 	mmc_free_host(mmc);
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);

+ 2 - 3
drivers/mmc/host/atmel-mci.c

@@ -1618,8 +1618,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
 	if (slot_data->bus_width >= 4)
 	if (slot_data->bus_width >= 4)
 		mmc->caps |= MMC_CAP_4_BIT_DATA;
 		mmc->caps |= MMC_CAP_4_BIT_DATA;
 
 
-	mmc->max_hw_segs = 64;
-	mmc->max_phys_segs = 64;
+	mmc->max_segs = 64;
 	mmc->max_req_size = 32768 * 512;
 	mmc->max_req_size = 32768 * 512;
 	mmc->max_blk_size = 32768;
 	mmc->max_blk_size = 32768;
 	mmc->max_blk_count = 512;
 	mmc->max_blk_count = 512;
@@ -1777,7 +1776,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	ret = -ENOMEM;
 	ret = -ENOMEM;
-	host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	host->regs = ioremap(regs->start, resource_size(regs));
 	if (!host->regs)
 	if (!host->regs)
 		goto err_ioremap;
 		goto err_ioremap;
 
 

+ 2 - 2
drivers/mmc/host/au1xmmc.c

@@ -964,7 +964,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
 		goto out1;
 		goto out1;
 	}
 	}
 
 
-	host->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+	host->ioarea = request_mem_region(r->start, resource_size(r),
 					   pdev->name);
 					   pdev->name);
 	if (!host->ioarea) {
 	if (!host->ioarea) {
 		dev_err(&pdev->dev, "mmio already in use\n");
 		dev_err(&pdev->dev, "mmio already in use\n");
@@ -998,7 +998,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
 	mmc->f_max = 24000000;
 	mmc->f_max = 24000000;
 
 
 	mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
 	mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-	mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+	mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
 
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_count = 512;
 	mmc->max_blk_count = 512;

+ 1 - 1
drivers/mmc/host/bfin_sdh.c

@@ -469,7 +469,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	mmc->ops = &sdh_ops;
 	mmc->ops = &sdh_ops;
-	mmc->max_phys_segs = 32;
+	mmc->max_segs = 32;
 	mmc->max_seg_size = 1 << 16;
 	mmc->max_seg_size = 1 << 16;
 	mmc->max_blk_size = 1 << 11;
 	mmc->max_blk_size = 1 << 11;
 	mmc->max_blk_count = 1 << 11;
 	mmc->max_blk_count = 1 << 11;

+ 25 - 29
drivers/mmc/host/cb710-mmc.c

@@ -25,7 +25,7 @@ static const u8 cb710_src_freq_mhz[16] = {
 	50, 55, 60, 65, 70, 75, 80, 85
 	50, 55, 60, 65, 70, 75, 80, 85
 };
 };
 
 
-static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
+static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz)
 {
 {
 	struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
 	struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
 	struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
 	struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
@@ -33,8 +33,11 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
 	u32 divider_idx;
 	u32 divider_idx;
 	int src_hz;
 	int src_hz;
 
 
-	/* this is magic, unverifiable for me, unless I get
-	 * MMC card with cables connected to bus signals */
+	/* on CB710 in HP nx9500:
+	 *   src_freq_idx == 0
+	 *   indexes 1-7 work as written in the table
+	 *   indexes 0,8-15 give no clock output
+	 */
 	pci_read_config_dword(pdev, 0x48, &src_freq_idx);
 	pci_read_config_dword(pdev, 0x48, &src_freq_idx);
 	src_freq_idx = (src_freq_idx >> 16) & 0xF;
 	src_freq_idx = (src_freq_idx >> 16) & 0xF;
 	src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
 	src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
@@ -46,13 +49,15 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
 
 
 	if (src_freq_idx)
 	if (src_freq_idx)
 		divider_idx |= 0x8;
 		divider_idx |= 0x8;
+	else if (divider_idx == 0)
+		divider_idx = 1;
 
 
 	cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
 	cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
 
 
 	dev_dbg(cb710_slot_dev(slot),
 	dev_dbg(cb710_slot_dev(slot),
-		"clock set to %d Hz, wanted %d Hz; flag = %d\n",
+		"clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n",
 		src_hz >> cb710_clock_divider_log2[divider_idx & 7],
 		src_hz >> cb710_clock_divider_log2[divider_idx & 7],
-		hz, (divider_idx & 8) != 0);
+		hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
 }
 }
 
 
 static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
 static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
@@ -95,16 +100,8 @@ static void cb710_mmc_reset_events(struct cb710_slot *slot)
 	cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
 	cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
 }
 }
 
 
-static int cb710_mmc_is_card_inserted(struct cb710_slot *slot)
-{
-	return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
-		& CB710_MMC_S3_CARD_DETECTED;
-}
-
 static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
 static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
 {
 {
-	dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n",
-		enable ? 4 : 1, enable ? "s" : "");
 	if (enable)
 	if (enable)
 		cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
 		cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
 			CB710_MMC_C1_4BIT_DATA_BUS, 0);
 			CB710_MMC_C1_4BIT_DATA_BUS, 0);
@@ -494,13 +491,8 @@ static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	reader->mrq = mrq;
 	reader->mrq = mrq;
 	cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
 	cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
 
 
-	if (cb710_mmc_is_card_inserted(slot)) {
-		if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
-			cb710_mmc_command(mmc, mrq->stop);
-		mdelay(1);
-	} else {
-		mrq->cmd->error = -ENOMEDIUM;
-	}
+	if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
+		cb710_mmc_command(mmc, mrq->stop);
 
 
 	tasklet_schedule(&reader->finish_req_tasklet);
 	tasklet_schedule(&reader->finish_req_tasklet);
 }
 }
@@ -512,7 +504,7 @@ static int cb710_mmc_powerup(struct cb710_slot *slot)
 #endif
 #endif
 	int err;
 	int err;
 
 
-	/* a lot of magic; see comment in cb710_mmc_set_clock() */
+	/* a lot of magic for now */
 	dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
 	dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
 	cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
 	cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
 	err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
 	err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
@@ -572,13 +564,7 @@ static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	struct cb710_mmc_reader *reader = mmc_priv(mmc);
 	struct cb710_mmc_reader *reader = mmc_priv(mmc);
 	int err;
 	int err;
 
 
-	cb710_mmc_set_clock(mmc, ios->clock);
-
-	if (!cb710_mmc_is_card_inserted(slot)) {
-		dev_dbg(cb710_slot_dev(slot),
-			"no card inserted - ignoring bus powerup request\n");
-		ios->power_mode = MMC_POWER_OFF;
-	}
+	cb710_mmc_select_clock_divider(mmc, ios->clock);
 
 
 	if (ios->power_mode != reader->last_power_mode)
 	if (ios->power_mode != reader->last_power_mode)
 	switch (ios->power_mode) {
 	switch (ios->power_mode) {
@@ -619,6 +605,14 @@ static int cb710_mmc_get_ro(struct mmc_host *mmc)
 		& CB710_MMC_S3_WRITE_PROTECTED;
 		& CB710_MMC_S3_WRITE_PROTECTED;
 }
 }
 
 
+static int cb710_mmc_get_cd(struct mmc_host *mmc)
+{
+	struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+
+	return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
+		& CB710_MMC_S3_CARD_DETECTED;
+}
+
 static int cb710_mmc_irq_handler(struct cb710_slot *slot)
 static int cb710_mmc_irq_handler(struct cb710_slot *slot)
 {
 {
 	struct mmc_host *mmc = cb710_slot_to_mmc(slot);
 	struct mmc_host *mmc = cb710_slot_to_mmc(slot);
@@ -664,7 +658,8 @@ static void cb710_mmc_finish_request_tasklet(unsigned long data)
 static const struct mmc_host_ops cb710_mmc_host = {
 static const struct mmc_host_ops cb710_mmc_host = {
 	.request = cb710_mmc_request,
 	.request = cb710_mmc_request,
 	.set_ios = cb710_mmc_set_ios,
 	.set_ios = cb710_mmc_set_ios,
-	.get_ro = cb710_mmc_get_ro
+	.get_ro = cb710_mmc_get_ro,
+	.get_cd = cb710_mmc_get_cd,
 };
 };
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
@@ -746,6 +741,7 @@ static int __devinit cb710_mmc_init(struct platform_device *pdev)
 err_free_mmc:
 err_free_mmc:
 	dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
 	dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
 
 
+	cb710_set_irq_handler(slot, NULL);
 	mmc_free_host(mmc);
 	mmc_free_host(mmc);
 	return err;
 	return err;
 }
 }

+ 3 - 5
drivers/mmc/host/davinci_mmc.c

@@ -138,7 +138,7 @@
 /*
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
  * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
  * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
- * for drivers with max_hw_segs == 1, making the segments bigger (64KB)
+ * for drivers with max_segs == 1, making the segments bigger (64KB)
  * than the page or two that's otherwise typical. nr_sg (passed from
  * than the page or two that's otherwise typical. nr_sg (passed from
  * platform data) == 16 gives at least the same throughput boost, using
  * platform data) == 16 gives at least the same throughput boost, using
  * EDMA transfer linkage instead of spending CPU time copying pages.
  * EDMA transfer linkage instead of spending CPU time copying pages.
@@ -1239,8 +1239,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 	 * Each hw_seg uses one EDMA parameter RAM slot, always one
 	 * Each hw_seg uses one EDMA parameter RAM slot, always one
 	 * channel and then usually some linked slots.
 	 * channel and then usually some linked slots.
 	 */
 	 */
-	mmc->max_hw_segs	= 1 + host->n_link;
-	mmc->max_phys_segs	= mmc->max_hw_segs;
+	mmc->max_segs		= 1 + host->n_link;
 
 
 	/* EDMA limit per hw segment (one or two MBytes) */
 	/* EDMA limit per hw segment (one or two MBytes) */
 	mmc->max_seg_size	= MAX_CCNT * rw_threshold;
 	mmc->max_seg_size	= MAX_CCNT * rw_threshold;
@@ -1250,8 +1249,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 	mmc->max_blk_count	= 65535; /* NBLK is 16 bits */
 	mmc->max_blk_count	= 65535; /* NBLK is 16 bits */
 	mmc->max_req_size	= mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size	= mmc->max_blk_size * mmc->max_blk_count;
 
 
-	dev_dbg(mmc_dev(host->mmc), "max_phys_segs=%d\n", mmc->max_phys_segs);
-	dev_dbg(mmc_dev(host->mmc), "max_hw_segs=%d\n", mmc->max_hw_segs);
+	dev_dbg(mmc_dev(host->mmc), "max_segs=%d\n", mmc->max_segs);
 	dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size);
 	dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size);
 	dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size);
 	dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size);
 	dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size);
 	dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size);

+ 1 - 2
drivers/mmc/host/imxmmc.c

@@ -966,8 +966,7 @@ static int __init imxmci_probe(struct platform_device *pdev)
 	mmc->caps = MMC_CAP_4_BIT_DATA;
 	mmc->caps = MMC_CAP_4_BIT_DATA;
 
 
 	/* MMC core transfer sizes tunable parameters */
 	/* MMC core transfer sizes tunable parameters */
-	mmc->max_hw_segs = 64;
-	mmc->max_phys_segs = 64;
+	mmc->max_segs = 64;
 	mmc->max_seg_size = 64*512;	/* default PAGE_CACHE_SIZE */
 	mmc->max_seg_size = 64*512;	/* default PAGE_CACHE_SIZE */
 	mmc->max_req_size = 64*512;	/* default PAGE_CACHE_SIZE */
 	mmc->max_req_size = 64*512;	/* default PAGE_CACHE_SIZE */
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_size = 2048;

+ 1 - 2
drivers/mmc/host/jz4740_mmc.c

@@ -876,8 +876,7 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
 	mmc->max_blk_count = (1 << 15) - 1;
 	mmc->max_blk_count = (1 << 15) - 1;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
 
-	mmc->max_phys_segs = 128;
-	mmc->max_hw_segs = 128;
+	mmc->max_segs = 128;
 	mmc->max_seg_size = mmc->max_req_size;
 	mmc->max_seg_size = mmc->max_req_size;
 
 
 	host->mmc = mmc;
 	host->mmc = mmc;

+ 22 - 2
drivers/mmc/host/mmc_spi.c

@@ -1055,6 +1055,8 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 {
 	struct mmc_spi_host	*host = mmc_priv(mmc);
 	struct mmc_spi_host	*host = mmc_priv(mmc);
 	int			status = -EINVAL;
 	int			status = -EINVAL;
+	int			crc_retry = 5;
+	struct mmc_command	stop;
 
 
 #ifdef DEBUG
 #ifdef DEBUG
 	/* MMC core and layered drivers *MUST* issue SPI-aware commands */
 	/* MMC core and layered drivers *MUST* issue SPI-aware commands */
@@ -1087,10 +1089,29 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	/* request exclusive bus access */
 	/* request exclusive bus access */
 	spi_bus_lock(host->spi->master);
 	spi_bus_lock(host->spi->master);
 
 
+crc_recover:
 	/* issue command; then optionally data and stop */
 	/* issue command; then optionally data and stop */
 	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
 	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
 	if (status == 0 && mrq->data) {
 	if (status == 0 && mrq->data) {
 		mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
 		mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+
+		/*
+		 * The SPI bus is not always reliable for large data transfers.
+		 * If an occasional crc error is reported by the SD device with
+		 * data read/write over SPI, it may be recovered by repeating
+		 * the last SD command again. The retry count is set to 5 to
+		 * ensure the driver passes stress tests.
+		 */
+		if (mrq->data->error == -EILSEQ && crc_retry) {
+			stop.opcode = MMC_STOP_TRANSMISSION;
+			stop.arg = 0;
+			stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+			status = mmc_spi_command_send(host, mrq, &stop, 0);
+			crc_retry--;
+			mrq->data->error = 0;
+			goto crc_recover;
+		}
+
 		if (mrq->stop)
 		if (mrq->stop)
 			status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
 			status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
 		else
 		else
@@ -1345,8 +1366,7 @@ static int mmc_spi_probe(struct spi_device *spi)
 
 
 	mmc->ops = &mmc_spi_ops;
 	mmc->ops = &mmc_spi_ops;
 	mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
 	mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
-	mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE;
-	mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE;
+	mmc->max_segs = MMC_SPI_BLOCKSATONCE;
 	mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
 	mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
 	mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
 	mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
 
 

+ 19 - 12
drivers/mmc/host/mmci.c

@@ -523,19 +523,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	struct mmci_host *host = mmc_priv(mmc);
 	struct mmci_host *host = mmc_priv(mmc);
 	u32 pwr = 0;
 	u32 pwr = 0;
 	unsigned long flags;
 	unsigned long flags;
+	int ret;
 
 
 	switch (ios->power_mode) {
 	switch (ios->power_mode) {
 	case MMC_POWER_OFF:
 	case MMC_POWER_OFF:
-		if(host->vcc &&
-		   regulator_is_enabled(host->vcc))
-			regulator_disable(host->vcc);
+		if (host->vcc)
+			ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
 		break;
 		break;
 	case MMC_POWER_UP:
 	case MMC_POWER_UP:
-#ifdef CONFIG_REGULATOR
-		if (host->vcc)
-			/* This implicitly enables the regulator */
-			mmc_regulator_set_ocr(host->vcc, ios->vdd);
-#endif
+		if (host->vcc) {
+			ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
+			if (ret) {
+				dev_err(mmc_dev(mmc), "unable to set OCR\n");
+				/*
+				 * The .set_ios() function in the mmc_host_ops
+				 * struct return void, and failing to set the
+				 * power should be rare so we print an error
+				 * and return here.
+				 */
+				return;
+			}
+		}
 		if (host->plat->vdd_handler)
 		if (host->plat->vdd_handler)
 			pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
 			pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
 						       ios->power_mode);
 						       ios->power_mode);
@@ -734,8 +742,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 	/*
 	/*
 	 * We can do SGIO
 	 * We can do SGIO
 	 */
 	 */
-	mmc->max_hw_segs = 16;
-	mmc->max_phys_segs = NR_SG;
+	mmc->max_segs = NR_SG;
 
 
 	/*
 	/*
 	 * Since only a certain number of bits are valid in the data length
 	 * Since only a certain number of bits are valid in the data length
@@ -870,8 +877,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
 		clk_disable(host->clk);
 		clk_disable(host->clk);
 		clk_put(host->clk);
 		clk_put(host->clk);
 
 
-		if (regulator_is_enabled(host->vcc))
-			regulator_disable(host->vcc);
+		if (host->vcc)
+			mmc_regulator_set_ocr(mmc, host->vcc, 0);
 		regulator_put(host->vcc);
 		regulator_put(host->vcc);
 
 
 		mmc_free_host(mmc);
 		mmc_free_host(mmc);

+ 1 - 2
drivers/mmc/host/msm_sdcc.c

@@ -1164,8 +1164,7 @@ msmsdcc_probe(struct platform_device *pdev)
 		mmc->caps |= MMC_CAP_SDIO_IRQ;
 		mmc->caps |= MMC_CAP_SDIO_IRQ;
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
 
-	mmc->max_phys_segs = NR_SG;
-	mmc->max_hw_segs = NR_SG;
+	mmc->max_segs = NR_SG;
 	mmc->max_blk_size = 4096;	/* MCI_DATA_CTL BLOCKSIZE up to 4096 */
 	mmc->max_blk_size = 4096;	/* MCI_DATA_CTL BLOCKSIZE up to 4096 */
 	mmc->max_blk_count = 65536;
 	mmc->max_blk_count = 65536;
 
 

+ 1 - 2
drivers/mmc/host/mvsdio.c

@@ -742,8 +742,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_count = 65535;
 	mmc->max_blk_count = 65535;
 
 
-	mmc->max_hw_segs = 1;
-	mmc->max_phys_segs = 1;
+	mmc->max_segs = 1;
 	mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
 

+ 1 - 2
drivers/mmc/host/mxcmmc.c

@@ -790,8 +790,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
 
 	/* MMC core transfer sizes tunable parameters */
 	/* MMC core transfer sizes tunable parameters */
-	mmc->max_hw_segs = 64;
-	mmc->max_phys_segs = 64;
+	mmc->max_segs = 64;
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_count = 65535;
 	mmc->max_blk_count = 65535;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

+ 1 - 2
drivers/mmc/host/omap.c

@@ -1335,8 +1335,7 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
 	 * NOTE max_seg_size assumption that small blocks aren't
 	 * NOTE max_seg_size assumption that small blocks aren't
 	 * normally used (except e.g. for reading SD registers).
 	 * normally used (except e.g. for reading SD registers).
 	 */
 	 */
-	mmc->max_phys_segs = 32;
-	mmc->max_hw_segs = 32;
+	mmc->max_segs = 32;
 	mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */
 	mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */
 	mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */
 	mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

+ 14 - 10
drivers/mmc/host/omap_hsmmc.c

@@ -250,9 +250,9 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
 		mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 		mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 
 
 	if (power_on)
 	if (power_on)
-		ret = mmc_regulator_set_ocr(host->vcc, vdd);
+		ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
 	else
 	else
-		ret = mmc_regulator_set_ocr(host->vcc, 0);
+		ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
 
 
 	if (mmc_slot(host).after_set_reg)
 	if (mmc_slot(host).after_set_reg)
 		mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
 		mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
@@ -291,18 +291,23 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
 	 * chips/cards need an interface voltage rail too.
 	 * chips/cards need an interface voltage rail too.
 	 */
 	 */
 	if (power_on) {
 	if (power_on) {
-		ret = mmc_regulator_set_ocr(host->vcc, vdd);
+		ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
 		/* Enable interface voltage rail, if needed */
 		/* Enable interface voltage rail, if needed */
 		if (ret == 0 && host->vcc_aux) {
 		if (ret == 0 && host->vcc_aux) {
 			ret = regulator_enable(host->vcc_aux);
 			ret = regulator_enable(host->vcc_aux);
 			if (ret < 0)
 			if (ret < 0)
-				ret = mmc_regulator_set_ocr(host->vcc, 0);
+				ret = mmc_regulator_set_ocr(host->mmc,
+							host->vcc, 0);
 		}
 		}
 	} else {
 	} else {
+		/* Shut down the rail */
 		if (host->vcc_aux)
 		if (host->vcc_aux)
 			ret = regulator_disable(host->vcc_aux);
 			ret = regulator_disable(host->vcc_aux);
-		if (ret == 0)
-			ret = mmc_regulator_set_ocr(host->vcc, 0);
+		if (!ret) {
+			/* Then proceed to shut down the local regulator */
+			ret = mmc_regulator_set_ocr(host->mmc,
+						host->vcc, 0);
+		}
 	}
 	}
 
 
 	if (mmc_slot(host).after_set_reg)
 	if (mmc_slot(host).after_set_reg)
@@ -343,9 +348,9 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
 	if (cardsleep) {
 	if (cardsleep) {
 		/* VCC can be turned off if card is asleep */
 		/* VCC can be turned off if card is asleep */
 		if (sleep)
 		if (sleep)
-			err = mmc_regulator_set_ocr(host->vcc, 0);
+			err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
 		else
 		else
-			err = mmc_regulator_set_ocr(host->vcc, vdd);
+			err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
 	} else
 	} else
 		err = regulator_set_mode(host->vcc, mode);
 		err = regulator_set_mode(host->vcc, mode);
 	if (err)
 	if (err)
@@ -2130,8 +2135,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
 
 	/* Since we do only SG emulation, we can have as many segs
 	/* Since we do only SG emulation, we can have as many segs
 	 * as we want. */
 	 * as we want. */
-	mmc->max_phys_segs = 1024;
-	mmc->max_hw_segs = 1024;
+	mmc->max_segs = 1024;
 
 
 	mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
 	mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
 	mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
 	mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */

+ 34 - 9
drivers/mmc/host/pxamci.c

@@ -99,14 +99,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
 	}
 	}
 }
 }
 
 
-static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+static inline int pxamci_set_power(struct pxamci_host *host,
+				    unsigned char power_mode,
+				    unsigned int vdd)
 {
 {
 	int on;
 	int on;
 
 
-#ifdef CONFIG_REGULATOR
-	if (host->vcc)
-		mmc_regulator_set_ocr(host->vcc, vdd);
-#endif
+	if (host->vcc) {
+		int ret;
+
+		if (power_mode == MMC_POWER_UP) {
+			ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+			if (ret)
+				return ret;
+		} else if (power_mode == MMC_POWER_OFF) {
+			ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+			if (ret)
+				return ret;
+		}
+	}
 	if (!host->vcc && host->pdata &&
 	if (!host->vcc && host->pdata &&
 	    gpio_is_valid(host->pdata->gpio_power)) {
 	    gpio_is_valid(host->pdata->gpio_power)) {
 		on = ((1 << vdd) & host->pdata->ocr_mask);
 		on = ((1 << vdd) & host->pdata->ocr_mask);
@@ -115,6 +126,8 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
 	}
 	}
 	if (!host->vcc && host->pdata && host->pdata->setpower)
 	if (!host->vcc && host->pdata && host->pdata->setpower)
 		host->pdata->setpower(mmc_dev(host->mmc), vdd);
 		host->pdata->setpower(mmc_dev(host->mmc), vdd);
+
+	return 0;
 }
 }
 
 
 static void pxamci_stop_clock(struct pxamci_host *host)
 static void pxamci_stop_clock(struct pxamci_host *host)
@@ -490,9 +503,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	}
 	}
 
 
 	if (host->power_mode != ios->power_mode) {
 	if (host->power_mode != ios->power_mode) {
+		int ret;
+
 		host->power_mode = ios->power_mode;
 		host->power_mode = ios->power_mode;
 
 
-		pxamci_set_power(host, ios->vdd);
+		ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
+		if (ret) {
+			dev_err(mmc_dev(mmc), "unable to set power\n");
+			/*
+			 * The .set_ios() function in the mmc_host_ops
+			 * struct return void, and failing to set the
+			 * power should be rare so we print an error and
+			 * return here.
+			 */
+			return;
+		}
 
 
 		if (ios->power_mode == MMC_POWER_ON)
 		if (ios->power_mode == MMC_POWER_ON)
 			host->cmdat |= CMDAT_INIT;
 			host->cmdat |= CMDAT_INIT;
@@ -503,8 +528,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	else
 	else
 		host->cmdat &= ~CMDAT_SD_4DAT;
 		host->cmdat &= ~CMDAT_SD_4DAT;
 
 
-	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
-		 host->clkrt, host->cmdat);
+	dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
+		host->clkrt, host->cmdat);
 }
 }
 
 
 static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
 static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
@@ -576,7 +601,7 @@ static int pxamci_probe(struct platform_device *pdev)
 	 * We can do SG-DMA, but we don't because we never know how much
 	 * We can do SG-DMA, but we don't because we never know how much
 	 * data we successfully wrote to the card.
 	 * data we successfully wrote to the card.
 	 */
 	 */
-	mmc->max_phys_segs = NR_SG;
+	mmc->max_segs = NR_SG;
 
 
 	/*
 	/*
 	 * Our hardware DMA can handle a maximum of one page per SG entry.
 	 * Our hardware DMA can handle a maximum of one page per SG entry.

+ 1 - 2
drivers/mmc/host/s3cmci.c

@@ -1736,8 +1736,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
 	mmc->max_req_size	= 4095 * 512;
 	mmc->max_req_size	= 4095 * 512;
 	mmc->max_seg_size	= mmc->max_req_size;
 	mmc->max_seg_size	= mmc->max_req_size;
 
 
-	mmc->max_phys_segs	= 128;
-	mmc->max_hw_segs	= 128;
+	mmc->max_segs		= 128;
 
 
 	dbg(host, dbg_debug,
 	dbg(host, dbg_debug,
 	    "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
 	    "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",

+ 1 - 1
drivers/mmc/host/sdhci-cns3xxx.c

@@ -15,7 +15,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 #include <mach/cns3xxx.h>
 #include <mach/cns3xxx.h>
 #include "sdhci.h"
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #include "sdhci-pltfm.h"

+ 143 - 0
drivers/mmc/host/sdhci-esdhc-imx.c

@@ -0,0 +1,143 @@
+/*
+ * Freescale eSDHC i.MX controller driver for the platform bus.
+ *
+ * derived from the OF-version.
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-pltfm.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci-esdhc.h"
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+	void __iomem *base = host->ioaddr + (reg & ~0x3);
+	u32 shift = (reg & 0x3) * 8;
+
+	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+	if (unlikely(reg == SDHCI_HOST_VERSION))
+		reg ^= 2;
+
+	return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	switch (reg) {
+	case SDHCI_TRANSFER_MODE:
+		/*
+		 * Postpone this write, we must do it together with a
+		 * command write that is down below.
+		 */
+		pltfm_host->scratchpad = val;
+		return;
+	case SDHCI_COMMAND:
+		writel(val << 16 | pltfm_host->scratchpad,
+			host->ioaddr + SDHCI_TRANSFER_MODE);
+		return;
+	case SDHCI_BLOCK_SIZE:
+		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+		break;
+	}
+	esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+	u32 new_val;
+
+	switch (reg) {
+	case SDHCI_POWER_CONTROL:
+		/*
+		 * FSL put some DMA bits here
+		 * If your board has a regulator, code should be here
+		 */
+		return;
+	case SDHCI_HOST_CONTROL:
+		/* FSL messed up here, so we can just keep those two */
+		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+		/* ensure the endianess */
+		new_val |= ESDHC_HOST_CONTROL_LE;
+		/* DMA mode bits are shifted */
+		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+		esdhc_clrset_le(host, 0xffff, new_val, reg);
+		return;
+	}
+	esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct clk *clk;
+
+	clk = clk_get(mmc_dev(host->mmc), NULL);
+	if (IS_ERR(clk)) {
+		dev_err(mmc_dev(host->mmc), "clk err\n");
+		return PTR_ERR(clk);
+	}
+	clk_enable(clk);
+	pltfm_host->clk = clk;
+
+	return 0;
+}
+
+static void esdhc_pltfm_exit(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+	.read_w = esdhc_readw_le,
+	.write_w = esdhc_writew_le,
+	.write_b = esdhc_writeb_le,
+	.set_clock = esdhc_set_clock,
+	.get_max_clock = esdhc_pltfm_get_max_clock,
+	.get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
+			| SDHCI_QUIRK_BROKEN_ADMA,
+	/* ADMA has issues. Might be fixable */
+	/* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
+	.ops = &sdhci_esdhc_ops,
+	.init = esdhc_pltfm_init,
+	.exit = esdhc_pltfm_exit,
+};

+ 83 - 0
drivers/mmc/host/sdhci-esdhc.h

@@ -0,0 +1,83 @@
+/*
+ * Freescale eSDHC controller driver generics for OF and pltfm.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
+#define _DRIVERS_MMC_SDHCI_ESDHC_H
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DEFAULT_QUIRKS	(SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
+				SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
+				SDHCI_QUIRK_NO_BUSY_IRQ | \
+				SDHCI_QUIRK_NONSTANDARD_CLOCK | \
+				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
+				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
+				SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \
+				SDHCI_QUIRK_NO_CARD_NO_RESET)
+
+#define ESDHC_SYSTEM_CONTROL	0x2c
+#define ESDHC_CLOCK_MASK	0x0000fff0
+#define ESDHC_PREDIV_SHIFT	8
+#define ESDHC_DIVIDER_SHIFT	4
+#define ESDHC_CLOCK_PEREN	0x00000004
+#define ESDHC_CLOCK_HCKEN	0x00000002
+#define ESDHC_CLOCK_IPGEN	0x00000001
+
+/* pltfm-specific */
+#define ESDHC_HOST_CONTROL_LE	0x20
+
+/* OF-specific */
+#define ESDHC_DMA_SYSCTL	0x40c
+#define ESDHC_DMA_SNOOP		0x00000040
+
+#define ESDHC_HOST_CONTROL_RES	0x05
+
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	int pre_div = 2;
+	int div = 1;
+	u32 temp;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| ESDHC_CLOCK_MASK);
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+	if (clock == 0)
+		goto out;
+
+	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+		pre_div *= 2;
+
+	while (host->max_clk / pre_div / div > clock && div < 16)
+		div++;
+
+	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+		clock, host->max_clk / pre_div / div);
+
+	pre_div >>= 1;
+	div--;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| (div << ESDHC_DIVIDER_SHIFT)
+		| (pre_div << ESDHC_PREDIV_SHIFT));
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+	mdelay(100);
+out:
+	host->clock = clock;
+}
+
+#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */

+ 8 - 62
drivers/mmc/host/sdhci-of-esdhc.c

@@ -18,23 +18,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci-of.h"
 #include "sdhci.h"
 #include "sdhci.h"
-
-/*
- * Ops and quirks for the Freescale eSDHC controller.
- */
-
-#define ESDHC_DMA_SYSCTL	0x40c
-#define ESDHC_DMA_SNOOP		0x00000040
-
-#define ESDHC_SYSTEM_CONTROL	0x2c
-#define ESDHC_CLOCK_MASK	0x0000fff0
-#define ESDHC_PREDIV_SHIFT	8
-#define ESDHC_DIVIDER_SHIFT	4
-#define ESDHC_CLOCK_PEREN	0x00000004
-#define ESDHC_CLOCK_HCKEN	0x00000002
-#define ESDHC_CLOCK_IPGEN	0x00000001
-
-#define ESDHC_HOST_CONTROL_RES	0x05
+#include "sdhci-esdhc.h"
 
 
 static u16 esdhc_readw(struct sdhci_host *host, int reg)
 static u16 esdhc_readw(struct sdhci_host *host, int reg)
 {
 {
@@ -68,51 +52,20 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
 	sdhci_be32bs_writeb(host, val, reg);
 	sdhci_be32bs_writeb(host, val, reg);
 }
 }
 
 
-static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-	int pre_div = 2;
-	int div = 1;
-
-	clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-		  ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
-
-	if (clock == 0)
-		goto out;
-
-	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
-		pre_div *= 2;
-
-	while (host->max_clk / pre_div / div > clock && div < 16)
-		div++;
-
-	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-		clock, host->max_clk / pre_div / div);
-
-	pre_div >>= 1;
-	div--;
-
-	setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-		  ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
-		  div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
-	mdelay(100);
-out:
-	host->clock = clock;
-}
-
-static int esdhc_enable_dma(struct sdhci_host *host)
+static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
 {
 	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
 	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
 	return 0;
 	return 0;
 }
 }
 
 
-static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
 {
 {
 	struct sdhci_of_host *of_host = sdhci_priv(host);
 	struct sdhci_of_host *of_host = sdhci_priv(host);
 
 
 	return of_host->clock;
 	return of_host->clock;
 }
 }
 
 
-static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 {
 {
 	struct sdhci_of_host *of_host = sdhci_priv(host);
 	struct sdhci_of_host *of_host = sdhci_priv(host);
 
 
@@ -120,14 +73,7 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
 }
 }
 
 
 struct sdhci_of_data sdhci_esdhc = {
 struct sdhci_of_data sdhci_esdhc = {
-	.quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
-		  SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-		  SDHCI_QUIRK_NO_BUSY_IRQ |
-		  SDHCI_QUIRK_NONSTANDARD_CLOCK |
-		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-		  SDHCI_QUIRK_PIO_NEEDS_DELAY |
-		  SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
-		  SDHCI_QUIRK_NO_CARD_NO_RESET,
+	.quirks = ESDHC_DEFAULT_QUIRKS,
 	.ops = {
 	.ops = {
 		.read_l = sdhci_be32bs_readl,
 		.read_l = sdhci_be32bs_readl,
 		.read_w = esdhc_readw,
 		.read_w = esdhc_readw,
@@ -136,8 +82,8 @@ struct sdhci_of_data sdhci_esdhc = {
 		.write_w = esdhc_writew,
 		.write_w = esdhc_writew,
 		.write_b = esdhc_writeb,
 		.write_b = esdhc_writeb,
 		.set_clock = esdhc_set_clock,
 		.set_clock = esdhc_set_clock,
-		.enable_dma = esdhc_enable_dma,
-		.get_max_clock = esdhc_get_max_clock,
-		.get_min_clock = esdhc_get_min_clock,
+		.enable_dma = esdhc_of_enable_dma,
+		.get_max_clock = esdhc_of_get_max_clock,
+		.get_min_clock = esdhc_of_get_min_clock,
 	},
 	},
 };
 };

+ 89 - 0
drivers/mmc/host/sdhci-pci.c

@@ -145,6 +145,37 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
 			  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 			  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 };
 
 
+/*
+ * ADMA operation is disabled for Moorestown platform due to
+ * hardware bugs.
+ */
+static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
+{
+	/*
+	 * slots number is fixed here for MRST as SDIO3 is never used and has
+	 * hardware bugs.
+	 */
+	chip->num_slots = 1;
+	return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
+	.quirks		= SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
+	.quirks		= SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+	.probe		= mrst_hc1_probe,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
+	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
+	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 {
 {
 	u8 scratch;
 	u8 scratch;
@@ -494,6 +525,62 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 		.driver_data	= (kernel_ulong_t)&sdhci_via,
 		.driver_data	= (kernel_ulong_t)&sdhci_via,
 	},
 	},
 
 
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MRST_SD0,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mrst_hc0,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MRST_SD1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mrst_hc1,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MFD_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mfd_sd,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MFD_SDIO1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MFD_SDIO2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MFD_EMMC0,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_MFD_EMMC1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+	},
+
 	{	/* Generic SD host controller */
 	{	/* Generic SD host controller */
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 	},
 	},
@@ -818,6 +905,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
 			goto free;
 			goto free;
 	}
 	}
 
 
+	slots = chip->num_slots;	/* Quirk may have changed this */
+
 	for (i = 0;i < slots;i++) {
 	for (i = 0;i < slots;i++) {
 		slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
 		slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
 		if (IS_ERR(slot)) {
 		if (IS_ERR(slot)) {

+ 37 - 7
drivers/mmc/host/sdhci-pltfm.c

@@ -30,7 +30,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 
 
 #include <linux/io.h>
 #include <linux/io.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 
 
 #include "sdhci.h"
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #include "sdhci-pltfm.h"
@@ -52,14 +52,17 @@ static struct sdhci_ops sdhci_pltfm_ops = {
 
 
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 {
 {
-	struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
 	const struct platform_device_id *platid = platform_get_device_id(pdev);
 	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	struct sdhci_pltfm_data *pdata;
 	struct sdhci_host *host;
 	struct sdhci_host *host;
+	struct sdhci_pltfm_host *pltfm_host;
 	struct resource *iomem;
 	struct resource *iomem;
 	int ret;
 	int ret;
 
 
-	if (!pdata && platid && platid->driver_data)
+	if (platid && platid->driver_data)
 		pdata = (void *)platid->driver_data;
 		pdata = (void *)platid->driver_data;
+	else
+		pdata = pdev->dev.platform_data;
 
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iomem) {
 	if (!iomem) {
@@ -71,16 +74,19 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "Invalid iomem size. You may "
 		dev_err(&pdev->dev, "Invalid iomem size. You may "
 			"experience problems.\n");
 			"experience problems.\n");
 
 
-	if (pdev->dev.parent)
-		host = sdhci_alloc_host(pdev->dev.parent, 0);
+	/* Some PCI-based MFD need the parent here */
+	if (pdev->dev.parent != &platform_bus)
+		host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
 	else
 	else
-		host = sdhci_alloc_host(&pdev->dev, 0);
+		host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
 
 
 	if (IS_ERR(host)) {
 	if (IS_ERR(host)) {
 		ret = PTR_ERR(host);
 		ret = PTR_ERR(host);
 		goto err;
 		goto err;
 	}
 	}
 
 
+	pltfm_host = sdhci_priv(host);
+
 	host->hw_name = "platform";
 	host->hw_name = "platform";
 	if (pdata && pdata->ops)
 	if (pdata && pdata->ops)
 		host->ops = pdata->ops;
 		host->ops = pdata->ops;
@@ -105,7 +111,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	if (pdata && pdata->init) {
 	if (pdata && pdata->init) {
-		ret = pdata->init(host);
+		ret = pdata->init(host, pdata);
 		if (ret)
 		if (ret)
 			goto err_plat_init;
 			goto err_plat_init;
 	}
 	}
@@ -160,11 +166,33 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
 	{ "sdhci", },
 	{ "sdhci", },
 #ifdef CONFIG_MMC_SDHCI_CNS3XXX
 #ifdef CONFIG_MMC_SDHCI_CNS3XXX
 	{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
 	{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
+#endif
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+	{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
 #endif
 #endif
 	{ },
 	{ },
 };
 };
 MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
 MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
 
 
+#ifdef CONFIG_PM
+static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct sdhci_host *host = platform_get_drvdata(dev);
+
+	return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pltfm_resume(struct platform_device *dev)
+{
+	struct sdhci_host *host = platform_get_drvdata(dev);
+
+	return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pltfm_suspend	NULL
+#define sdhci_pltfm_resume	NULL
+#endif	/* CONFIG_PM */
+
 static struct platform_driver sdhci_pltfm_driver = {
 static struct platform_driver sdhci_pltfm_driver = {
 	.driver = {
 	.driver = {
 		.name	= "sdhci",
 		.name	= "sdhci",
@@ -173,6 +201,8 @@ static struct platform_driver sdhci_pltfm_driver = {
 	.probe		= sdhci_pltfm_probe,
 	.probe		= sdhci_pltfm_probe,
 	.remove		= __devexit_p(sdhci_pltfm_remove),
 	.remove		= __devexit_p(sdhci_pltfm_remove),
 	.id_table	= sdhci_pltfm_ids,
 	.id_table	= sdhci_pltfm_ids,
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
 };
 };
 
 
 /*****************************************************************************\
 /*****************************************************************************\

+ 9 - 1
drivers/mmc/host/sdhci-pltfm.h

@@ -11,8 +11,16 @@
 #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
 #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
 #define _DRIVERS_MMC_SDHCI_PLTFM_H
 #define _DRIVERS_MMC_SDHCI_PLTFM_H
 
 
-#include <linux/sdhci-pltfm.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/mmc/sdhci-pltfm.h>
+
+struct sdhci_pltfm_host {
+	struct clk *clk;
+	u32 scratchpad; /* to handle quirks across io-accessor calls */
+};
 
 
 extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
 extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
+extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
 
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */

+ 253 - 0
drivers/mmc/host/sdhci-pxa.c

@@ -0,0 +1,253 @@
+/* linux/drivers/mmc/host/sdhci-pxa.c
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *		Zhangfei Gao <zhangfei.gao@marvell.com>
+ *		Kevin Wang <dwang4@marvell.com>
+ *		Mingwei Wang <mwwang@marvell.com>
+ *		Philip Rakity <prakity@marvell.com>
+ *		Mark Brown <markb@marvell.com>
+ *
+ * This program 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.
+ */
+
+/* Supports:
+ * SDHCI support for MMP2/PXA910/PXA168
+ *
+ * Refer to sdhci-s3c.c.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <plat/sdhci.h>
+#include "sdhci.h"
+
+#define DRIVER_NAME	"sdhci-pxa"
+
+#define SD_FIFO_PARAM		0x104
+#define DIS_PAD_SD_CLK_GATE	0x400
+
+struct sdhci_pxa {
+	struct sdhci_host		*host;
+	struct sdhci_pxa_platdata	*pdata;
+	struct clk			*clk;
+	struct resource			*res;
+
+	u8 clk_enable;
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * SDHCI core callbacks                                                      *
+ *                                                                           *
+\*****************************************************************************/
+static void set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	struct sdhci_pxa *pxa = sdhci_priv(host);
+	u32 tmp = 0;
+
+	if (clock == 0) {
+		if (pxa->clk_enable) {
+			clk_disable(pxa->clk);
+			pxa->clk_enable = 0;
+		}
+	} else {
+		if (0 == pxa->clk_enable) {
+			if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) {
+				tmp = readl(host->ioaddr + SD_FIFO_PARAM);
+				tmp |= DIS_PAD_SD_CLK_GATE;
+				writel(tmp, host->ioaddr + SD_FIFO_PARAM);
+			}
+			clk_enable(pxa->clk);
+			pxa->clk_enable = 1;
+		}
+	}
+}
+
+static struct sdhci_ops sdhci_pxa_ops = {
+	.set_clock = set_clock,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
+{
+	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct sdhci_host *host = NULL;
+	struct resource *iomem = NULL;
+	struct sdhci_pxa *pxa = NULL;
+	int ret, irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no irq specified\n");
+		return irq;
+	}
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem) {
+		dev_err(dev, "no memory specified\n");
+		return -ENOENT;
+	}
+
+	host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa));
+	if (IS_ERR(host)) {
+		dev_err(dev, "failed to alloc host\n");
+		return PTR_ERR(host);
+	}
+
+	pxa = sdhci_priv(host);
+	pxa->host = host;
+	pxa->pdata = pdata;
+	pxa->clk_enable = 0;
+
+	pxa->clk = clk_get(dev, "PXA-SDHCLK");
+	if (IS_ERR(pxa->clk)) {
+		dev_err(dev, "failed to get io clock\n");
+		ret = PTR_ERR(pxa->clk);
+		goto out;
+	}
+
+	pxa->res = request_mem_region(iomem->start, resource_size(iomem),
+				      mmc_hostname(host->mmc));
+	if (!pxa->res) {
+		dev_err(&pdev->dev, "cannot request region\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+	if (!host->ioaddr) {
+		dev_err(&pdev->dev, "failed to remap registers\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	host->hw_name = "MMC";
+	host->ops = &sdhci_pxa_ops;
+	host->irq = irq;
+	host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+	if (pdata->quirks)
+		host->quirks |= pdata->quirks;
+
+	ret = sdhci_add_host(host);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add host\n");
+		goto out;
+	}
+
+	if (pxa->pdata->max_speed)
+		host->mmc->f_max = pxa->pdata->max_speed;
+
+	platform_set_drvdata(pdev, host);
+
+	return 0;
+out:
+	if (host) {
+		clk_put(pxa->clk);
+		if (host->ioaddr)
+			iounmap(host->ioaddr);
+		if (pxa->res)
+			release_mem_region(pxa->res->start,
+					   resource_size(pxa->res));
+		sdhci_free_host(host);
+	}
+
+	return ret;
+}
+
+static int __devexit sdhci_pxa_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct sdhci_pxa *pxa = sdhci_priv(host);
+	int dead = 0;
+	u32 scratch;
+
+	if (host) {
+		scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+		if (scratch == (u32)-1)
+			dead = 1;
+
+		sdhci_remove_host(host, dead);
+
+		if (host->ioaddr)
+			iounmap(host->ioaddr);
+		if (pxa->res)
+			release_mem_region(pxa->res->start,
+					   resource_size(pxa->res));
+		if (pxa->clk_enable) {
+			clk_disable(pxa->clk);
+			pxa->clk_enable = 0;
+		}
+		clk_put(pxa->clk);
+
+		sdhci_free_host(host);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct sdhci_host *host = platform_get_drvdata(dev);
+
+	return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pxa_resume(struct platform_device *dev)
+{
+	struct sdhci_host *host = platform_get_drvdata(dev);
+
+	return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pxa_suspend	NULL
+#define sdhci_pxa_resume	NULL
+#endif
+
+static struct platform_driver sdhci_pxa_driver = {
+	.probe		= sdhci_pxa_probe,
+	.remove		= __devexit_p(sdhci_pxa_remove),
+	.suspend	= sdhci_pxa_suspend,
+	.resume		= sdhci_pxa_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_pxa_init(void)
+{
+	return platform_driver_register(&sdhci_pxa_driver);
+}
+
+static void __exit sdhci_pxa_exit(void)
+{
+	platform_driver_unregister(&sdhci_pxa_driver);
+}
+
+module_init(sdhci_pxa_init);
+module_exit(sdhci_pxa_exit);
+
+MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
+MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
+MODULE_LICENSE("GPL v2");

+ 57 - 29
drivers/mmc/host/sdhci.c

@@ -47,7 +47,8 @@ static void sdhci_finish_command(struct sdhci_host *);
 
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
 {
-	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+	printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+		mmc_hostname(host->mmc));
 
 
 	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
 	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
 		sdhci_readl(host, SDHCI_DMA_ADDRESS),
 		sdhci_readl(host, SDHCI_DMA_ADDRESS),
@@ -1001,13 +1002,28 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	if (clock == 0)
 	if (clock == 0)
 		goto out;
 		goto out;
 
 
-	for (div = 1;div < 256;div *= 2) {
-		if ((host->max_clk / div) <= clock)
-			break;
+	if (host->version >= SDHCI_SPEC_300) {
+		/* Version 3.00 divisors must be a multiple of 2. */
+		if (host->max_clk <= clock)
+			div = 1;
+		else {
+			for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
+				if ((host->max_clk / div) <= clock)
+					break;
+			}
+		}
+	} else {
+		/* Version 2.00 divisors must be a power of 2. */
+		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+			if ((host->max_clk / div) <= clock)
+				break;
+		}
 	}
 	}
 	div >>= 1;
 	div >>= 1;
 
 
-	clk = div << SDHCI_DIVIDER_SHIFT;
+	clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+		<< SDHCI_DIVIDER_HI_SHIFT;
 	clk |= SDHCI_CLOCK_INT_EN;
 	clk |= SDHCI_CLOCK_INT_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
 
@@ -1034,11 +1050,9 @@ out:
 
 
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
 {
-	u8 pwr;
+	u8 pwr = 0;
 
 
-	if (power == (unsigned short)-1)
-		pwr = 0;
-	else {
+	if (power != (unsigned short)-1) {
 		switch (1 << power) {
 		switch (1 << power) {
 		case MMC_VDD_165_195:
 		case MMC_VDD_165_195:
 			pwr = SDHCI_POWER_180;
 			pwr = SDHCI_POWER_180;
@@ -1168,6 +1182,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	else
 	else
 		sdhci_set_power(host, ios->vdd);
 		sdhci_set_power(host, ios->vdd);
 
 
+	if (host->ops->platform_send_init_74_clocks)
+		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
+
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
 
 	if (ios->bus_width == MMC_BUS_WIDTH_8)
 	if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -1180,8 +1197,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	else
 	else
 		ctrl &= ~SDHCI_CTRL_4BITBUS;
 		ctrl &= ~SDHCI_CTRL_4BITBUS;
 
 
-	if (ios->timing == MMC_TIMING_SD_HS &&
-	    !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
+	if ((ios->timing == MMC_TIMING_SD_HS ||
+	     ios->timing == MMC_TIMING_MMC_HS)
+	    && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
 		ctrl |= SDHCI_CTRL_HISPD;
 		ctrl |= SDHCI_CTRL_HISPD;
 	else
 	else
 		ctrl &= ~SDHCI_CTRL_HISPD;
 		ctrl &= ~SDHCI_CTRL_HISPD;
@@ -1205,22 +1223,25 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 {
 {
 	struct sdhci_host *host;
 	struct sdhci_host *host;
 	unsigned long flags;
 	unsigned long flags;
-	int present;
+	int is_readonly;
 
 
 	host = mmc_priv(mmc);
 	host = mmc_priv(mmc);
 
 
 	spin_lock_irqsave(&host->lock, flags);
 	spin_lock_irqsave(&host->lock, flags);
 
 
 	if (host->flags & SDHCI_DEVICE_DEAD)
 	if (host->flags & SDHCI_DEVICE_DEAD)
-		present = 0;
+		is_readonly = 0;
+	else if (host->ops->get_ro)
+		is_readonly = host->ops->get_ro(host);
 	else
 	else
-		present = sdhci_readl(host, SDHCI_PRESENT_STATE);
+		is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
+				& SDHCI_WRITE_PROTECT);
 
 
 	spin_unlock_irqrestore(&host->lock, flags);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 
-	if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
-		return !!(present & SDHCI_WRITE_PROTECT);
-	return !(present & SDHCI_WRITE_PROTECT);
+	/* This quirk needs to be replaced by a callback-function later */
+	return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
+		!is_readonly : is_readonly;
 }
 }
 
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1427,7 +1448,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 		sdhci_finish_command(host);
 		sdhci_finish_command(host);
 }
 }
 
 
-#ifdef DEBUG
+#ifdef CONFIG_MMC_DEBUG
 static void sdhci_show_adma_error(struct sdhci_host *host)
 static void sdhci_show_adma_error(struct sdhci_host *host)
 {
 {
 	const char *name = mmc_hostname(host->mmc);
 	const char *name = mmc_hostname(host->mmc);
@@ -1708,7 +1729,7 @@ int sdhci_add_host(struct sdhci_host *host)
 	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
 	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
 	host->version = (host->version & SDHCI_SPEC_VER_MASK)
 	host->version = (host->version & SDHCI_SPEC_VER_MASK)
 				>> SDHCI_SPEC_VER_SHIFT;
 				>> SDHCI_SPEC_VER_SHIFT;
-	if (host->version > SDHCI_SPEC_200) {
+	if (host->version > SDHCI_SPEC_300) {
 		printk(KERN_ERR "%s: Unknown controller version (%d). "
 		printk(KERN_ERR "%s: Unknown controller version (%d). "
 			"You may experience problems.\n", mmc_hostname(mmc),
 			"You may experience problems.\n", mmc_hostname(mmc),
 			host->version);
 			host->version);
@@ -1779,8 +1800,13 @@ int sdhci_add_host(struct sdhci_host *host)
 		mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
 		mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
 	}
 	}
 
 
-	host->max_clk =
-		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+	if (host->version >= SDHCI_SPEC_300)
+		host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+			>> SDHCI_CLOCK_BASE_SHIFT;
+	else
+		host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+			>> SDHCI_CLOCK_BASE_SHIFT;
+
 	host->max_clk *= 1000000;
 	host->max_clk *= 1000000;
 	if (host->max_clk == 0 || host->quirks &
 	if (host->max_clk == 0 || host->quirks &
 			SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
 			SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
@@ -1815,18 +1841,21 @@ int sdhci_add_host(struct sdhci_host *host)
 	mmc->ops = &sdhci_ops;
 	mmc->ops = &sdhci_ops;
 	if (host->ops->get_min_clock)
 	if (host->ops->get_min_clock)
 		mmc->f_min = host->ops->get_min_clock(host);
 		mmc->f_min = host->ops->get_min_clock(host);
+	else if (host->version >= SDHCI_SPEC_300)
+		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
 	else
 	else
-		mmc->f_min = host->max_clk / 256;
+		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 	mmc->f_max = host->max_clk;
 	mmc->f_max = host->max_clk;
 	mmc->caps |= MMC_CAP_SDIO_IRQ;
 	mmc->caps |= MMC_CAP_SDIO_IRQ;
 
 
 	if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
 	if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
-		mmc->caps |= MMC_CAP_4_BIT_DATA;
+		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
 
 
 	if (caps & SDHCI_CAN_DO_HISPD)
 	if (caps & SDHCI_CAN_DO_HISPD)
-		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
 
-	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
+	    mmc_card_is_removable(mmc))
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 
 
 	mmc->ocr_avail = 0;
 	mmc->ocr_avail = 0;
@@ -1850,12 +1879,11 @@ int sdhci_add_host(struct sdhci_host *host)
 	 * can do scatter/gather or not.
 	 * can do scatter/gather or not.
 	 */
 	 */
 	if (host->flags & SDHCI_USE_ADMA)
 	if (host->flags & SDHCI_USE_ADMA)
-		mmc->max_hw_segs = 128;
+		mmc->max_segs = 128;
 	else if (host->flags & SDHCI_USE_SDMA)
 	else if (host->flags & SDHCI_USE_SDMA)
-		mmc->max_hw_segs = 1;
+		mmc->max_segs = 1;
 	else /* PIO */
 	else /* PIO */
-		mmc->max_hw_segs = 128;
-	mmc->max_phys_segs = 128;
+		mmc->max_segs = 128;
 
 
 	/*
 	/*
 	 * Maximum number of sectors in one transfer. Limited by DMA boundary
 	 * Maximum number of sectors in one transfer. Limited by DMA boundary

+ 21 - 129
drivers/mmc/host/sdhci.h

@@ -1,6 +1,8 @@
 /*
 /*
  *  linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
  *  linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
  *
  *
+ * Header file for Host Controller registers and I/O accessors.
+ *
  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
@@ -8,14 +10,16 @@
  * the Free Software Foundation; either version 2 of the License, or (at
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
  * your option) any later version.
  */
  */
-#ifndef __SDHCI_H
-#define __SDHCI_H
+#ifndef __SDHCI_HW_H
+#define __SDHCI_HW_H
 
 
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/compiler.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/io.h>
 #include <linux/io.h>
 
 
+#include <linux/mmc/sdhci.h>
+
 /*
 /*
  * Controller registers
  * Controller registers
  */
  */
@@ -86,6 +90,10 @@
 
 
 #define SDHCI_CLOCK_CONTROL	0x2C
 #define SDHCI_CLOCK_CONTROL	0x2C
 #define  SDHCI_DIVIDER_SHIFT	8
 #define  SDHCI_DIVIDER_SHIFT	8
+#define  SDHCI_DIVIDER_HI_SHIFT	6
+#define  SDHCI_DIV_MASK	0xFF
+#define  SDHCI_DIV_MASK_LEN	8
+#define  SDHCI_DIV_HI_MASK	0x300
 #define  SDHCI_CLOCK_CARD_EN	0x0004
 #define  SDHCI_CLOCK_CARD_EN	0x0004
 #define  SDHCI_CLOCK_INT_STABLE	0x0002
 #define  SDHCI_CLOCK_INT_STABLE	0x0002
 #define  SDHCI_CLOCK_INT_EN	0x0001
 #define  SDHCI_CLOCK_INT_EN	0x0001
@@ -140,6 +148,7 @@
 #define  SDHCI_TIMEOUT_CLK_SHIFT 0
 #define  SDHCI_TIMEOUT_CLK_SHIFT 0
 #define  SDHCI_TIMEOUT_CLK_UNIT	0x00000080
 #define  SDHCI_TIMEOUT_CLK_UNIT	0x00000080
 #define  SDHCI_CLOCK_BASE_MASK	0x00003F00
 #define  SDHCI_CLOCK_BASE_MASK	0x00003F00
+#define  SDHCI_CLOCK_V3_BASE_MASK	0x0000FF00
 #define  SDHCI_CLOCK_BASE_SHIFT	8
 #define  SDHCI_CLOCK_BASE_SHIFT	8
 #define  SDHCI_MAX_BLOCK_MASK	0x00030000
 #define  SDHCI_MAX_BLOCK_MASK	0x00030000
 #define  SDHCI_MAX_BLOCK_SHIFT  16
 #define  SDHCI_MAX_BLOCK_SHIFT  16
@@ -178,134 +187,14 @@
 #define  SDHCI_SPEC_VER_SHIFT	0
 #define  SDHCI_SPEC_VER_SHIFT	0
 #define   SDHCI_SPEC_100	0
 #define   SDHCI_SPEC_100	0
 #define   SDHCI_SPEC_200	1
 #define   SDHCI_SPEC_200	1
+#define   SDHCI_SPEC_300	2
 
 
-struct sdhci_ops;
-
-struct sdhci_host {
-	/* Data set by hardware interface driver */
-	const char		*hw_name;	/* Hardware bus name */
-
-	unsigned int		quirks;		/* Deviations from spec. */
-
-/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
-/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA				(1<<1)
-/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
-/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
-/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
-/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
-/* Controller has an unusable ADMA engine */
-#define SDHCI_QUIRK_BROKEN_ADMA				(1<<6)
-/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<7)
-/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<8)
-/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_ADMA_SIZE			(1<<9)
-/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<10)
-/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<11)
-/* Controller provides an incorrect timeout value for transfers */
-#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<12)
-/* Controller has an issue with buffer bits for small transfers */
-#define SDHCI_QUIRK_BROKEN_SMALL_PIO			(1<<13)
-/* Controller does not provide transfer-complete interrupt when not busy */
-#define SDHCI_QUIRK_NO_BUSY_IRQ				(1<<14)
-/* Controller has unreliable card detection */
-#define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15)
-/* Controller reports inverted write-protect state */
-#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16)
-/* Controller has nonstandard clock management */
-#define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<17)
-/* Controller does not like fast PIO transfers */
-#define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)
-/* Controller losing signal/interrupt enable states after reset */
-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET		(1<<19)
-/* Controller has to be forced to use block size of 2048 bytes */
-#define SDHCI_QUIRK_FORCE_BLK_SZ_2048			(1<<20)
-/* Controller cannot do multi-block transfers */
-#define SDHCI_QUIRK_NO_MULTIBLOCK			(1<<21)
-/* Controller can only handle 1-bit data transfers */
-#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 reports wrong base clock capability */
-#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN		(1<<25)
-/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC		(1<<26)
-/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS			(1<<27)
-/* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12		(1<<28)
-/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define SDHCI_QUIRK_NO_HISPD_BIT			(1<<29)
-
-	int			irq;		/* Device IRQ */
-	void __iomem *		ioaddr;		/* Mapped address */
-
-	const struct sdhci_ops	*ops;		/* Low level hw interface */
-
-	struct regulator	*vmmc;		/* Power regulator */
-
-	/* Internal data */
-	struct mmc_host		*mmc;		/* MMC structure */
-	u64			dma_mask;	/* custom DMA mask */
-
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
-	struct led_classdev	led;		/* LED control */
-	char   led_name[32];
-#endif
-
-	spinlock_t		lock;		/* Mutex */
-
-	int			flags;		/* Host attributes */
-#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 */
-
-	unsigned int		version;	/* SDHCI spec. version */
-
-	unsigned int		max_clk;	/* Max possible freq (MHz) */
-	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
-
-	unsigned int		clock;		/* Current clock (MHz) */
-	u8			pwr;		/* Current voltage */
-
-	struct mmc_request	*mrq;		/* Current request */
-	struct mmc_command	*cmd;		/* Current command */
-	struct mmc_data		*data;		/* Current data request */
-	unsigned int		data_early:1;	/* Data finished before cmd */
-
-	struct sg_mapping_iter	sg_miter;	/* SG state for PIO */
-	unsigned int		blocks;		/* remaining PIO blocks */
-
-	int			sg_count;	/* Mapped sg entries */
-
-	u8			*adma_desc;	/* ADMA descriptor table */
-	u8			*align_buffer;	/* Bounce buffer */
-
-	dma_addr_t		adma_addr;	/* Mapped ADMA descr. table */
-	dma_addr_t		align_addr;	/* Mapped bounce buffer */
-
-	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
-	struct tasklet_struct	finish_tasklet;
-
-	struct timer_list	timer;		/* Timer for timeouts */
-
-	unsigned int		caps;		/* Alternative capabilities */
-
-	unsigned long		private[0] ____cacheline_aligned;
-};
+/*
+ * End of controller registers.
+ */
 
 
+#define SDHCI_MAX_DIV_SPEC_200	256
+#define SDHCI_MAX_DIV_SPEC_300	2046
 
 
 struct sdhci_ops {
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -323,6 +212,9 @@ struct sdhci_ops {
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_min_clock)(struct sdhci_host *host);
 	unsigned int	(*get_min_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
+	void (*platform_send_init_74_clocks)(struct sdhci_host *host,
+					     u8 power_mode);
+	unsigned int    (*get_ro)(struct sdhci_host *host);
 };
 };
 
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -427,4 +319,4 @@ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
 extern int sdhci_resume_host(struct sdhci_host *host);
 extern int sdhci_resume_host(struct sdhci_host *host);
 #endif
 #endif
 
 
-#endif /* __SDHCI_H */
+#endif /* __SDHCI_HW_H */

+ 1 - 2
drivers/mmc/host/sh_mmcif.c

@@ -846,8 +846,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 	mmc->caps = MMC_CAP_MMC_HIGHSPEED;
 	mmc->caps = MMC_CAP_MMC_HIGHSPEED;
 	if (pd->caps)
 	if (pd->caps)
 		mmc->caps |= pd->caps;
 		mmc->caps |= pd->caps;
-	mmc->max_phys_segs = 128;
-	mmc->max_hw_segs = 128;
+	mmc->max_segs = 128;
 	mmc->max_blk_size = 512;
 	mmc->max_blk_size = 512;
 	mmc->max_blk_count = 65535;
 	mmc->max_blk_count = 65535;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

+ 1 - 2
drivers/mmc/host/tifm_sd.c

@@ -978,11 +978,10 @@ static int tifm_sd_probe(struct tifm_dev *sock)
 	mmc->f_max = 24000000;
 	mmc->f_max = 24000000;
 
 
 	mmc->max_blk_count = 2048;
 	mmc->max_blk_count = 2048;
-	mmc->max_hw_segs = mmc->max_blk_count;
+	mmc->max_segs = mmc->max_blk_count;
 	mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
 	mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
 	mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
 	mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
 	mmc->max_req_size = mmc->max_seg_size;
 	mmc->max_req_size = mmc->max_seg_size;
-	mmc->max_phys_segs = mmc->max_hw_segs;
 
 
 	sock->card_event = tifm_sd_card_event;
 	sock->card_event = tifm_sd_card_event;
 	sock->data_event = tifm_sd_data_event;
 	sock->data_event = tifm_sd_data_event;

+ 566 - 0
drivers/mmc/host/ushc.c

@@ -0,0 +1,566 @@
+/*
+ * USB SD Host Controller (USHC) controller driver.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Notes:
+ *   - Only version 2 devices are supported.
+ *   - Version 2 devices only support SDIO cards/devices (R2 response is
+ *     unsupported).
+ *
+ * References:
+ *   [USHC] USB SD Host Controller specification (CS-118793-SP)
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+
+enum ushc_request {
+	USHC_GET_CAPS  = 0x00,
+	USHC_HOST_CTRL = 0x01,
+	USHC_PWR_CTRL  = 0x02,
+	USHC_CLK_FREQ  = 0x03,
+	USHC_EXEC_CMD  = 0x04,
+	USHC_READ_RESP = 0x05,
+	USHC_RESET     = 0x06,
+};
+
+enum ushc_request_type {
+	USHC_GET_CAPS_TYPE  = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_PWR_CTRL_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_CLK_FREQ_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_EXEC_CMD_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_READ_RESP_TYPE = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	USHC_RESET_TYPE     = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+};
+
+#define USHC_GET_CAPS_VERSION_MASK 0xff
+#define USHC_GET_CAPS_3V3      (1 << 8)
+#define USHC_GET_CAPS_3V0      (1 << 9)
+#define USHC_GET_CAPS_1V8      (1 << 10)
+#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
+
+#define USHC_HOST_CTRL_4BIT     (1 << 1)
+#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
+
+#define USHC_PWR_CTRL_OFF 0x00
+#define USHC_PWR_CTRL_3V3 0x01
+#define USHC_PWR_CTRL_3V0 0x02
+#define USHC_PWR_CTRL_1V8 0x03
+
+#define USHC_READ_RESP_BUSY        (1 << 4)
+#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
+#define USHC_READ_RESP_ERR_CRC     (1 << 2)
+#define USHC_READ_RESP_ERR_DAT     (1 << 1)
+#define USHC_READ_RESP_ERR_CMD     (1 << 0)
+#define USHC_READ_RESP_ERR_MASK    0x0f
+
+struct ushc_cbw {
+	__u8 signature;
+	__u8 cmd_idx;
+	__le16 block_size;
+	__le32 arg;
+} __attribute__((packed));
+
+#define USHC_CBW_SIGNATURE 'C'
+
+struct ushc_csw {
+	__u8 signature;
+	__u8 status;
+	__le32 response;
+} __attribute__((packed));
+
+#define USHC_CSW_SIGNATURE 'S'
+
+struct ushc_int_data {
+	u8 status;
+	u8 reserved[3];
+};
+
+#define USHC_INT_STATUS_SDIO_INT     (1 << 1)
+#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
+
+
+struct ushc_data {
+	struct usb_device *usb_dev;
+	struct mmc_host *mmc;
+
+	struct urb *int_urb;
+	struct ushc_int_data *int_data;
+
+	struct urb *cbw_urb;
+	struct ushc_cbw *cbw;
+
+	struct urb *data_urb;
+
+	struct urb *csw_urb;
+	struct ushc_csw *csw;
+
+	spinlock_t lock;
+	struct mmc_request *current_req;
+	u32 caps;
+	u16 host_ctrl;
+	unsigned long flags;
+	u8 last_status;
+	int clock_freq;
+};
+
+#define DISCONNECTED    0
+#define INT_EN          1
+#define IGNORE_NEXT_INT 2
+
+static void data_callback(struct urb *urb);
+
+static int ushc_hw_reset(struct ushc_data *ushc)
+{
+	return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+			       USHC_RESET, USHC_RESET_TYPE,
+			       0, 0, NULL, 0, 100);
+}
+
+static int ushc_hw_get_caps(struct ushc_data *ushc)
+{
+	int ret;
+	int version;
+
+	ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0),
+			      USHC_GET_CAPS, USHC_GET_CAPS_TYPE,
+			      0, 0, &ushc->caps, sizeof(ushc->caps), 100);
+	if (ret < 0)
+		return ret;
+
+	ushc->caps = le32_to_cpu(ushc->caps);
+
+	version = ushc->caps & USHC_GET_CAPS_VERSION_MASK;
+	if (version != 0x02) {
+		dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val)
+{
+	u16 host_ctrl;
+	int ret;
+
+	host_ctrl = (ushc->host_ctrl & ~mask) | val;
+	ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+			      USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE,
+			      host_ctrl, 0, NULL, 0, 100);
+	if (ret < 0)
+		return ret;
+	ushc->host_ctrl = host_ctrl;
+	return 0;
+}
+
+static void int_callback(struct urb *urb)
+{
+	struct ushc_data *ushc = urb->context;
+	u8 status, last_status;
+
+	if (urb->status < 0)
+		return;
+
+	status = ushc->int_data->status;
+	last_status = ushc->last_status;
+	ushc->last_status = status;
+
+	/*
+	 * Ignore the card interrupt status on interrupt transfers that
+	 * were submitted while card interrupts where disabled.
+	 *
+	 * This avoid occasional spurious interrupts when enabling
+	 * interrupts immediately after clearing the source on the card.
+	 */
+
+	if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags)
+	    && test_bit(INT_EN, &ushc->flags)
+	    && status & USHC_INT_STATUS_SDIO_INT) {
+		mmc_signal_sdio_irq(ushc->mmc);
+	}
+
+	if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT)
+		mmc_detect_change(ushc->mmc, msecs_to_jiffies(100));
+
+	if (!test_bit(INT_EN, &ushc->flags))
+		set_bit(IGNORE_NEXT_INT, &ushc->flags);
+	usb_submit_urb(ushc->int_urb, GFP_ATOMIC);
+}
+
+static void cbw_callback(struct urb *urb)
+{
+	struct ushc_data *ushc = urb->context;
+
+	if (urb->status != 0) {
+		usb_unlink_urb(ushc->data_urb);
+		usb_unlink_urb(ushc->csw_urb);
+	}
+}
+
+static void data_callback(struct urb *urb)
+{
+	struct ushc_data *ushc = urb->context;
+
+	if (urb->status != 0)
+		usb_unlink_urb(ushc->csw_urb);
+}
+
+static void csw_callback(struct urb *urb)
+{
+	struct ushc_data *ushc = urb->context;
+	struct mmc_request *req = ushc->current_req;
+	int status;
+
+	status = ushc->csw->status;
+
+	if (urb->status != 0) {
+		req->cmd->error = urb->status;
+	} else if (status & USHC_READ_RESP_ERR_CMD) {
+		if (status & USHC_READ_RESP_ERR_CRC)
+			req->cmd->error = -EIO;
+		else
+			req->cmd->error = -ETIMEDOUT;
+	}
+	if (req->data) {
+		if (status & USHC_READ_RESP_ERR_DAT) {
+			if (status & USHC_READ_RESP_ERR_CRC)
+				req->data->error = -EIO;
+			else
+				req->data->error = -ETIMEDOUT;
+			req->data->bytes_xfered = 0;
+		} else {
+			req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+		}
+	}
+
+	req->cmd->resp[0] = le32_to_cpu(ushc->csw->response);
+
+	mmc_request_done(ushc->mmc, req);
+}
+
+static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+	struct ushc_data *ushc = mmc_priv(mmc);
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ushc->lock, flags);
+
+	if (test_bit(DISCONNECTED, &ushc->flags)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* Version 2 firmware doesn't support the R2 response format. */
+	if (req->cmd->flags & MMC_RSP_136) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* The Astoria's data FIFOs don't work with clock speeds < 5MHz so
+	   limit commands with data to 6MHz or more. */
+	if (req->data && ushc->clock_freq < 6000000) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ushc->current_req = req;
+
+	/* Start cmd with CBW. */
+	ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode);
+	if (req->data)
+		ushc->cbw->block_size = cpu_to_le16(req->data->blksz);
+	else
+		ushc->cbw->block_size = 0;
+	ushc->cbw->arg = cpu_to_le32(req->cmd->arg);
+
+	ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC);
+	if (ret < 0)
+		goto out;
+
+	/* Submit data (if any). */
+	if (req->data) {
+		struct mmc_data *data = req->data;
+		int pipe;
+
+		if (data->flags & MMC_DATA_READ)
+			pipe = usb_rcvbulkpipe(ushc->usb_dev, 6);
+		else
+			pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
+
+		usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
+				  sg_virt(data->sg), data->sg->length,
+				  data_callback, ushc);
+		ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
+		if (ret < 0)
+			goto out;
+	}
+
+	/* Submit CSW. */
+	ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC);
+	if (ret < 0)
+		goto out;
+
+out:
+	spin_unlock_irqrestore(&ushc->lock, flags);
+	if (ret < 0) {
+		usb_unlink_urb(ushc->cbw_urb);
+		usb_unlink_urb(ushc->data_urb);
+		req->cmd->error = ret;
+		mmc_request_done(mmc, req);
+	}
+}
+
+static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode)
+{
+	u16 voltage;
+
+	switch (power_mode) {
+	case MMC_POWER_OFF:
+		voltage = USHC_PWR_CTRL_OFF;
+		break;
+	case MMC_POWER_UP:
+	case MMC_POWER_ON:
+		voltage = USHC_PWR_CTRL_3V3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+			       USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE,
+			       voltage, 0, NULL, 0, 100);
+}
+
+static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width)
+{
+	return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT,
+				     bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0);
+}
+
+static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs)
+{
+	int ret;
+
+	/* Hardware can't detect interrupts while the clock is off. */
+	if (clk == 0)
+		clk = 400000;
+
+	ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD,
+				    enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+			      USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE,
+			      clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100);
+	if (ret < 0)
+		return ret;
+
+	ushc->clock_freq = clk;
+	return 0;
+}
+
+static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct ushc_data *ushc = mmc_priv(mmc);
+
+	ushc_set_power(ushc, ios->power_mode);
+	ushc_set_bus_width(ushc, 1 << ios->bus_width);
+	ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS);
+}
+
+static int ushc_get_cd(struct mmc_host *mmc)
+{
+	struct ushc_data *ushc = mmc_priv(mmc);
+
+	return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT);
+}
+
+static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct ushc_data *ushc = mmc_priv(mmc);
+
+	if (enable)
+		set_bit(INT_EN, &ushc->flags);
+	else
+		clear_bit(INT_EN, &ushc->flags);
+}
+
+static void ushc_clean_up(struct ushc_data *ushc)
+{
+	usb_free_urb(ushc->int_urb);
+	usb_free_urb(ushc->csw_urb);
+	usb_free_urb(ushc->data_urb);
+	usb_free_urb(ushc->cbw_urb);
+
+	kfree(ushc->int_data);
+	kfree(ushc->cbw);
+	kfree(ushc->csw);
+
+	mmc_free_host(ushc->mmc);
+}
+
+static const struct mmc_host_ops ushc_ops = {
+	.request         = ushc_request,
+	.set_ios         = ushc_set_ios,
+	.get_cd          = ushc_get_cd,
+	.enable_sdio_irq = ushc_enable_sdio_irq,
+};
+
+static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct mmc_host *mmc;
+	struct ushc_data *ushc;
+	int ret = -ENOMEM;
+
+	mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
+	if (mmc == NULL)
+		return -ENOMEM;
+	ushc = mmc_priv(mmc);
+	usb_set_intfdata(intf, ushc);
+
+	ushc->usb_dev = usb_dev;
+	ushc->mmc = mmc;
+
+	spin_lock_init(&ushc->lock);
+
+	ret = ushc_hw_reset(ushc);
+	if (ret < 0)
+		goto err;
+
+	/* Read capabilities. */
+	ret = ushc_hw_get_caps(ushc);
+	if (ret < 0)
+		goto err;
+
+	mmc->ops = &ushc_ops;
+
+	mmc->f_min = 400000;
+	mmc->f_max = 50000000;
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+	mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0;
+
+	mmc->max_seg_size  = 512*511;
+	mmc->max_segs      = 1;
+	mmc->max_req_size  = 512*511;
+	mmc->max_blk_size  = 512;
+	mmc->max_blk_count = 511;
+
+	ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (ushc->int_urb == NULL)
+		goto err;
+	ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
+	if (ushc->int_data == NULL)
+		goto err;
+	usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
+			 usb_rcvintpipe(usb_dev,
+					intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
+			 ushc->int_data, sizeof(struct ushc_int_data),
+			 int_callback, ushc,
+			 intf->cur_altsetting->endpoint[0].desc.bInterval);
+
+	ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (ushc->cbw_urb == NULL)
+		goto err;
+	ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+	if (ushc->cbw == NULL)
+		goto err;
+	ushc->cbw->signature = USHC_CBW_SIGNATURE;
+
+	usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
+			  ushc->cbw, sizeof(struct ushc_cbw),
+			  cbw_callback, ushc);
+
+	ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (ushc->data_urb == NULL)
+		goto err;
+
+	ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (ushc->csw_urb == NULL)
+		goto err;
+	ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+	if (ushc->csw == NULL)
+		goto err;
+	usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
+			  ushc->csw, sizeof(struct ushc_csw),
+			  csw_callback, ushc);
+
+	ret = mmc_add_host(ushc->mmc);
+	if (ret)
+		goto err;
+
+	ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL);
+	if (ret < 0) {
+		mmc_remove_host(ushc->mmc);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	ushc_clean_up(ushc);
+	return ret;
+}
+
+static void ushc_disconnect(struct usb_interface *intf)
+{
+	struct ushc_data *ushc = usb_get_intfdata(intf);
+
+	spin_lock_irq(&ushc->lock);
+	set_bit(DISCONNECTED, &ushc->flags);
+	spin_unlock_irq(&ushc->lock);
+
+	usb_kill_urb(ushc->int_urb);
+	usb_kill_urb(ushc->cbw_urb);
+	usb_kill_urb(ushc->data_urb);
+	usb_kill_urb(ushc->csw_urb);
+
+	mmc_remove_host(ushc->mmc);
+
+	ushc_clean_up(ushc);
+}
+
+static struct usb_device_id ushc_id_table[] = {
+	/* CSR USB SD Host Controller */
+	{ USB_DEVICE(0x0a12, 0x5d10) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, ushc_id_table);
+
+static struct usb_driver ushc_driver = {
+	.name       = "ushc",
+	.id_table   = ushc_id_table,
+	.probe      = ushc_probe,
+	.disconnect = ushc_disconnect,
+};
+
+static int __init ushc_init(void)
+{
+	return usb_register(&ushc_driver);
+}
+module_init(ushc_init);
+
+static void __exit ushc_exit(void)
+{
+	usb_deregister(&ushc_driver);
+}
+module_exit(ushc_exit);
+
+MODULE_DESCRIPTION("USB SD Host Controller driver");
+MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
+MODULE_LICENSE("GPL");

+ 1 - 2
drivers/mmc/host/via-sdmmc.c

@@ -1050,8 +1050,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host)
 	mmc->ops = &via_sdc_ops;
 	mmc->ops = &via_sdc_ops;
 
 
 	/*Hardware cannot do scatter lists*/
 	/*Hardware cannot do scatter lists*/
-	mmc->max_hw_segs = 1;
-	mmc->max_phys_segs = 1;
+	mmc->max_segs = 1;
 
 
 	mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
 	mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
 	mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
 	mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;

+ 1 - 2
drivers/mmc/host/wbsd.c

@@ -1235,8 +1235,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
 	 * Maximum number of segments. Worst case is one sector per segment
 	 * Maximum number of segments. Worst case is one sector per segment
 	 * so this will be 64kB/512.
 	 * so this will be 64kB/512.
 	 */
 	 */
-	mmc->max_hw_segs = 128;
-	mmc->max_phys_segs = 128;
+	mmc->max_segs = 128;
 
 
 	/*
 	/*
 	 * Maximum request size. Also limited by 64KiB buffer.
 	 * Maximum request size. Also limited by 64KiB buffer.

+ 6 - 0
include/linux/mmc/card.h

@@ -48,6 +48,7 @@ struct mmc_ext_csd {
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
 	unsigned int		sectors;
+	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_size;		/* In sectors */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		hc_erase_timeout;	/* In milliseconds */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
@@ -113,6 +114,7 @@ struct mmc_card {
 #define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
 #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_HIGHSPEED	(1<<2)		/* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
 #define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
+#define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
 	unsigned int		quirks; 	/* card quirks */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -154,11 +156,13 @@ struct mmc_card {
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 
 
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 {
 {
@@ -173,6 +177,8 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		(dev_name(&(c)->dev))
 #define mmc_card_id(c)		(dev_name(&(c)->dev))
 
 
+#define mmc_dev_to_card(d)	container_of(d, struct mmc_card, dev)
+
 #define mmc_list_to_card(l)	container_of(l, struct mmc_card, node)
 #define mmc_list_to_card(l)	container_of(l, struct mmc_card, node)
 #define mmc_get_drvdata(c)	dev_get_drvdata(&(c)->dev)
 #define mmc_get_drvdata(c)	dev_get_drvdata(&(c)->dev)
 #define mmc_set_drvdata(c,d)	dev_set_drvdata(&(c)->dev, d)
 #define mmc_set_drvdata(c,d)	dev_set_drvdata(&(c)->dev, d)

+ 2 - 0
include/linux/mmc/core.h

@@ -153,6 +153,8 @@ extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
 				   unsigned int nr);
 
 
+extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 
 

+ 43 - 5
include/linux/mmc/host.h

@@ -50,6 +50,12 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY	0
 #define MMC_TIMING_LEGACY	0
 #define MMC_TIMING_MMC_HS	1
 #define MMC_TIMING_MMC_HS	1
 #define MMC_TIMING_SD_HS	2
 #define MMC_TIMING_SD_HS	2
+
+	unsigned char	ddr;			/* dual data rate used */
+
+#define MMC_SDR_MODE		0
+#define MMC_1_2V_DDR_MODE	1
+#define MMC_1_8V_DDR_MODE	2
 };
 };
 
 
 struct mmc_host_ops {
 struct mmc_host_ops {
@@ -123,6 +129,7 @@ struct mmc_host {
 	const struct mmc_host_ops *ops;
 	const struct mmc_host_ops *ops;
 	unsigned int		f_min;
 	unsigned int		f_min;
 	unsigned int		f_max;
 	unsigned int		f_max;
+	unsigned int		f_init;
 	u32			ocr_avail;
 	u32			ocr_avail;
 	struct notifier_block	pm_notify;
 	struct notifier_block	pm_notify;
 
 
@@ -157,13 +164,16 @@ struct mmc_host {
 #define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
 #define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
 #define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
 #define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
 #define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
+#define MMC_CAP_1_8V_DDR	(1 << 11)	/* can support */
+						/* DDR mode at 1.8V */
+#define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
+						/* DDR mode at 1.2V */
 
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 
 	/* host specific block data */
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
-	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
-	unsigned short		max_phys_segs;	/* see blk_queue_max_phys_segments */
+	unsigned short		max_segs;	/* see blk_queue_max_segments */
 	unsigned short		unused;
 	unsigned short		unused;
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
@@ -212,6 +222,10 @@ struct mmc_host {
 	struct led_trigger	*led;		/* activity led */
 	struct led_trigger	*led;		/* activity led */
 #endif
 #endif
 
 
+#ifdef CONFIG_REGULATOR
+	bool			regulator_enabled; /* regulator state */
+#endif
+
 	struct dentry		*debugfs_root;
 	struct dentry		*debugfs_root;
 
 
 	unsigned long		private[0] ____cacheline_aligned;
 	unsigned long		private[0] ____cacheline_aligned;
@@ -236,8 +250,8 @@ static inline void *mmc_priv(struct mmc_host *host)
 extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_resume_host(struct mmc_host *);
 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 int mmc_power_save_host(struct mmc_host *host);
+extern int mmc_power_restore_host(struct mmc_host *host);
 
 
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
@@ -250,8 +264,24 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 
 
 struct regulator;
 struct regulator;
 
 
+#ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
 int mmc_regulator_get_ocrmask(struct regulator *supply);
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+			struct regulator *supply,
+			unsigned short vdd_bit);
+#else
+static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+	return 0;
+}
+
+static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
+				 struct regulator *supply,
+				 unsigned short vdd_bit)
+{
+	return 0;
+}
+#endif
 
 
 int mmc_card_awake(struct mmc_host *host);
 int mmc_card_awake(struct mmc_host *host);
 int mmc_card_sleep(struct mmc_host *host);
 int mmc_card_sleep(struct mmc_host *host);
@@ -268,5 +298,13 @@ static inline void mmc_set_disable_delay(struct mmc_host *host,
 	host->disable_delay = disable_delay;
 	host->disable_delay = disable_delay;
 }
 }
 
 
+/* Module parameter */
+extern int mmc_assume_removable;
+
+static inline int mmc_card_is_removable(struct mmc_host *host)
+{
+	return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
+}
+
 #endif
 #endif
 
 

+ 9 - 1
include/linux/mmc/mmc.h

@@ -277,11 +277,19 @@ struct _mmc_csd {
 
 
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK	0x3	/* Mask out reserved and DDR bits */
+#define EXT_CSD_CARD_TYPE_MASK	0xF	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
+					     /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
+					     /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
+					| EXT_CSD_CARD_TYPE_DDR_1_2V)
 
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
+#define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
+#define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
 
 
 #define EXT_CSD_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)

+ 1 - 1
include/linux/sdhci-pltfm.h → include/linux/mmc/sdhci-pltfm.h

@@ -28,7 +28,7 @@ struct sdhci_host;
 struct sdhci_pltfm_data {
 struct sdhci_pltfm_data {
 	struct sdhci_ops *ops;
 	struct sdhci_ops *ops;
 	unsigned int quirks;
 	unsigned int quirks;
-	int (*init)(struct sdhci_host *host);
+	int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
 	void (*exit)(struct sdhci_host *host);
 	void (*exit)(struct sdhci_host *host);
 };
 };
 
 

+ 144 - 0
include/linux/mmc/sdhci.h

@@ -0,0 +1,144 @@
+/*
+ *  linux/include/linux/mmc/sdhci.h - Secure Digital Host Controller Interface
+ *
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+
+struct sdhci_host {
+	/* Data set by hardware interface driver */
+	const char *hw_name;	/* Hardware bus name */
+
+	unsigned int quirks;	/* Deviations from spec. */
+
+/* Controller doesn't honor resets unless we touch the clock register */
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
+/* Controller has bad caps bits, but really supports DMA */
+#define SDHCI_QUIRK_FORCE_DMA				(1<<1)
+/* Controller doesn't like to be reset when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
+/* Controller doesn't like clearing the power reg before a change */
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
+/* Controller has an unusable DMA engine */
+#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
+/* Controller has an unusable ADMA engine */
+#define SDHCI_QUIRK_BROKEN_ADMA				(1<<6)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<7)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<8)
+/* Controller can only ADMA chunks that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_ADMA_SIZE			(1<<9)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<10)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<11)
+/* Controller provides an incorrect timeout value for transfers */
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<12)
+/* Controller has an issue with buffer bits for small transfers */
+#define SDHCI_QUIRK_BROKEN_SMALL_PIO			(1<<13)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_BUSY_IRQ				(1<<14)
+/* Controller has unreliable card detection */
+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15)
+/* Controller reports inverted write-protect state */
+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16)
+/* Controller has nonstandard clock management */
+#define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<17)
+/* Controller does not like fast PIO transfers */
+#define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)
+/* Controller losing signal/interrupt enable states after reset */
+#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET		(1<<19)
+/* Controller has to be forced to use block size of 2048 bytes */
+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048			(1<<20)
+/* Controller cannot do multi-block transfers */
+#define SDHCI_QUIRK_NO_MULTIBLOCK			(1<<21)
+/* Controller can only handle 1-bit data transfers */
+#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 reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN		(1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC		(1<<26)
+/* Controller is missing device caps. Use caps provided by host */
+#define SDHCI_QUIRK_MISSING_CAPS			(1<<27)
+/* Controller uses Auto CMD12 command to stop the transfer */
+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12		(1<<28)
+/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
+#define SDHCI_QUIRK_NO_HISPD_BIT			(1<<29)
+
+	int irq;		/* Device IRQ */
+	void __iomem *ioaddr;	/* Mapped address */
+
+	const struct sdhci_ops *ops;	/* Low level hw interface */
+
+	struct regulator *vmmc;	/* Power regulator */
+
+	/* Internal data */
+	struct mmc_host *mmc;	/* MMC structure */
+	u64 dma_mask;		/* custom DMA mask */
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+	struct led_classdev led;	/* LED control */
+	char led_name[32];
+#endif
+
+	spinlock_t lock;	/* Mutex */
+
+	int flags;		/* Host attributes */
+#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 */
+
+	unsigned int version;	/* SDHCI spec. version */
+
+	unsigned int max_clk;	/* Max possible freq (MHz) */
+	unsigned int timeout_clk;	/* Timeout freq (KHz) */
+
+	unsigned int clock;	/* Current clock (MHz) */
+	u8 pwr;			/* Current voltage */
+
+	struct mmc_request *mrq;	/* Current request */
+	struct mmc_command *cmd;	/* Current command */
+	struct mmc_data *data;	/* Current data request */
+	unsigned int data_early:1;	/* Data finished before cmd */
+
+	struct sg_mapping_iter sg_miter;	/* SG state for PIO */
+	unsigned int blocks;	/* remaining PIO blocks */
+
+	int sg_count;		/* Mapped sg entries */
+
+	u8 *adma_desc;		/* ADMA descriptor table */
+	u8 *align_buffer;	/* Bounce buffer */
+
+	dma_addr_t adma_addr;	/* Mapped ADMA descr. table */
+	dma_addr_t align_addr;	/* Mapped bounce buffer */
+
+	struct tasklet_struct card_tasklet;	/* Tasklet structures */
+	struct tasklet_struct finish_tasklet;
+
+	struct timer_list timer;	/* Timer for timeouts */
+
+	unsigned int caps;	/* Alternative capabilities */
+
+	unsigned long private[0] ____cacheline_aligned;
+};
+#endif /* __SDHCI_H */

+ 7 - 0
include/linux/pci_ids.h

@@ -2430,6 +2430,13 @@
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
+#define PCI_DEVICE_ID_INTEL_MRST_SD0	0x0807
+#define PCI_DEVICE_ID_INTEL_MRST_SD1	0x0808
+#define PCI_DEVICE_ID_INTEL_MFD_SD	0x0820
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO1	0x0821
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO2	0x0822
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC0	0x0823
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC1	0x0824
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_8257X_SOL	0x1062
 #define PCI_DEVICE_ID_INTEL_8257X_SOL	0x1062