SDMMC: add the new API about direct read-wirte for the eMMC formatted already

This commit is contained in:
xbw
2014-03-20 13:38:24 +08:00
parent cf2ac748bd
commit 680462b44f
3 changed files with 161 additions and 2 deletions

View File

@@ -2379,6 +2379,10 @@ static const struct mmc_fixup blk_fixups[] =
END_FIXUP
};
#if defined(CONFIG_MMC_DW_ROCKCHIP)
extern struct mmc_card *this_card;
#endif
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
@@ -2428,6 +2432,10 @@ static int mmc_blk_probe(struct mmc_card *card)
pm_runtime_set_active(&card->dev);
pm_runtime_enable(&card->dev);
}
#if defined(CONFIG_MMC_DW_ROCKCHIP)
if(card->host->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
this_card = card;
#endif
return 0;
@@ -2440,7 +2448,11 @@ static int mmc_blk_probe(struct mmc_card *card)
static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
#if defined(CONFIG_MMC_DW_ROCKCHIP)
if(card->host->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
this_card = NULL;
#endif
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);

View File

@@ -46,7 +46,7 @@ obj-$(CONFIG_MMC_DW) += rk_sdmmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
# To Specific Extensions for Synopsys DW Multimedia Card Interface in Rockchip Soc. Added by XBW.
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o rk_sdmmc_of.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o rk_sdmmc_of.o rk_sdmmc_ops.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o

147
drivers/mmc/host/rk_sdmmc_ops.c Executable file
View File

@@ -0,0 +1,147 @@
/*
* linux/drivers/mmchost/rkemmc_ops.c
*
* 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/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#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>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#define BLKSZ 512
struct mmc_card *this_card = NULL;
/*
* Fill in the mmc_request structure given a set of transfer parameters.
*/
static void rk_emmc_prepare_mrq(struct mmc_request *mrq, struct scatterlist *sg,
unsigned sg_len, unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
{
BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
if (blocks > 1) {
mrq->cmd->opcode = write ?
MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
} else {
mrq->cmd->opcode = write ?
MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
}
mrq->cmd->arg = dev_addr;
if (!mmc_card_blockaddr(this_card))
mrq->cmd->arg <<= 9;
mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
if (blocks == 1)
mrq->stop = NULL;
else {
mrq->stop->opcode = MMC_STOP_TRANSMISSION;
mrq->stop->arg = 0;
mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
}
mrq->data->blksz = blksz;
mrq->data->blocks = blocks;
mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
mrq->data->sg = sg;
mrq->data->sg_len = sg_len;
mmc_set_data_timeout(mrq->data, this_card);
}
static int rk_emmc_busy(struct mmc_command *cmd)
{
return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
(R1_CURRENT_STATE(cmd->resp[0]) == 7);
}
/*
* Wait for the card to finish the busy state
*/
static int rk_emmc_wait_busy(void)
{
int ret, busy;
struct mmc_command cmd = {0};
busy = 0;
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = this_card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
ret = mmc_wait_for_cmd(this_card->host, &cmd, 0);
if (ret)
break;
if (!busy && rk_emmc_busy(&cmd)) {
busy = 1;
if (this_card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
pr_info("%s: Warning: Host did not "
"wait for busy state to end.\n",
mmc_hostname(this_card->host));
}
} while (rk_emmc_busy(&cmd));
return ret;
}
/*
* Transfer a single sector of kernel addressable data
*/
int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz, int write)
{
int ret = 0;
struct mmc_request mrq = {0};
struct mmc_command cmd = {0};
struct mmc_command stop = {0};
struct mmc_data data = {0};
struct scatterlist sg;
if(!this_card)
return -EIO;
mrq.cmd = &cmd;
mrq.data = &data;
mrq.stop = &stop;
sg_init_one(&sg, buffer, blksz);
rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, 1, blksz, write);
mmc_claim_host(this_card->host);
mmc_wait_for_req(this_card->host, &mrq);
if (cmd.error){
ret = cmd.error;
goto exit;
}
if (data.error){
ret = data.error;
goto exit;
}
ret = rk_emmc_wait_busy();
exit:
mmc_release_host(this_card->host);
return ret;
}
EXPORT_SYMBOL(rk_emmc_transfer);