diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /drivers/mmc/core/mmc_ops.c | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/mmc/core/mmc_ops.c')
| -rw-r--r-- | drivers/mmc/core/mmc_ops.c | 276 | 
1 files changed, 276 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c new file mode 100644 index 00000000000..7dd720fa589 --- /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; +} +  | 
