Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da7fbe58 authored by Pierre Ossman's avatar Pierre Ossman
Browse files

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: default avatarPierre Ossman <drzeus@drzeus.cx>
parent aaac1b47
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>

#include <asm/system.h>
#include <asm/uaccess.h>
+1 −1
Original line number Diff line number Diff line
@@ -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
+64 −447
Original line number Diff line number Diff line
@@ -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

@@ -190,80 +195,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
@@ -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)
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
	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)
{
	if (ms < 1000 / HZ) {
		cond_resched();
		mdelay(ms);
	} else {
		msleep(ms);
	}
	host->ios.chip_select = mode;
	mmc_set_ios(host);
}

/*
@@ -708,32 +589,6 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid)
	return card;
}

/*
 * 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.
@@ -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);
		}
		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);
+19 −13
Original line number Diff line number Diff line
@@ -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
+276 −0
Original line number Diff line number Diff line
/*
 *  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;
}
Loading