summary refs log tree commit diff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2006-12-24 22:46:55 +0100
committerPierre Ossman <drzeus@drzeus.cx>2007-05-01 13:04:18 +0200
commitda7fbe58d2d347e95af699ddf04d885be6362bbe (patch)
tree560df47c41bb64ace46f82f9fa5e2fabc8bafbab /drivers/mmc/core
parentaaac1b470bd0dccb30912356617069dc6199cc80 (diff)
downloadlinux-da7fbe58d2d347e95af699ddf04d885be6362bbe.tar.gz
mmc: Separate out protocol ops
Move protocol operations and definitions into their own files
in an effort to separate protocol handling and bus
arbitration more clearly.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/Makefile2
-rw-r--r--drivers/mmc/core/core.c511
-rw-r--r--drivers/mmc/core/core.h32
-rw-r--r--drivers/mmc/core/mmc_ops.c276
-rw-r--r--drivers/mmc/core/mmc_ops.h27
-rw-r--r--drivers/mmc/core/sd_ops.c316
-rw-r--r--drivers/mmc/core/sd_ops.h25
-rw-r--r--drivers/mmc/core/sysfs.c2
-rw-r--r--drivers/mmc/core/sysfs.h27
9 files changed, 756 insertions, 462 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index f911fbd2845b..5977abf3e41b 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -7,5 +7,5 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
 endif
 
 obj-$(CONFIG_MMC)		+= mmc_core.o
-mmc_core-y			:= core.o sysfs.o
+mmc_core-y			:= core.o sysfs.o mmc_ops.o sd_ops.o
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 334e663e465b..310be2fe1944 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -23,9 +23,14 @@
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
 
 #include "core.h"
+#include "sysfs.h"
+
+#include "mmc_ops.h"
+#include "sd_ops.h"
 
 #define CMD_RETRIES	3
 
@@ -191,80 +196,6 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
 /**
- *	mmc_wait_for_app_cmd - start an application command and wait for
- 			       completion
- *	@host: MMC host to start command
- *	@rca: RCA to send MMC_APP_CMD to
- *	@cmd: MMC command to start
- *	@retries: maximum number of retries
- *
- *	Sends a MMC_APP_CMD, checks the card response, sends the command
- *	in the parameter and waits for it to complete. Return any error
- *	that occurred while the command was executing.  Do not attempt to
- *	parse the response.
- */
-int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
-	struct mmc_command *cmd, int retries)
-{
-	struct mmc_request mrq;
-	struct mmc_command appcmd;
-
-	int i, err;
-
-	BUG_ON(!host->claimed);
-	BUG_ON(retries < 0);
-
-	err = MMC_ERR_INVALID;
-
-	/*
-	 * We have to resend MMC_APP_CMD for each attempt so
-	 * we cannot use the retries field in mmc_command.
-	 */
-	for (i = 0;i <= retries;i++) {
-		memset(&mrq, 0, sizeof(struct mmc_request));
-
-		appcmd.opcode = MMC_APP_CMD;
-		appcmd.arg = rca << 16;
-		appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-		appcmd.retries = 0;
-		memset(appcmd.resp, 0, sizeof(appcmd.resp));
-		appcmd.data = NULL;
-
-		mrq.cmd = &appcmd;
-		appcmd.data = NULL;
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (appcmd.error) {
-			err = appcmd.error;
-			continue;
-		}
-
-		/* Check that card supported application commands */
-		if (!(appcmd.resp[0] & R1_APP_CMD))
-			return MMC_ERR_FAILED;
-
-		memset(&mrq, 0, sizeof(struct mmc_request));
-
-		memset(cmd->resp, 0, sizeof(cmd->resp));
-		cmd->retries = 0;
-
-		mrq.cmd = cmd;
-		cmd->data = NULL;
-
-		mmc_wait_for_req(host, &mrq);
-
-		err = cmd->error;
-		if (cmd->error == MMC_ERR_NONE)
-			break;
-	}
-
-	return err;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-
-/**
  *	mmc_set_data_timeout - set the timeout for a data command
  *	@data: data phase for command
  *	@card: the MMC card associated with the data transfer
@@ -385,60 +316,10 @@ static inline void mmc_set_ios(struct mmc_host *host)
 	host->ops->set_ios(host, ios);
 }
 
-static int mmc_select_card(struct mmc_card *card)
-{
-	int err;
-	struct mmc_command cmd;
-
-	BUG_ON(!card->host->claimed);
-
-	cmd.opcode = MMC_SELECT_CARD;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-	err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
-		return err;
-
-	/*
-	 * We can only change the bus width of SD cards when
-	 * they are selected so we have to put the handling
-	 * here.
-	 *
-	 * The card is in 1 bit mode by default so
-	 * we only need to change if it supports the
-	 * wider version.
-	 */
-	if (mmc_card_sd(card) &&
-		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) &&
-		(card->host->caps & MMC_CAP_4_BIT_DATA)) {
-
-		struct mmc_command cmd;
-		cmd.opcode = SD_APP_SET_BUS_WIDTH;
-		cmd.arg = SD_BUS_WIDTH_4;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-		err = mmc_wait_for_app_cmd(card->host, card->rca,
-			&cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
-			return err;
-
-		card->host->ios.bus_width = MMC_BUS_WIDTH_4;
-		mmc_set_ios(card->host);
-	}
-
-	return MMC_ERR_NONE;
-}
-
-
-static inline void mmc_delay(unsigned int ms)
+void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
-	if (ms < 1000 / HZ) {
-		cond_resched();
-		mdelay(ms);
-	} else {
-		msleep(ms);
-	}
+	host->ios.chip_select = mode;
+	mmc_set_ios(host);
 }
 
 /*
@@ -709,32 +590,6 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid)
 }
 
 /*
- * Tell attached cards to go to IDLE state
- */
-static void mmc_idle_cards(struct mmc_host *host)
-{
-	struct mmc_command cmd;
-
-	host->ios.chip_select = MMC_CS_HIGH;
-	mmc_set_ios(host);
-
-	mmc_delay(1);
-
-	cmd.opcode = MMC_GO_IDLE_STATE;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
-
-	mmc_wait_for_cmd(host, &cmd, 0);
-
-	mmc_delay(1);
-
-	host->ios.chip_select = MMC_CS_DONTCARE;
-	mmc_set_ios(host);
-
-	mmc_delay(1);
-}
-
-/*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
  * We then wait a bit for the power to stabilise.  Finally,
@@ -778,97 +633,6 @@ static void mmc_power_off(struct mmc_host *host)
 	mmc_set_ios(host);
 }
 
-static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
-	struct mmc_command cmd;
-	int i, err = 0;
-
-	cmd.opcode = MMC_SEND_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
-	for (i = 100; i; i--) {
-		err = mmc_wait_for_cmd(host, &cmd, 0);
-		if (err != MMC_ERR_NONE)
-			break;
-
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
-			break;
-
-		err = MMC_ERR_TIMEOUT;
-
-		mmc_delay(10);
-	}
-
-	if (rocr)
-		*rocr = cmd.resp[0];
-
-	return err;
-}
-
-static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
-	struct mmc_command cmd;
-	int i, err = 0;
-
-	cmd.opcode = SD_APP_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
-	for (i = 100; i; i--) {
-		err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
-			break;
-
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
-			break;
-
-		err = MMC_ERR_TIMEOUT;
-
-		mmc_delay(10);
-	}
-
-	if (rocr)
-		*rocr = cmd.resp[0];
-
-	return err;
-}
-
-static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
-{
-	struct mmc_command cmd;
-	int err, sd2;
-	static const u8 test_pattern = 0xAA;
-
-	/*
-	* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
-	* before SD_APP_OP_COND. This command will harmlessly fail for
-	* SD 1.0 cards.
-	*/
-	cmd.opcode = SD_SEND_IF_COND;
-	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
-	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
-
-	err = mmc_wait_for_cmd(host, &cmd, 0);
-	if (err == MMC_ERR_NONE) {
-		if ((cmd.resp[0] & 0xFF) == test_pattern) {
-			sd2 = 1;
-		} else {
-			sd2 = 0;
-			err = MMC_ERR_FAILED;
-		}
-	} else {
-		/*
-		 * Treat errors as SD 1.0 card.
-		 */
-		sd2 = 0;
-		err = MMC_ERR_NONE;
-	}
-	if (rsd2)
-		*rsd2 = sd2;
-	return err;
-}
-
 /*
  * Discover the card by requesting its CID.
  *
@@ -878,27 +642,18 @@ static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
 static void mmc_discover_card(struct mmc_host *host)
 {
 	unsigned int err;
-
-	struct mmc_command cmd;
+	u32 cid[4];
 
 	BUG_ON(host->card);
 
-	cmd.opcode = MMC_ALL_SEND_CID;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
-
-	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-	if (err == MMC_ERR_TIMEOUT) {
-		err = MMC_ERR_NONE;
-		return;
-	}
+	err = mmc_all_send_cid(host, cid);
 	if (err != MMC_ERR_NONE) {
 		printk(KERN_ERR "%s: error requesting CID: %d\n",
 			mmc_hostname(host), err);
 		return;
 	}
 
-	host->card = mmc_alloc_card(host, cmd.resp);
+	host->card = mmc_alloc_card(host, cid);
 	if (IS_ERR(host->card)) {
 		err = PTR_ERR(host->card);
 		host->card = NULL;
@@ -908,16 +663,10 @@ static void mmc_discover_card(struct mmc_host *host)
 	if (host->mode == MMC_MODE_SD) {
 		host->card->type = MMC_TYPE_SD;
 
-		cmd.opcode = SD_SEND_RELATIVE_ADDR;
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+		err = mmc_send_relative_addr(host, &host->card->rca);
 		if (err != MMC_ERR_NONE)
 			mmc_card_set_dead(host->card);
 		else {
-			host->card->rca = cmd.resp[0] >> 16;
-
 			if (!host->ops->get_ro) {
 				printk(KERN_WARNING "%s: host does not "
 					"support reading read-only "
@@ -932,11 +681,7 @@ static void mmc_discover_card(struct mmc_host *host)
 		host->card->type = MMC_TYPE_MMC;
 		host->card->rca = 1;
 
-		cmd.opcode = MMC_SET_RELATIVE_ADDR;
-		cmd.arg = host->card->rca << 16;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+		err = mmc_set_relative_addr(host->card);
 		if (err != MMC_ERR_NONE)
 			mmc_card_set_dead(host->card);
 	}
@@ -944,7 +689,6 @@ static void mmc_discover_card(struct mmc_host *host)
 
 static void mmc_read_csd(struct mmc_host *host)
 {
-	struct mmc_command cmd;
 	int err;
 
 	if (!host->card)
@@ -952,18 +696,12 @@ static void mmc_read_csd(struct mmc_host *host)
 	if (mmc_card_dead(host->card))
 		return;
 
-	cmd.opcode = MMC_SEND_CSD;
-	cmd.arg = host->card->rca << 16;
-	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
-
-	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+	err = mmc_send_csd(host->card, host->card->raw_csd);
 	if (err != MMC_ERR_NONE) {
 		mmc_card_set_dead(host->card);
 		return;
 	}
 
-	memcpy(host->card->raw_csd, cmd.resp, sizeof(host->card->raw_csd));
-
 	mmc_decode_csd(host->card);
 	mmc_decode_cid(host->card);
 }
@@ -971,13 +709,7 @@ static void mmc_read_csd(struct mmc_host *host)
 static void mmc_process_ext_csd(struct mmc_host *host)
 {
 	int err;
-
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-
 	u8 *ext_csd;
-	struct scatterlist sg;
 
 	if (!host->card)
 		return;
@@ -1000,32 +732,8 @@ static void mmc_process_ext_csd(struct mmc_host *host)
 		return;
 	}
 
-	memset(&cmd, 0, sizeof(struct mmc_command));
-
-	cmd.opcode = MMC_SEND_EXT_CSD;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	memset(&data, 0, sizeof(struct mmc_data));
-
-	mmc_set_data_timeout(&data, host->card, 0);
-
-	data.blksz = 512;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	sg_init_one(&sg, ext_csd, 512);
-
-	mmc_wait_for_req(host, &mrq);
-
-	if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+	err = mmc_send_ext_csd(host->card, ext_csd);
+	if (err != MMC_ERR_NONE) {
 		if (host->card->csd.capacity == (4096 * 512)) {
 			printk(KERN_ERR "%s: unable to read EXT_CSD "
 				"on a possible high capacity card. "
@@ -1066,14 +774,8 @@ static void mmc_process_ext_csd(struct mmc_host *host)
 
 	if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
 		/* Activate highspeed support. */
-		cmd.opcode = MMC_SWITCH;
-		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-			  (EXT_CSD_HS_TIMING << 16) |
-			  (1 << 8) |
-			  EXT_CSD_CMD_SET_NORMAL;
-		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+		err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE,
+			EXT_CSD_HS_TIMING, 1);
 		if (err != MMC_ERR_NONE) {
 			printk("%s: failed to switch card to mmc v4 "
 			       "high-speed mode.\n",
@@ -1090,14 +792,9 @@ static void mmc_process_ext_csd(struct mmc_host *host)
 	/* Check for host support for wide-bus modes. */
 	if (host->caps & MMC_CAP_4_BIT_DATA) {
 		/* Activate 4-bit support. */
-		cmd.opcode = MMC_SWITCH;
-		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-			  (EXT_CSD_BUS_WIDTH << 16) |
-			  (EXT_CSD_BUS_WIDTH_4 << 8) |
-			  EXT_CSD_CMD_SET_NORMAL;
-		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+		err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE,
+			EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4 |
+			EXT_CSD_CMD_SET_NORMAL);
 		if (err != MMC_ERR_NONE) {
 			printk("%s: failed to switch card to "
 			       "mmc v4 4-bit bus mode.\n",
@@ -1116,10 +813,6 @@ out:
 static void mmc_read_scr(struct mmc_host *host)
 {
 	int err;
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-	struct scatterlist sg;
 
 	if (!host->card)
 		return;
@@ -1128,61 +821,19 @@ static void mmc_read_scr(struct mmc_host *host)
 	if (!mmc_card_sd(host->card))
 		return;
 
-	memset(&cmd, 0, sizeof(struct mmc_command));
-
-	cmd.opcode = MMC_APP_CMD;
-	cmd.arg = host->card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-	err = mmc_wait_for_cmd(host, &cmd, 0);
-	if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
-		mmc_card_set_dead(host->card);
-		return;
-	}
-
-	memset(&cmd, 0, sizeof(struct mmc_command));
-
-	cmd.opcode = SD_APP_SEND_SCR;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	memset(&data, 0, sizeof(struct mmc_data));
-
-	mmc_set_data_timeout(&data, host->card, 0);
-
-	data.blksz = 1 << 3;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	sg_init_one(&sg, (u8*)host->card->raw_scr, 8);
-
-	mmc_wait_for_req(host, &mrq);
-
-	if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+	err = mmc_app_send_scr(host->card, host->card->raw_scr);
+	if (err != MMC_ERR_NONE) {
 		mmc_card_set_dead(host->card);
 		return;
 	}
 
-	host->card->raw_scr[0] = ntohl(host->card->raw_scr[0]);
-	host->card->raw_scr[1] = ntohl(host->card->raw_scr[1]);
-
 	mmc_decode_scr(host->card);
 }
 
 static void mmc_read_switch_caps(struct mmc_host *host)
 {
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
+	int err;
 	unsigned char *status;
-	struct scatterlist sg;
 
 	if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
 		return;
@@ -1204,32 +855,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
 		return;
 	}
 
-	memset(&cmd, 0, sizeof(struct mmc_command));
-
-	cmd.opcode = SD_SWITCH;
-	cmd.arg = 0x00FFFFF1;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	memset(&data, 0, sizeof(struct mmc_data));
-
-	mmc_set_data_timeout(&data, host->card, 0);
-
-	data.blksz = 64;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	sg_init_one(&sg, status, 64);
-
-	mmc_wait_for_req(host, &mrq);
-
-	if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+	err = mmc_sd_switch(host->card, SD_SWITCH_CHECK,
+		SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status);
+	if (err != MMC_ERR_NONE) {
 		printk("%s: unable to read switch capabilities, "
 			"performance might suffer.\n",
 			mmc_hostname(host));
@@ -1239,33 +867,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
 	if (status[13] & 0x02)
 		host->card->sw_caps.hs_max_dtr = 50000000;
 
-	memset(&cmd, 0, sizeof(struct mmc_command));
-
-	cmd.opcode = SD_SWITCH;
-	cmd.arg = 0x80FFFFF1;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	memset(&data, 0, sizeof(struct mmc_data));
-
-	mmc_set_data_timeout(&data, host->card, 0);
-
-	data.blksz = 64;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	sg_init_one(&sg, status, 64);
-
-	mmc_wait_for_req(host, &mrq);
-
-	if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
-		(status[16] & 0xF) != 1) {
+	err = mmc_sd_switch(host->card, SD_SWITCH_SET,
+		SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status);
+	if (err != MMC_ERR_NONE || (status[16] & 0xF) != 1) {
 		printk(KERN_WARNING "%s: Problem switching card "
 			"into high-speed mode!\n",
 			mmc_hostname(host));
@@ -1314,16 +918,11 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host)
  */
 static void mmc_check_card(struct mmc_card *card)
 {
-	struct mmc_command cmd;
 	int err;
 
 	BUG_ON(!card);
 
-	cmd.opcode = MMC_SEND_STATUS;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-	err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
+	err = mmc_send_status(card, NULL);
 	if (err == MMC_ERR_NONE)
 		return;
 
@@ -1338,9 +937,9 @@ static void mmc_setup(struct mmc_host *host)
 	host->mode = MMC_MODE_SD;
 
 	mmc_power_up(host);
-	mmc_idle_cards(host);
+	mmc_go_idle(host);
 
-	err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+	err = mmc_send_if_cond(host, host->ocr_avail);
 	if (err != MMC_ERR_NONE) {
 		return;
 	}
@@ -1369,7 +968,7 @@ static void mmc_setup(struct mmc_host *host)
 	 * state.  We wait 1ms to give cards time to
 	 * respond.
 	 */
-	mmc_idle_cards(host);
+	mmc_go_idle(host);
 
 	/*
 	 * Send the selected OCR multiple times... until the cards
@@ -1377,17 +976,17 @@ static void mmc_setup(struct mmc_host *host)
 	 * (My SanDisk card seems to need this.)
 	 */
 	if (host->mode == MMC_MODE_SD) {
-		int err, sd2;
-		err = mmc_send_if_cond(host, host->ocr, &sd2);
-		if (err == MMC_ERR_NONE) {
-			/*
-			* If SD_SEND_IF_COND indicates an SD 2.0
-			* compliant card and we should set bit 30
-			* of the ocr to indicate that we can handle
-			* block-addressed SDHC cards.
-			*/
-			mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
-		}
+		/*
+		 * If SD_SEND_IF_COND indicates an SD 2.0
+		 * compliant card and we should set bit 30
+		 * of the ocr to indicate that we can handle
+		 * block-addressed SDHC cards.
+		 */
+		err = mmc_send_if_cond(host, host->ocr);
+		if (err == MMC_ERR_NONE)
+			ocr = host->ocr | (1 << 30);
+
+		mmc_send_app_op_cond(host, ocr, NULL);
 	} else {
 		/* The extra bit indicates that we support high capacity */
 		mmc_send_op_cond(host, host->ocr | (1 << 30), NULL);
@@ -1409,6 +1008,24 @@ static void mmc_setup(struct mmc_host *host)
 			mmc_card_set_dead(host->card);
 	}
 
+	/*
+	 * The card is in 1 bit mode by default so
+	 * we only need to change if it supports the
+	 * wider version.
+	 */
+	if (host->card && !mmc_card_dead(host->card) && 
+		mmc_card_sd(host->card) &&
+		(host->card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) &&
+		(host->card->host->caps & MMC_CAP_4_BIT_DATA)) {
+		err = mmc_app_set_bus_width(host->card, SD_BUS_WIDTH_4);
+		if (err != MMC_ERR_NONE)
+			mmc_card_set_dead(host->card);
+		else {
+			host->ios.bus_width = MMC_BUS_WIDTH_4;
+			mmc_set_ios(host);
+		}
+	}
+
 	if (host->mode == MMC_MODE_SD) {
 		mmc_read_scr(host);
 		mmc_read_switch_caps(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 076cb2f49a0f..1c1066342fba 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -2,24 +2,30 @@
  *  linux/drivers/mmc/core/core.h
  *
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2007 Pierre Ossman
  *
  * 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 _MMC_CORE_H
-#define _MMC_CORE_H
-/* core-internal functions */
-void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
-int mmc_register_card(struct mmc_card *card);
-void mmc_remove_card(struct mmc_card *card);
+#ifndef _MMC_CORE_CORE_H
+#define _MMC_CORE_CORE_H
 
-struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
-int mmc_add_host_sysfs(struct mmc_host *host);
-void mmc_remove_host_sysfs(struct mmc_host *host);
-void mmc_free_host_sysfs(struct mmc_host *host);
+#include <linux/delay.h>
+
+#define MMC_CMD_RETRIES        3
+
+void mmc_set_chip_select(struct mmc_host *host, int mode);
+
+static inline void mmc_delay(unsigned int ms)
+{
+	if (ms < 1000 / HZ) {
+		cond_resched();
+		mdelay(ms);
+	} else {
+		msleep(ms);
+	}
+}
 
-int mmc_schedule_work(struct work_struct *work);
-int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);
-void mmc_flush_scheduled_work(void);
 #endif
+
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
new file mode 100644
index 000000000000..7dd720fa5895
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.c
@@ -0,0 +1,276 @@
+/*
+ *  linux/drivers/mmc/mmc_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "mmc_ops.h"
+
+static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SELECT_CARD;
+
+	if (card) {
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+	}
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_select_card(struct mmc_card *card)
+{
+	BUG_ON(!card);
+
+	return _mmc_select_card(card->host, card);
+}
+
+int mmc_deselect_cards(struct mmc_host *host)
+{
+	return _mmc_select_card(host, NULL);
+}
+
+int mmc_go_idle(struct mmc_host *host)
+{
+	int err;
+	struct mmc_command cmd;
+
+	mmc_set_chip_select(host, MMC_CS_HIGH);
+
+	mmc_delay(1);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_GO_IDLE_STATE;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+
+	mmc_delay(1);
+
+	mmc_set_chip_select(host, MMC_CS_DONTCARE);
+
+	mmc_delay(1);
+
+	return err;
+}
+
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(!cid);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_ALL_SEND_CID;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memcpy(cid, cmd.resp, sizeof(u32) * 4);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_set_relative_addr(struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SET_RELATIVE_ADDR;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!csd);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_CSD;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memcpy(csd, cmd.resp, sizeof(u32) * 4);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!ext_csd);
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = MMC_SEND_EXT_CSD;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 512;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, ext_csd, 512);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SWITCH;
+	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+		  (index << 16) |
+		  (value << 8) |
+		  set;
+	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_status(struct mmc_card *card, u32 *status)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_STATUS;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	if (status)
+		*status = cmd.resp[0];
+
+	return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
new file mode 100644
index 000000000000..7a481e8ca5ea
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.h
@@ -0,0 +1,27 @@
+/*
+ *  linux/drivers/mmc/mmc_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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 _MMC_MMC_OPS_H
+#define _MMC_MMC_OPS_H
+
+int mmc_select_card(struct mmc_card *card);
+int mmc_deselect_cards(struct mmc_host *host);
+int mmc_go_idle(struct mmc_host *host);
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_csd(struct mmc_card *card, u32 *csd);
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
+int mmc_send_status(struct mmc_card *card, u32 *status);
+
+#endif
+
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
new file mode 100644
index 000000000000..9697ce581101
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.c
@@ -0,0 +1,316 @@
+/*
+ *  linux/drivers/mmc/sd_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include "core.h"
+#include "sd_ops.h"
+
+/**
+ *	mmc_wait_for_app_cmd - start an application command and wait for
+ 			       completion
+ *	@host: MMC host to start command
+ *	@rca: RCA to send MMC_APP_CMD to
+ *	@cmd: MMC command to start
+ *	@retries: maximum number of retries
+ *
+ *	Sends a MMC_APP_CMD, checks the card response, sends the command
+ *	in the parameter and waits for it to complete. Return any error
+ *	that occurred while the command was executing.  Do not attempt to
+ *	parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+	struct mmc_command *cmd, int retries)
+{
+	struct mmc_request mrq;
+
+	int i, err;
+
+	BUG_ON(!cmd);
+	BUG_ON(retries < 0);
+
+	err = MMC_ERR_INVALID;
+
+	/*
+	 * We have to resend MMC_APP_CMD for each attempt so
+	 * we cannot use the retries field in mmc_command.
+	 */
+	for (i = 0;i <= retries;i++) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		err = mmc_app_cmd(host, card);
+		if (err != MMC_ERR_NONE)
+			continue;
+
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		memset(cmd->resp, 0, sizeof(cmd->resp));
+		cmd->retries = 0;
+
+		mrq.cmd = cmd;
+		cmd->data = NULL;
+
+		mmc_wait_for_req(host, &mrq);
+
+		err = cmd->error;
+		if (cmd->error == MMC_ERR_NONE)
+			break;
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(card && (card->host != host));
+
+	cmd.opcode = MMC_APP_CMD;
+
+	if (card) {
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+	}
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	/* Check that card supported application commands */
+	if (!(cmd.resp[0] & R1_APP_CMD))
+		return MMC_ERR_FAILED;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_app_set_bus_width(struct mmc_card *card, int width)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_APP_SET_BUS_WIDTH;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	switch (width) {
+	case MMC_BUS_WIDTH_1:
+		cmd.arg = SD_BUS_WIDTH_1;
+		break;
+	case MMC_BUS_WIDTH_4:
+		cmd.arg = SD_BUS_WIDTH_4;
+		break;
+	default:
+		return MMC_ERR_INVALID;
+	}
+
+	err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_APP_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+	struct mmc_command cmd;
+	int err;
+	static const u8 test_pattern = 0xAA;
+
+	/*
+	 * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+	 * before SD_APP_OP_COND. This command will harmlessly fail for
+	 * SD 1.0 cards.
+	 */
+	cmd.opcode = SD_SEND_IF_COND;
+	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	if ((cmd.resp[0] & 0xFF) != test_pattern)
+		return MMC_ERR_FAILED;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(!rca);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_SEND_RELATIVE_ADDR;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	*rca = cmd.resp[0] >> 16;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
+{
+	int err;
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!scr);
+
+	err = mmc_app_cmd(card->host, card);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_APP_SEND_SCR;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 8;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, scr, 8);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	scr[0] = ntohl(scr[0]);
+	scr[1] = ntohl(scr[1]);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+	u8 value, u8 *resp)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	mode = !!mode;
+	value &= 0xF;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_SWITCH;
+	cmd.arg = mode << 31 | 0x00FFFFFF;
+	cmd.arg &= ~(0xF << (group * 4));
+	cmd.arg |= value << (group * 4);
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 64;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, resp, 64);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
new file mode 100644
index 000000000000..1240fddba5e3
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.h
@@ -0,0 +1,25 @@
+/*
+ *  linux/drivers/mmc/sd_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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 _MMC_SD_OPS_H
+#define _MMC_SD_OPS_H
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+int mmc_app_set_bus_width(struct mmc_card *card, int width);
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+	u8 value, u8 *resp);
+
+#endif
+
diff --git a/drivers/mmc/core/sysfs.c b/drivers/mmc/core/sysfs.c
index bf9a5f8beb86..5c9ce02e7e55 100644
--- a/drivers/mmc/core/sysfs.c
+++ b/drivers/mmc/core/sysfs.c
@@ -18,7 +18,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 
-#include "core.h"
+#include "sysfs.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)
diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h
new file mode 100644
index 000000000000..80e29b358282
--- /dev/null
+++ b/drivers/mmc/core/sysfs.h
@@ -0,0 +1,27 @@
+/*
+ *  linux/drivers/mmc/core/sysfs.h
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2007 Pierre Ossman
+ *
+ * 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 _MMC_CORE_SYSFS_H
+#define _MMC_CORE_SYSFS_H
+
+void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
+int mmc_register_card(struct mmc_card *card);
+void mmc_remove_card(struct mmc_card *card);
+
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
+int mmc_add_host_sysfs(struct mmc_host *host);
+void mmc_remove_host_sysfs(struct mmc_host *host);
+void mmc_free_host_sysfs(struct mmc_host *host);
+
+int mmc_schedule_work(struct work_struct *work);
+int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);
+void mmc_flush_scheduled_work(void);
+
+#endif