summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/mmc
diff options
context:
space:
mode:
authorKevin2014-11-15 10:00:36 +0800
committerKevin2014-11-15 10:00:36 +0800
commit9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch)
treede942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/mmc
parent392e8802486cb573b916e746010e141a75f507e6 (diff)
downloadFOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.gz
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.bz2
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.zip
add via modify part source code for wm8880 4.4 kitkat
Diffstat (limited to 'ANDROID_3.4.5/drivers/mmc')
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/block.c288
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/bus.c118
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/core.c701
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/core.h2
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/host.c82
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/mmc.c16
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c22
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd.c16
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd_ops.c21
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/Kconfig25
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/Makefile4
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c2837
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h691
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c2405
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c2855
15 files changed, 9843 insertions, 240 deletions
diff --git a/ANDROID_3.4.5/drivers/mmc/card/block.c b/ANDROID_3.4.5/drivers/mmc/card/block.c
index 54c83224..90a15016 100644
--- a/ANDROID_3.4.5/drivers/mmc/card/block.c
+++ b/ANDROID_3.4.5/drivers/mmc/card/block.c
@@ -126,10 +126,18 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
-
+ DBG("[%s] s\n",__func__);
mutex_lock(&open_lock);
md = disk->private_data;
if (md && md->usage == 0)
@@ -137,18 +145,20 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
if (md)
md->usage++;
mutex_unlock(&open_lock);
-
+ DBG("[%s] e\n",__func__);
return md;
}
static inline int mmc_get_devidx(struct gendisk *disk)
{
int devidx = disk->first_minor / perdev_minors;
+ DBG("[%s] s\n",__func__);
return devidx;
}
static void mmc_blk_put(struct mmc_blk_data *md)
{
+ DBG("[%s] s\n",__func__);
mutex_lock(&open_lock);
md->usage--;
if (md->usage == 0) {
@@ -161,6 +171,7 @@ static void mmc_blk_put(struct mmc_blk_data *md)
kfree(md);
}
mutex_unlock(&open_lock);
+ DBG("[%s] e\n",__func__);
}
static ssize_t power_ro_lock_show(struct device *dev,
@@ -170,6 +181,7 @@ static ssize_t power_ro_lock_show(struct device *dev,
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
struct mmc_card *card = md->queue.card;
int locked = 0;
+ DBG("[%s] s\n",__func__);
if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
locked = 2;
@@ -177,7 +189,7 @@ static ssize_t power_ro_lock_show(struct device *dev,
locked = 1;
ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
-
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -188,12 +200,17 @@ static ssize_t power_ro_lock_store(struct device *dev,
struct mmc_blk_data *md, *part_md;
struct mmc_card *card;
unsigned long set;
-
- if (kstrtoul(buf, 0, &set))
+ DBG("[%s] s\n",__func__);
+
+ if (kstrtoul(buf, 0, &set)) {
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
+ }
- if (set != 1)
+ if (set != 1) {
+ DBG("[%s] e2\n",__func__);
return count;
+ }
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
@@ -224,6 +241,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
}
mmc_blk_put(md);
+ DBG("[%s] e3\n",__func__);
return count;
}
@@ -232,11 +250,13 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
{
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ DBG("[%s] s\n",__func__);
ret = snprintf(buf, PAGE_SIZE, "%d",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
mmc_blk_put(md);
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -247,6 +267,8 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
char *end;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
unsigned long set = simple_strtoul(buf, &end, 0);
+ DBG("[%s] s\n",__func__);
+
if (end == buf) {
ret = -EINVAL;
goto out;
@@ -256,6 +278,7 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
ret = count;
out:
mmc_blk_put(md);
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -263,6 +286,7 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
int ret = -ENXIO;
+ DBG("[%s] s\n",__func__);
mutex_lock(&block_mutex);
if (md) {
@@ -276,26 +300,30 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
}
}
mutex_unlock(&block_mutex);
-
+ DBG("[%s] e\n",__func__);
return ret;
}
static int mmc_blk_release(struct gendisk *disk, fmode_t mode)
{
struct mmc_blk_data *md = disk->private_data;
+ DBG("[%s] s\n",__func__);
mutex_lock(&block_mutex);
mmc_blk_put(md);
mutex_unlock(&block_mutex);
+ DBG("[%s] e\n",__func__);
return 0;
}
static int
mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
+ DBG("[%s] s\n",__func__);
geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
geo->heads = 4;
geo->sectors = 16;
+ DBG("[%s] e\n",__func__);
return 0;
}
@@ -310,6 +338,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
{
struct mmc_blk_ioc_data *idata;
int err;
+ DBG("[%s] s\n",__func__);
idata = kzalloc(sizeof(*idata), GFP_KERNEL);
if (!idata) {
@@ -328,8 +357,10 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
goto idata_err;
}
- if (!idata->buf_bytes)
+ if (!idata->buf_bytes) {
+ DBG("[%s] e1\n",__func__);
return idata;
+ }
idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
if (!idata->buf) {
@@ -342,7 +373,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
err = -EFAULT;
goto copy_err;
}
-
+ DBG("[%s] e2\n",__func__);
return idata;
copy_err:
@@ -350,6 +381,7 @@ copy_err:
idata_err:
kfree(idata);
out:
+ DBG("[%s] e3\n",__func__);
return ERR_PTR(err);
}
@@ -364,18 +396,22 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
-
+ DBG("[%s] s\n",__func__);
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
* whole block device, not on a partition. This prevents overspray
* between sibling partitions.
*/
- if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+ if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) {
+ DBG("[%s] e1\n",__func__);
return -EPERM;
+ }
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
- if (IS_ERR(idata))
+ if (IS_ERR(idata)) {
+ DBG("[%s] e2\n",__func__);
return PTR_ERR(idata);
+ }
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
@@ -481,6 +517,7 @@ cmd_done:
mmc_blk_put(md);
kfree(idata->buf);
kfree(idata);
+ DBG("[%s] e3\n",__func__);
return err;
}
@@ -488,8 +525,10 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
int ret = -EINVAL;
+ DBG("[%s] s\n",__func__);
if (cmd == MMC_IOC_CMD)
ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -497,6 +536,7 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
+ DBG("[%s] s\n",__func__);
return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
}
#endif
@@ -517,9 +557,12 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
{
int ret;
struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+ DBG("[%s] s\n",__func__);
- if (main_md->part_curr == md->part_type)
+ if (main_md->part_curr == md->part_type) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
if (mmc_card_mmc(card)) {
u8 part_config = card->ext_csd.part_config;
@@ -530,13 +573,16 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
- if (ret)
+ if (ret) {
+ DBG("[%s] e2\n",__func__);
return ret;
+ }
card->ext_csd.part_config = part_config;
}
main_md->part_curr = md->part_type;
+ DBG("[%s] e3\n",__func__);
return 0;
}
@@ -545,29 +591,35 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
int err;
u32 result;
__be32 *blocks;
-
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
unsigned int timeout_us;
struct scatterlist sg;
+ DBG("[%s] s\n",__func__);
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err)
+ if (err) {
+ DBG("[%s] e1\n",__func__);
return (u32)-1;
- if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
+ }
+ if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) {
+ DBG("[%s] e2\n",__func__);
return (u32)-1;
+ }
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.timeout_ns = card->csd.tacc_ns * 100;
data.timeout_clks = card->csd.tacc_clks * 100;
@@ -591,8 +643,10 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
mrq.data = &data;
blocks = kmalloc(4, GFP_KERNEL);
- if (!blocks)
+ if (!blocks) {
+ DBG("[%s] e3\n",__func__);
return (u32)-1;
+ }
sg_init_one(&sg, blocks, 4);
@@ -603,7 +657,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
if (cmd.error || data.error)
result = (u32)-1;
-
+ DBG("[%s] e4\n",__func__);
return result;
}
@@ -611,12 +665,15 @@ static int send_stop(struct mmc_card *card, u32 *status)
{
struct mmc_command cmd = {0};
int err;
+ DBG("[%s] s\n",__func__);
cmd.opcode = MMC_STOP_TRANSMISSION;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
if (err == 0)
*status = cmd.resp[0];
+ DBG("[%s] e\n",__func__);
return err;
}
@@ -624,14 +681,17 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
{
struct mmc_command cmd = {0};
int err;
+ DBG("[%s] s\n",__func__);
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, retries);
if (err == 0)
*status = cmd.resp[0];
+ DBG("[%s] e\n",__func__);
return err;
}
@@ -643,12 +703,14 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
bool status_valid, u32 status)
{
+ DBG("[%s] s\n",__func__);
switch (error) {
case -EILSEQ:
/* response crc error, retry the r/w cmd */
pr_err("%s: %s sending %s command, card status %#x\n",
req->rq_disk->disk_name, "response CRC error",
name, status);
+ DBG("[%s] e1\n",__func__);
return ERR_RETRY;
case -ETIMEDOUT:
@@ -658,6 +720,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
/* If the status cmd initially failed, retry the r/w cmd */
if (!status_valid) {
pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name);
+ DBG("[%s] e2\n",__func__);
return ERR_RETRY;
}
/*
@@ -667,17 +730,20 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
*/
if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name);
+ DBG("[%s] e3\n",__func__);
return ERR_RETRY;
}
/* Otherwise abort the command */
pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name);
+ DBG("[%s] e4\n",__func__);
return ERR_ABORT;
default:
/* We don't understand the error code the driver gave us */
pr_err("%s: unknown error %d sending read/write command, card status %#x\n",
req->rq_disk->disk_name, error, status);
+ DBG("[%s] e5\n",__func__);
return ERR_ABORT;
}
}
@@ -706,10 +772,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
bool prev_cmd_status_valid = true;
u32 status, stop_status = 0;
int err, retry;
+ DBG("[%s] s\n",__func__);
- if (mmc_card_removed(card))
+ if (mmc_card_removed(card)) {
+ DBG("[%s] e1\n",__func__);
return ERR_NOMEDIUM;
-
+ }
/*
* Try to get card status which indicates both the card state
* and why there was no response. If the first attempt fails,
@@ -728,8 +796,11 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
/* We couldn't get a response from the card. Give up. */
if (err) {
/* Check if the card is removed */
- if (mmc_detect_card_removed(card->host))
+ if (mmc_detect_card_removed(card->host)) {
+ DBG("[%s] e1\n",__func__);
return ERR_NOMEDIUM;
+ }
+ DBG("[%s] e2\n",__func__);
return ERR_ABORT;
}
@@ -754,25 +825,31 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
* If the stop cmd also timed out, the card is probably
* not present, so abort. Other errors are bad news too.
*/
- if (err)
+ if (err) {
+ DBG("[%s] e4\n",__func__);
return ERR_ABORT;
+ }
if (stop_status & R1_CARD_ECC_FAILED)
*ecc_err = 1;
}
/* Check for set block count errors */
- if (brq->sbc.error)
+ if (brq->sbc.error) {
+ DBG("[%s] e5\n",__func__);
return mmc_blk_cmd_error(req, "SET_BLOCK_COUNT", brq->sbc.error,
prev_cmd_status_valid, status);
-
+ }
/* Check for r/w command errors */
- if (brq->cmd.error)
+ if (brq->cmd.error) {
+ DBG("[%s] e6\n",__func__);
return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
prev_cmd_status_valid, status);
-
+ }
/* Data errors */
- if (!brq->stop.error)
+ if (!brq->stop.error) {
+ DBG("[%s] e7\n",__func__);
return ERR_CONTINUE;
+ }
/* Now for stop errors. These aren't fatal to the transfer. */
pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
@@ -787,6 +864,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
brq->stop.resp[0] = stop_status;
brq->stop.error = 0;
}
+ DBG("[%s] e8\n",__func__);
return ERR_CONTINUE;
}
@@ -794,9 +872,12 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
int type)
{
int err;
+ DBG("[%s] s\n",__func__);
- if (md->reset_done & type)
+ if (md->reset_done & type) {
+ DBG("[%s] e1\n",__func__);
return -EEXIST;
+ }
md->reset_done |= type;
err = mmc_hw_reset(host);
@@ -812,15 +893,19 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
* We have failed to get back into the correct
* partition, so we need to abort the whole request.
*/
+ DBG("[%s] e2\n",__func__);
return -ENODEV;
}
}
+ DBG("[%s] e3\n",__func__);
return err;
}
static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
{
+ DBG("[%s] s\n",__func__);
md->reset_done &= ~type;
+ DBG("[%s] e\n",__func__);
}
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
@@ -829,6 +914,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg;
int err = 0, type = MMC_BLK_DISCARD;
+ DBG("[%s] s\n",__func__);
if (!mmc_can_erase(card)) {
err = -EOPNOTSUPP;
@@ -864,7 +950,7 @@ out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
-
+ DBG("[%s] e\n",__func__);
return err ? 0 : 1;
}
@@ -875,6 +961,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg, trim_arg, erase_arg;
int err = 0, type = MMC_BLK_SECDISCARD;
+ DBG("[%s] s\n",__func__);
if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
err = -EOPNOTSUPP;
@@ -948,7 +1035,7 @@ out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
-
+ DBG("[%s] e\n",__func__);
return err ? 0 : 1;
}
@@ -957,6 +1044,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
int ret = 0;
+ DBG("[%s] s\n",__func__);
ret = mmc_flush_cache(card);
if (ret)
@@ -965,7 +1053,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
spin_lock_irq(&md->lock);
__blk_end_request_all(req, ret);
spin_unlock_irq(&md->lock);
-
+ DBG("[%s] e\n",__func__);
return ret ? 0 : 1;
}
@@ -980,6 +1068,7 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
struct mmc_card *card,
struct request *req)
{
+ DBG("[%s] s\n",__func__);
if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
/* Legacy mode imposes restrictions on transfers. */
if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
@@ -990,6 +1079,7 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
else if (brq->data.blocks < card->ext_csd.rel_sectors)
brq->data.blocks = 1;
}
+ DBG("[%s] e\n",__func__);
}
#define CMD_ERRORS \
@@ -1008,7 +1098,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
struct mmc_blk_request *brq = &mq_mrq->brq;
struct request *req = mq_mrq->req;
int ecc_err = 0;
-
+ DBG("[%s] s\n",__func__);
/*
* sbc.error indicates a problem with the set block count
* command. No data will have been transferred.
@@ -1041,6 +1131,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
if (brq->cmd.resp[0] & CMD_ERRORS) {
pr_err("%s: r/w command failed, status = %#x\n",
req->rq_disk->disk_name, brq->cmd.resp[0]);
+ DBG("[%s] e1\n",__func__);
return MMC_BLK_ABORT;
}
@@ -1056,6 +1147,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
if (err) {
pr_err("%s: error %d requesting status\n",
req->rq_disk->disk_name, err);
+ DBG("[%s] e2\n",__func__);
return MMC_BLK_CMD_ERR;
}
/*
@@ -1075,20 +1167,29 @@ static int mmc_blk_err_check(struct mmc_card *card,
brq->cmd.resp[0], brq->stop.resp[0]);
if (rq_data_dir(req) == READ) {
- if (ecc_err)
+ if (ecc_err) {
+ DBG("[%s] e3\n",__func__);
return MMC_BLK_ECC_ERR;
+ }
+ DBG("[%s] e4\n",__func__);
return MMC_BLK_DATA_ERR;
} else {
+ DBG("[%s] e5\n",__func__);
return MMC_BLK_CMD_ERR;
}
}
- if (!brq->data.bytes_xfered)
+ if (!brq->data.bytes_xfered) {
+ DBG("[%s] e6\n",__func__);
return MMC_BLK_RETRY;
+ }
- if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+ if (blk_rq_bytes(req) != brq->data.bytes_xfered) {
+ DBG("[%s] e7\n",__func__);
return MMC_BLK_PARTIAL;
-
+ }
+
+ DBG("[%s] e8\n",__func__);
return MMC_BLK_SUCCESS;
}
@@ -1102,7 +1203,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct request *req = mqrq->req;
struct mmc_blk_data *md = mq->data;
bool do_data_tag;
-
+
/*
* Reliable writes are used to implement Forced Unit Access and
* REQ_META accesses, and are supported only on MMCs.
@@ -1114,7 +1215,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
(req->cmd_flags & REQ_META)) &&
(rq_data_dir(req) == WRITE) &&
(md->flags & MMC_BLK_REL_WR);
-
+ DBG("[%s] s\n",__func__);
memset(brq, 0, sizeof(struct mmc_blk_request));
brq->mrq.cmd = &brq->cmd;
brq->mrq.data = &brq->data;
@@ -1122,11 +1223,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->cmd.arg = blk_rq_pos(req);
if (!mmc_card_blockaddr(card))
brq->cmd.arg <<= 9;
- brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq->cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq->data.blksz = 512;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
- brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ //brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ brq->stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
brq->data.blocks = blk_rq_sectors(req);
/*
@@ -1244,12 +1347,14 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
mqrq->mmc_active.err_check = mmc_blk_err_check;
mmc_queue_bounce_pre(mqrq);
+ DBG("[%s] e\n",__func__);
}
static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
struct mmc_blk_request *brq, struct request *req,
int ret)
{
+ DBG("[%s] s\n",__func__);
/*
* If this is an SD card and we're writing, we can first
* mark the known good sectors as ok.
@@ -1272,6 +1377,7 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
}
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -1285,9 +1391,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
struct mmc_queue_req *mq_rq;
struct request *req;
struct mmc_async_req *areq;
+ DBG("[%s] s\n",__func__);
- if (!rqc && !mq->mqrq_prev->req)
+ if (!rqc && !mq->mqrq_prev->req) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
do {
if (rqc) {
@@ -1296,8 +1405,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
} else
areq = NULL;
areq = mmc_start_req(card->host, areq, (int *) &status);
- if (!areq)
+ if (!areq) {
+ DBG("[%s] e2\n",__func__);
return 0;
+ }
mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
brq = &mq_rq->brq;
@@ -1385,7 +1496,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
}
} while (ret);
-
+ DBG("[%s] e3\n",__func__);
return 1;
cmd_abort:
@@ -1401,7 +1512,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
}
-
+ DBG("[%s] e4\n",__func__);
return 0;
}
@@ -1413,7 +1524,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
int ret;
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
-
+ DBG("[%s] s\n",__func__);
+
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
if (mmc_bus_needs_resume(card->host)) {
mmc_resume_bus(card->host);
@@ -1425,6 +1537,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
/* claim host only for the first request */
mmc_claim_host(card->host);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+/*
+ if(card->host->card_attath_status == card_attach_status_change) {
+ goto cmd_err;
+ }
+*/
+#endif
+
ret = mmc_blk_part_switch(card, md);
if (ret) {
if (req) {
@@ -1457,11 +1577,13 @@ out:
if (!req)
/* release host only when there are no more requests */
mmc_release_host(card->host);
+ DBG("[%s] e\n",__func__);
return ret;
}
static inline int mmc_blk_readonly(struct mmc_card *card)
{
+ DBG("[%s] s\n",__func__);
return mmc_card_readonly(card) ||
!(card->csd.cmdclass & CCC_BLOCK_WRITE);
}
@@ -1475,10 +1597,13 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
{
struct mmc_blk_data *md;
int devidx, ret;
+ DBG("[%s] s\n",__func__);
devidx = find_first_zero_bit(dev_use, max_devices);
- if (devidx >= max_devices)
+ if (devidx >= max_devices) {
+ DBG("[%s] e1\n",__func__);
return ERR_PTR(-ENOSPC);
+ }
__set_bit(devidx, dev_use);
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
@@ -1546,8 +1671,11 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
* messages to tell when the card is present.
*/
+ /*snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+ "mmcblk%d%s", md->name_idx, subname ? subname : "");*/
+
snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
- "mmcblk%d%s", md->name_idx, subname ? subname : "");
+ "mmcblk%d%s", card->host->wmt_host_index, subname ? subname : "");
blk_queue_logical_block_size(md->queue.queue, 512);
set_capacity(md->disk, size);
@@ -1566,7 +1694,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->flags |= MMC_BLK_REL_WR;
blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
}
-
+ DBG("[%s] e2\n",__func__);
return md;
err_putdisk:
@@ -1574,6 +1702,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
err_kfree:
kfree(md);
out:
+ DBG("[%s] e3\n",__func__);
return ERR_PTR(ret);
}
@@ -1581,6 +1710,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
sector_t size;
struct mmc_blk_data *md;
+ DBG("[%s] s\n",__func__);
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
@@ -1598,6 +1728,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
MMC_BLK_DATA_AREA_MAIN);
+ DBG("[%s] e\n",__func__);
return md;
}
@@ -1611,11 +1742,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
{
char cap_str[10];
struct mmc_blk_data *part_md;
+ DBG("[%s] s\n",__func__);
part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
subname, area_type);
- if (IS_ERR(part_md))
+ if (IS_ERR(part_md)) {
+ DBG("[%s] e1\n",__func__);
return PTR_ERR(part_md);
+ }
part_md->part_type = part_type;
list_add(&part_md->part, &md->part);
@@ -1624,6 +1758,7 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
pr_info("%s: %s %s partition %u %s\n",
part_md->disk->disk_name, mmc_card_id(card),
mmc_card_name(card), part_md->part_type, cap_str);
+ DBG("[%s] e2\n",__func__);
return 0;
}
@@ -1636,9 +1771,12 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{
int idx, ret = 0;
+ DBG("[%s] s\n",__func__);
- if (!mmc_card_mmc(card))
+ if (!mmc_card_mmc(card)) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
for (idx = 0; idx < card->nr_parts; idx++) {
if (card->part[idx].size) {
@@ -1648,17 +1786,20 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
card->part[idx].force_ro,
card->part[idx].name,
card->part[idx].area_type);
- if (ret)
+ if (ret) {
+ DBG("[%s] e2\n",__func__);
return ret;
+ }
}
}
-
+ DBG("[%s] e3\n",__func__);
return ret;
}
static void mmc_blk_remove_req(struct mmc_blk_data *md)
{
struct mmc_card *card;
+ DBG("[%s] s\n",__func__);
if (md) {
card = md->queue.card;
@@ -1677,6 +1818,7 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
mmc_cleanup_queue(&md->queue);
mmc_blk_put(md);
}
+ DBG("[%s] e\n",__func__);
}
static void mmc_blk_remove_parts(struct mmc_card *card,
@@ -1684,6 +1826,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
{
struct list_head *pos, *q;
struct mmc_blk_data *part_md;
+ DBG("[%s] s\n",__func__);
__clear_bit(md->name_idx, name_use);
list_for_each_safe(pos, q, &md->part) {
@@ -1691,12 +1834,14 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
list_del(pos);
mmc_blk_remove_req(part_md);
}
+ DBG("[%s] e\n",__func__);
}
static int mmc_add_disk(struct mmc_blk_data *md)
{
int ret;
struct mmc_card *card = md->queue.card;
+ DBG("[%s] s\n",__func__);
add_disk(md->disk);
md->force_ro.show = force_ro_show;
@@ -1728,13 +1873,14 @@ static int mmc_add_disk(struct mmc_blk_data *md)
if (ret)
goto power_ro_lock_fail;
}
+ DBG("[%s] e1\n",__func__);
return ret;
power_ro_lock_fail:
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
force_ro_fail:
del_gendisk(md->disk);
-
+ DBG("[%s] e2\n",__func__);
return ret;
}
@@ -1784,16 +1930,19 @@ static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
char cap_str[10];
-
+ DBG("[%s] s\n",__func__);
/*
* Check that the card supports the command class(es) we need.
*/
- if (!(card->csd.cmdclass & CCC_BLOCK_READ))
+ if (!(card->csd.cmdclass & CCC_BLOCK_READ)) {
+ DBG("[%s] e1\n",__func__);
return -ENODEV;
-
+ }
md = mmc_blk_alloc(card);
- if (IS_ERR(md))
+ if (IS_ERR(md)) {
+ DBG("[%s] e2\n",__func__);
return PTR_ERR(md);
+ }
string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
cap_str, sizeof(cap_str));
@@ -1817,17 +1966,21 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(part_md))
goto out;
}
+
+ DBG("[%s] e3\n",__func__);
return 0;
out:
mmc_blk_remove_parts(card, md);
mmc_blk_remove_req(md);
+ DBG("[%s] e4\n",__func__);
return 0;
}
static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
+ DBG("[%s] s\n",__func__);
mmc_blk_remove_parts(card, md);
mmc_claim_host(card->host);
@@ -1838,6 +1991,7 @@ static void mmc_blk_remove(struct mmc_card *card)
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
mmc_set_bus_resume_policy(card->host, 0);
#endif
+ DBG("[%s] e\n",__func__);
}
#ifdef CONFIG_PM
@@ -1845,6 +1999,7 @@ static int mmc_blk_suspend(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
+ DBG("[%s] s\n",__func__);
if (md) {
mmc_queue_suspend(&md->queue);
@@ -1852,6 +2007,7 @@ static int mmc_blk_suspend(struct mmc_card *card)
mmc_queue_suspend(&part_md->queue);
}
}
+ DBG("[%s] e\n",__func__);
return 0;
}
@@ -1859,6 +2015,7 @@ static int mmc_blk_resume(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
+ DBG("[%s] s\n",__func__);
if (md) {
/*
@@ -1871,6 +2028,7 @@ static int mmc_blk_resume(struct mmc_card *card)
mmc_queue_resume(&part_md->queue);
}
}
+ DBG("[%s] e\n",__func__);
return 0;
}
#else
@@ -1891,6 +2049,7 @@ static struct mmc_driver mmc_driver = {
static int __init mmc_blk_init(void)
{
int res;
+ DBG("[%s] s\n",__func__);
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
@@ -1904,18 +2063,21 @@ static int __init mmc_blk_init(void)
res = mmc_register_driver(&mmc_driver);
if (res)
goto out2;
-
+ DBG("[%s] e1\n",__func__);
return 0;
out2:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out:
+ DBG("[%s] e2\n",__func__);
return res;
}
static void __exit mmc_blk_exit(void)
{
+ DBG("[%s] s\n",__func__);
mmc_unregister_driver(&mmc_driver);
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
+ DBG("[%s] e\n",__func__);
}
module_init(mmc_blk_init);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/bus.c b/ANDROID_3.4.5/drivers/mmc/core/bus.c
index c60cee92..e2cbbc3c 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/bus.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/bus.c
@@ -27,21 +27,34 @@
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ DBG("[%s] s\n",__func__);
+
switch (card->type) {
case MMC_TYPE_MMC:
+ DBG("[%s] e1\n",__func__);
return sprintf(buf, "MMC\n");
case MMC_TYPE_SD:
+ DBG("[%s] e2\n",__func__);
return sprintf(buf, "SD\n");
case MMC_TYPE_SDIO:
+ DBG("[%s] e3\n",__func__);
return sprintf(buf, "SDIO\n");
case MMC_TYPE_SD_COMBO:
+ DBG("[%s] e4\n",__func__);
return sprintf(buf, "SDcombo\n");
default:
+ DBG("[%s] e5\n",__func__);
return -EFAULT;
}
}
@@ -58,6 +71,7 @@ static struct device_attribute mmc_dev_attrs[] = {
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
+ DBG("[%s]\n",__func__);
return 1;
}
@@ -68,6 +82,8 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
const char *type;
int retval = 0;
+ DBG("[%s] s\n",__func__);
+
switch (card->type) {
case MMC_TYPE_MMC:
type = "MMC";
@@ -87,13 +103,17 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
if (type) {
retval = add_uevent_var(env, "MMC_TYPE=%s", type);
- if (retval)
+ if (retval) {
+ DBG("[%s] e1\n",__func__);
return retval;
+ }
}
retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
- if (retval)
+ if (retval) {
+ DBG("[%s] e2\n",__func__);
return retval;
+ }
/*
* Request the mmc_block device. Note: that this is a direct request
@@ -101,6 +121,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
*/
retval = add_uevent_var(env, "MODALIAS=mmc:block");
+ DBG("[%s] e3\n",__func__);
return retval;
}
@@ -109,6 +130,7 @@ static int mmc_bus_probe(struct device *dev)
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
+ DBG("[%s]\n",__func__);
return drv->probe(card);
}
@@ -117,8 +139,11 @@ static int mmc_bus_remove(struct device *dev)
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
+ DBG("[%s] s\n",__func__);
+
drv->remove(card);
+ DBG("[%s] e\n",__func__);
return 0;
}
@@ -126,10 +151,15 @@ static int mmc_bus_suspend(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
+ pm_message_t state = { PM_EVENT_SUSPEND };
int ret = 0;
+ DBG("[%s] s\n",__func__);
+
if (dev->driver && drv->suspend)
ret = drv->suspend(card);
+
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -139,8 +169,12 @@ static int mmc_bus_resume(struct device *dev)
struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0;
+ DBG("[%s] s\n",__func__);
+
if (dev->driver && drv->resume)
ret = drv->resume(card);
+
+ DBG("[%s] e\n",__func__);
return ret;
}
@@ -149,20 +183,44 @@ static int mmc_bus_resume(struct device *dev)
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+
+ ret = mmc_power_save_host(card->host);
+
+ DBG("[%s] e\n",__func__);
+ /*return mmc_power_save_host(card->host);*/
+ return ret;
- return mmc_power_save_host(card->host);
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+
+ ret = mmc_power_restore_host(card->host);
+
+ DBG("[%s] e\n",__func__);
+ /*return mmc_power_restore_host(card->host);*/
+ return ret;
- return mmc_power_restore_host(card->host);
}
static int mmc_runtime_idle(struct device *dev)
{
- return pm_runtime_suspend(dev);
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+
+ ret = pm_runtime_suspend(dev);
+
+ DBG("[%s] e\n",__func__);
+ /*return pm_runtime_suspend(dev);*/
+ return ret;
}
#endif /* !CONFIG_PM_RUNTIME */
@@ -185,12 +243,24 @@ static struct bus_type mmc_bus_type = {
int mmc_register_bus(void)
{
- return bus_register(&mmc_bus_type);
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+
+ ret = bus_register(&mmc_bus_type);
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+ /*return bus_register(&mmc_bus_type);*/
}
void mmc_unregister_bus(void)
{
+ DBG("[%s] s\n",__func__);
+
bus_unregister(&mmc_bus_type);
+
+ DBG("[%s] e\n",__func__);
}
/**
@@ -199,8 +269,17 @@ void mmc_unregister_bus(void)
*/
int mmc_register_driver(struct mmc_driver *drv)
{
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+
drv->drv.bus = &mmc_bus_type;
- return driver_register(&drv->drv);
+ ret = driver_register(&drv->drv);
+
+ DBG("[%s] e\n",__func__);
+ /*return driver_register(&drv->drv);*/
+ return ret;
+
}
EXPORT_SYMBOL(mmc_register_driver);
@@ -211,8 +290,12 @@ EXPORT_SYMBOL(mmc_register_driver);
*/
void mmc_unregister_driver(struct mmc_driver *drv)
{
+ DBG("[%s] s\n",__func__);
+
drv->drv.bus = &mmc_bus_type;
driver_unregister(&drv->drv);
+
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_unregister_driver);
@@ -221,12 +304,16 @@ static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ DBG("[%s] s\n",__func__);
+
sdio_free_common_cis(card);
if (card->info)
kfree(card->info);
kfree(card);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -235,10 +322,13 @@ static void mmc_release_card(struct device *dev)
struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
{
struct mmc_card *card;
+ DBG("[%s] s\n",__func__);
card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
- if (!card)
+ if (!card) {
+ DBG("[%s] e1\n",__func__);
return ERR_PTR(-ENOMEM);
+ }
card->host = host;
@@ -249,6 +339,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
card->dev.release = mmc_release_card;
card->dev.type = type;
+ DBG("[%s] e2\n",__func__);
return card;
}
@@ -267,7 +358,7 @@ int mmc_add_card(struct mmc_card *card)
[UHS_SDR104_BUS_SPEED] = "SDR104 ",
[UHS_DDR50_BUS_SPEED] = "DDR50 ",
};
-
+ DBG("[%s] s\n",__func__);
dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
@@ -322,11 +413,14 @@ int mmc_add_card(struct mmc_card *card)
#endif
ret = device_add(&card->dev);
- if (ret)
+ if (ret) {
+ DBG("[%s] e1\n",__func__);
return ret;
+ }
mmc_card_set_present(card);
+ DBG("[%s] e2\n",__func__);
return 0;
}
@@ -336,6 +430,8 @@ int mmc_add_card(struct mmc_card *card)
*/
void mmc_remove_card(struct mmc_card *card)
{
+ DBG("[%s] s\n",__func__);
+
#ifdef CONFIG_DEBUG_FS
mmc_remove_card_debugfs(card);
#endif
@@ -352,5 +448,7 @@ void mmc_remove_card(struct mmc_card *card)
}
put_device(&card->dev);
+
+ DBG("[%s] e\n",__func__);
}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/core.c b/ANDROID_3.4.5/drivers/mmc/core/core.c
index 95902a7e..7dc7edd5 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/core.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/core.c
@@ -41,9 +41,18 @@
#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"
+#include "../host/mmc_atsmb.h"
+#include <mach/hardware.h>
+
static struct workqueue_struct *workqueue;
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
@@ -75,7 +84,14 @@ MODULE_PARM_DESC(
static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
- return queue_delayed_work(workqueue, work, delay);
+ int ret;
+ DBG("[%s] s\n",__func__);
+
+ ret = queue_delayed_work(workqueue, work, delay);
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+ /*return queue_delayed_work(workqueue, work, delay);*/
}
/*
@@ -83,7 +99,11 @@ static int mmc_schedule_delayed_work(struct delayed_work *work,
*/
static void mmc_flush_scheduled_work(void)
{
+ DBG("[%s] s\n",__func__);
+
flush_workqueue(workqueue);
+
+ DBG("[%s] e\n",__func__);
}
#ifdef CONFIG_FAIL_MMC_REQUEST
@@ -135,6 +155,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
+ DBG("[%s] s\n",__func__);
if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
@@ -177,6 +198,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
mmc_host_clk_release(host);
}
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_request_done);
@@ -188,6 +210,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
unsigned int i, sz;
struct scatterlist *sg;
#endif
+ DBG("[%s] s\n",__func__);
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
@@ -243,23 +266,32 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq);
+
+ DBG("[%s] e\n",__func__);
}
static void mmc_wait_done(struct mmc_request *mrq)
{
+ DBG("[%s] s\n",__func__);
+
complete(&mrq->completion);
+
+ DBG("[%s] e\n",__func__);
}
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
+ DBG("[%s] s\n",__func__);
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
if (mmc_card_removed(host->card)) {
mrq->cmd->error = -ENOMEDIUM;
complete(&mrq->completion);
+ DBG("[%s] e1\n",__func__);
return -ENOMEDIUM;
}
mmc_start_request(host, mrq);
+ DBG("[%s] e2\n",__func__);
return 0;
}
@@ -267,7 +299,7 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd;
-
+ DBG("[%s] s\n",__func__);
while (1) {
wait_for_completion(&mrq->completion);
@@ -282,6 +314,7 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
cmd->error = 0;
host->ops->request(host, mrq);
}
+ DBG("[%s] e\n",__func__);
}
/**
@@ -298,11 +331,13 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req)
{
+ DBG("[%s] s\n",__func__);
if (host->ops->pre_req) {
mmc_host_clk_hold(host);
host->ops->pre_req(host, mrq, is_first_req);
mmc_host_clk_release(host);
}
+ DBG("[%s] e\n",__func__);
}
/**
@@ -317,11 +352,13 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err)
{
+ DBG("[%s] s\n",__func__);
if (host->ops->post_req) {
mmc_host_clk_hold(host);
host->ops->post_req(host, mrq, err);
mmc_host_clk_release(host);
}
+ DBG("[%s] e\n",__func__);
}
/**
@@ -346,7 +383,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
int err = 0;
int start_err = 0;
struct mmc_async_req *data = host->areq;
-
+ DBG("[%s] s\n",__func__);
/* Prepare a new request */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);
@@ -373,6 +410,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (error)
*error = err;
+ DBG("[%s] e\n",__func__);
return data;
}
EXPORT_SYMBOL(mmc_start_req);
@@ -388,8 +426,10 @@ EXPORT_SYMBOL(mmc_start_req);
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
+ DBG("[%s] s\n",__func__);
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_wait_for_req);
@@ -404,7 +444,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
{
int err;
u32 status;
-
+ DBG("[%s] s\n",__func__);
BUG_ON(!card);
if (!card->ext_csd.hpi_en) {
@@ -446,6 +486,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
out:
mmc_release_host(card->host);
+ DBG("[%s] e\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_interrupt_hpi);
@@ -464,6 +505,8 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq = {NULL};
+ DBG("[%s] s\n",__func__);
+
WARN_ON(!host->claimed);
memset(cmd->resp, 0, sizeof(cmd->resp));
@@ -474,6 +517,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
mmc_wait_for_req(host, &mrq);
+ DBG("[%s] e\n",__func__);
return cmd->error;
}
@@ -490,13 +534,14 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
{
unsigned int mult;
-
+ DBG("[%s] s\n",__func__);
/*
* SDIO cards only define an upper 1 s limit on access.
*/
if (mmc_card_sdio(card)) {
data->timeout_ns = 1000000000;
data->timeout_clks = 0;
+ DBG("[%s] e1\n",__func__);
return;
}
@@ -574,6 +619,8 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
data->timeout_ns = 100000000; /* 100ms */
}
}
+
+ DBG("[%s] e2\n",__func__);
}
EXPORT_SYMBOL(mmc_set_data_timeout);
@@ -620,6 +667,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
unsigned long flags;
int stop;
+ DBG("[%s] s\n",__func__);
+
might_sleep();
add_wait_queue(&host->wq, &wait);
@@ -644,6 +693,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
remove_wait_queue(&host->wq, &wait);
if (host->ops->enable && !stop && host->claim_cnt == 1)
host->ops->enable(host);
+
+ DBG("[%s] e\n",__func__);
return stop;
}
@@ -659,6 +710,7 @@ int mmc_try_claim_host(struct mmc_host *host)
{
int claimed_host = 0;
unsigned long flags;
+ DBG("[%s] s\n",__func__);
spin_lock_irqsave(&host->lock, flags);
if (!host->claimed || host->claimer == current) {
@@ -670,6 +722,8 @@ int mmc_try_claim_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
if (host->ops->enable && claimed_host && host->claim_cnt == 1)
host->ops->enable(host);
+
+ DBG("[%s] e\n",__func__);
return claimed_host;
}
EXPORT_SYMBOL(mmc_try_claim_host);
@@ -684,6 +738,7 @@ EXPORT_SYMBOL(mmc_try_claim_host);
void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
+ DBG("[%s] s\n",__func__);
WARN_ON(!host->claimed);
@@ -700,6 +755,7 @@ void mmc_release_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
}
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_release_host);
@@ -711,6 +767,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
{
struct mmc_ios *ios = &host->ios;
+ DBG("[%s] s\n",__func__);
+
pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
"width %u timing %u\n",
mmc_hostname(host), ios->clock, ios->bus_mode,
@@ -720,6 +778,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
if (ios->clock > 0)
mmc_set_ungated(host);
host->ops->set_ios(host, ios);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -727,10 +787,14 @@ static inline void mmc_set_ios(struct mmc_host *host)
*/
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
+ DBG("[%s] s\n",__func__);
+
mmc_host_clk_hold(host);
host->ios.chip_select = mode;
mmc_set_ios(host);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -739,6 +803,8 @@ void mmc_set_chip_select(struct mmc_host *host, int mode)
*/
static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
+ DBG("[%s] s\n",__func__);
+
WARN_ON(hz < host->f_min);
if (hz > host->f_max)
@@ -746,13 +812,18 @@ static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
host->ios.clock = hz;
mmc_set_ios(host);
+
+ DBG("[%s] e\n",__func__);
}
void mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
+ DBG("[%s] s\n",__func__);
mmc_host_clk_hold(host);
__mmc_set_clock(host, hz);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
#ifdef CONFIG_MMC_CLKGATE
@@ -762,13 +833,16 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
void mmc_gate_clock(struct mmc_host *host)
{
unsigned long flags;
-
+ DBG("[%s] s\n",__func__);
+
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_old = host->ios.clock;
host->ios.clock = 0;
host->clk_gated = true;
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_set_ios(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -777,6 +851,7 @@ void mmc_gate_clock(struct mmc_host *host)
*/
void mmc_ungate_clock(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
/*
* We should previously have gated the clock, so the clock shall
* be 0 here! The clock may however be 0 during initialization,
@@ -789,12 +864,14 @@ void mmc_ungate_clock(struct mmc_host *host)
/* This call will also set host->clk_gated to false */
__mmc_set_clock(host, host->clk_old);
}
+
+ DBG("[%s] e\n",__func__);
}
void mmc_set_ungated(struct mmc_host *host)
{
unsigned long flags;
-
+ DBG("[%s] s\n",__func__);
/*
* We've been given a new frequency while the clock is gated,
* so make sure we regard this as ungating it.
@@ -802,6 +879,8 @@ void mmc_set_ungated(struct mmc_host *host)
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_gated = false;
spin_unlock_irqrestore(&host->clk_lock, flags);
+
+ DBG("[%s] e\n",__func__);
}
#else
@@ -815,10 +894,14 @@ void mmc_set_ungated(struct mmc_host *host)
*/
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
+ DBG("[%s] s\n",__func__);
+
mmc_host_clk_hold(host);
host->ios.bus_mode = mode;
mmc_set_ios(host);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -826,10 +909,14 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
+ DBG("[%s] s\n",__func__);
+
mmc_host_clk_hold(host);
host->ios.bus_width = width;
mmc_set_ios(host);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
/**
@@ -852,19 +939,28 @@ static int mmc_vdd_to_ocrbitnum(int vdd, bool low_bits)
const int max_bit = ilog2(MMC_VDD_35_36);
int bit;
- if (vdd < 1650 || vdd > 3600)
+ DBG("[%s] s\n",__func__);
+
+ if (vdd < 1650 || vdd > 3600) {
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
+ }
- if (vdd >= 1650 && vdd <= 1950)
+ if (vdd >= 1650 && vdd <= 1950) {
+ DBG("[%s] e2\n",__func__);
return ilog2(MMC_VDD_165_195);
+ }
if (low_bits)
vdd -= 1;
/* Base 2000 mV, step 100 mV, bit's base 8. */
bit = (vdd - 2000) / 100 + 8;
- if (bit > max_bit)
+ if (bit > max_bit) {
+ DBG("[%s] e3\n",__func__);
return max_bit;
+ }
+ DBG("[%s] e4\n",__func__);
return bit;
}
@@ -885,23 +981,32 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
{
u32 mask = 0;
- if (vdd_max < vdd_min)
+ DBG("[%s] s\n",__func__);
+
+ if (vdd_max < vdd_min) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
/* Prefer high bits for the boundary vdd_max values. */
vdd_max = mmc_vdd_to_ocrbitnum(vdd_max, false);
- if (vdd_max < 0)
+ if (vdd_max < 0) {
+ DBG("[%s] e2\n",__func__);
return 0;
+ }
/* Prefer low bits for the boundary vdd_min values. */
vdd_min = mmc_vdd_to_ocrbitnum(vdd_min, true);
- if (vdd_min < 0)
+ if (vdd_min < 0) {
+ DBG("[%s] e3\n",__func__);
return 0;
+ }
/* Fill the mask, from max bit to min bit. */
while (vdd_max >= vdd_min)
mask |= 1 << vdd_max--;
+ DBG("[%s] e4\n",__func__);
return mask;
}
EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
@@ -923,9 +1028,13 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
int count;
int i;
+ DBG("[%s] s\n",__func__);
+
count = regulator_count_voltages(supply);
- if (count < 0)
+ if (count < 0) {
+ DBG("[%s] e1\n",__func__);
return count;
+ }
for (i = 0; i < count; i++) {
int vdd_uV;
@@ -939,6 +1048,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
}
+ DBG("[%s] e2\n",__func__);
return result;
}
EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
@@ -962,6 +1072,8 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
int result = 0;
int min_uV, max_uV;
+ DBG("[%s] s\n",__func__);
+
if (vdd_bit) {
int tmp;
int voltage;
@@ -1009,6 +1121,8 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
if (result)
dev_err(mmc_dev(mmc),
"could not set regulator OCR (%d)\n", result);
+
+ DBG("[%s] e\n",__func__);
return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);
@@ -1023,6 +1137,8 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
int bit;
+ DBG("[%s] s\n",__func__);
+
ocr &= host->ocr_avail;
bit = ffs(ocr);
@@ -1041,6 +1157,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
ocr = 0;
}
+ DBG("[%s] e\n",__func__);
return ocr;
}
@@ -1049,6 +1166,8 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
struct mmc_command cmd = {0};
int err = 0;
+ DBG("[%s] s\n",__func__);
+
BUG_ON(!host);
/*
@@ -1061,11 +1180,15 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
+ if (err) {
+ DBG("[%s] e1\n",__func__);
return err;
+ }
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
+ DBG("[%s] e2\n",__func__);
return -EIO;
+ }
}
host->ios.signal_voltage = signal_voltage;
@@ -1075,7 +1198,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
err = host->ops->start_signal_voltage_switch(host, &host->ios);
mmc_host_clk_release(host);
}
-
+ DBG("[%s] e3\n",__func__);
return err;
}
@@ -1084,10 +1207,14 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
*/
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
+ DBG("[%s] s\n",__func__);
+
mmc_host_clk_hold(host);
host->ios.timing = timing;
mmc_set_ios(host);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1095,10 +1222,14 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
*/
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
{
+ DBG("[%s] s\n",__func__);
+
mmc_host_clk_hold(host);
host->ios.drv_type = drv_type;
mmc_set_ios(host);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
static void mmc_poweroff_notify(struct mmc_host *host)
@@ -1107,6 +1238,8 @@ static void mmc_poweroff_notify(struct mmc_host *host)
unsigned int timeout;
unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
int err = 0;
+
+ DBG("[%s] s\n",__func__);
card = host->card;
mmc_claim_host(host);
@@ -1141,6 +1274,8 @@ static void mmc_poweroff_notify(struct mmc_host *host)
card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
}
mmc_release_host(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1157,6 +1292,8 @@ static void mmc_poweroff_notify(struct mmc_host *host)
static void mmc_power_up(struct mmc_host *host)
{
int bit;
+
+ DBG("[%s] s\n",__func__);
mmc_host_clk_hold(host);
@@ -1195,11 +1332,14 @@ static void mmc_power_up(struct mmc_host *host)
mmc_delay(10);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
void mmc_power_off(struct mmc_host *host)
{
int err = 0;
+ DBG("[%s] s\n",__func__);
mmc_host_clk_hold(host);
host->ios.clock = 0;
@@ -1245,6 +1385,8 @@ void mmc_power_off(struct mmc_host *host)
mmc_delay(1);
mmc_host_clk_release(host);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1252,11 +1394,14 @@ void mmc_power_off(struct mmc_host *host)
*/
static void __mmc_release_bus(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
BUG_ON(!host);
BUG_ON(host->bus_refs);
BUG_ON(!host->bus_dead);
host->bus_ops = NULL;
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1265,10 +1410,13 @@ static void __mmc_release_bus(struct mmc_host *host)
static inline void mmc_bus_get(struct mmc_host *host)
{
unsigned long flags;
-
+ DBG("[%s] s\n",__func__);
+
spin_lock_irqsave(&host->lock, flags);
host->bus_refs++;
spin_unlock_irqrestore(&host->lock, flags);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1278,20 +1426,26 @@ static inline void mmc_bus_get(struct mmc_host *host)
static inline void mmc_bus_put(struct mmc_host *host)
{
unsigned long flags;
+ DBG("[%s] s\n",__func__);
spin_lock_irqsave(&host->lock, flags);
host->bus_refs--;
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
spin_unlock_irqrestore(&host->lock, flags);
+
+ DBG("[%s] e\n",__func__);
}
int mmc_resume_bus(struct mmc_host *host)
{
unsigned long flags;
-
- if (!mmc_bus_needs_resume(host))
+ DBG("[%s] s\n",__func__);
+
+ if (!mmc_bus_needs_resume(host)) {
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
+ }
printk("%s: Starting deferred resume\n", mmc_hostname(host));
spin_lock_irqsave(&host->lock, flags);
@@ -1311,6 +1465,7 @@ int mmc_resume_bus(struct mmc_host *host)
mmc_bus_put(host);
printk("%s: Deferred resume completed\n", mmc_hostname(host));
+ DBG("[%s] e2\n",__func__);
return 0;
}
@@ -1324,6 +1479,8 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
+ DBG("[%s] s\n",__func__);
+
BUG_ON(!host);
BUG_ON(!ops);
@@ -1339,6 +1496,8 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
host->bus_dead = 0;
spin_unlock_irqrestore(&host->lock, flags);
+
+ DBG("[%s] e\n",__func__);
}
/*
@@ -1348,6 +1507,8 @@ void mmc_detach_bus(struct mmc_host *host)
{
unsigned long flags;
+ DBG("[%s] s\n",__func__);
+
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -1360,6 +1521,8 @@ void mmc_detach_bus(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
mmc_bus_put(host);
+
+ DBG("[%s] e\n",__func__);
}
/**
@@ -1374,6 +1537,8 @@ void mmc_detach_bus(struct mmc_host *host)
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
+ DBG("[%s] s\n",__func__);
+
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
@@ -1384,6 +1549,8 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
wake_lock(&host->detect_wake_lock);
mmc_schedule_delayed_work(&host->detect, delay);
+
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_detect_change);
@@ -1392,6 +1559,8 @@ void mmc_init_erase(struct mmc_card *card)
{
unsigned int sz;
+ DBG("[%s] s\n",__func__);
+
if (is_power_of_2(card->erase_size))
card->erase_shift = ffs(card->erase_size) - 1;
else
@@ -1435,6 +1604,8 @@ void mmc_init_erase(struct mmc_card *card)
card->pref_erase += card->erase_size - sz;
}
}
+
+ DBG("[%s] e\n",__func__);
}
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
@@ -1442,6 +1613,8 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
{
unsigned int erase_timeout;
+ DBG("[%s] s\n",__func__);
+
if (arg == MMC_DISCARD_ARG ||
(arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) {
erase_timeout = card->ext_csd.trim_timeout;
@@ -1498,6 +1671,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
erase_timeout = 1000;
+ DBG("[%s] e\n",__func__);
return erase_timeout;
}
@@ -1507,6 +1681,8 @@ static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
{
unsigned int erase_timeout;
+ DBG("[%s] s\n",__func__);
+
if (card->ssr.erase_timeout) {
/* Erase timeout specified in SD Status Register (SSR) */
erase_timeout = card->ssr.erase_timeout * qty +
@@ -1523,6 +1699,7 @@ static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
if (erase_timeout < 1000)
erase_timeout = 1000;
+ DBG("[%s] e\n",__func__);
return erase_timeout;
}
@@ -1530,10 +1707,22 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
unsigned int arg,
unsigned int qty)
{
- if (mmc_card_sd(card))
- return mmc_sd_erase_timeout(card, arg, qty);
- else
- return mmc_mmc_erase_timeout(card, arg, qty);
+ unsigned int ret;
+
+ DBG("[%s] s\n",__func__);
+
+ if (mmc_card_sd(card)) {
+ ret = mmc_sd_erase_timeout(card, arg, qty);
+ /*return mmc_sd_erase_timeout(card, arg, qty);*/
+ DBG("[%s] e1\n",__func__);
+ return ret;
+ } else {
+ ret = mmc_mmc_erase_timeout(card, arg, qty);
+ /*return mmc_mmc_erase_timeout(card, arg, qty);*/
+ DBG("[%s] e2\n",__func__);
+ return ret;
+ }
+
}
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
@@ -1543,6 +1732,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int qty = 0;
int err;
+ DBG("[%s] s\n",__func__);
/*
* qty is used to calculate the erase timeout which depends on how many
* erase groups (or allocation units in SD terminology) are affected.
@@ -1578,7 +1768,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
else
cmd.opcode = MMC_ERASE_GROUP_START;
cmd.arg = from;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
pr_err("mmc_erase: group start error %d, "
@@ -1593,7 +1784,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
else
cmd.opcode = MMC_ERASE_GROUP_END;
cmd.arg = to;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
pr_err("mmc_erase: group end error %d, status %#x\n",
@@ -1605,7 +1797,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_ERASE;
cmd.arg = arg;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
@@ -1650,28 +1843,43 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
unsigned int arg)
{
unsigned int rem, to = from + nr;
+ int ret;
+
+ DBG("[%s] s\n",__func__);
if (!(card->host->caps & MMC_CAP_ERASE) ||
- !(card->csd.cmdclass & CCC_ERASE))
+ !(card->csd.cmdclass & CCC_ERASE)) {
+ DBG("[%s] e1\n",__func__);
return -EOPNOTSUPP;
+ }
- if (!card->erase_size)
+ if (!card->erase_size) {
+ DBG("[%s] e2\n",__func__);
return -EOPNOTSUPP;
+ }
- if (mmc_card_sd(card) && arg != MMC_ERASE_ARG)
+ if (mmc_card_sd(card) && arg != MMC_ERASE_ARG) {
+ DBG("[%s] e3\n",__func__);
return -EOPNOTSUPP;
+ }
if ((arg & MMC_SECURE_ARGS) &&
- !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
+ !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)) {
+ DBG("[%s] e4\n",__func__);
return -EOPNOTSUPP;
+ }
if ((arg & MMC_TRIM_ARGS) &&
- !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
+ !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)) {
+ DBG("[%s] e5\n",__func__);
return -EOPNOTSUPP;
+ }
if (arg == MMC_SECURE_ERASE_ARG) {
- if (from % card->erase_size || nr % card->erase_size)
+ if (from % card->erase_size || nr % card->erase_size) {
+ DBG("[%s] e6\n",__func__);
return -EINVAL;
+ }
}
if (arg == MMC_ERASE_ARG) {
@@ -1681,72 +1889,107 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
from += rem;
if (nr > rem)
nr -= rem;
- else
+ else {
+ DBG("[%s] e7\n",__func__);
return 0;
+ }
}
rem = nr % card->erase_size;
if (rem)
nr -= rem;
}
- if (nr == 0)
+ if (nr == 0) {
+ DBG("[%s] e8\n",__func__);
return 0;
+ }
to = from + nr;
- if (to <= from)
+ if (to <= from) {
+ DBG("[%s] e9\n",__func__);
return -EINVAL;
+ }
/* 'from' and 'to' are inclusive */
to -= 1;
- return mmc_do_erase(card, from, to, arg);
+ ret = mmc_do_erase(card, from, to, arg);
+ DBG("[%s] e10\n",__func__);
+ /*return mmc_do_erase(card, from, to, arg);*/
+ return ret;
}
EXPORT_SYMBOL(mmc_erase);
int mmc_can_erase(struct mmc_card *card)
{
+ DBG("[%s] s\n",__func__);
+
if ((card->host->caps & MMC_CAP_ERASE) &&
- (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
+ (card->csd.cmdclass & CCC_ERASE) && card->erase_size) {
+ DBG("[%s] e1\n",__func__);
return 1;
+ }
+ DBG("[%s] e2\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_can_erase);
int mmc_can_trim(struct mmc_card *card)
{
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
+ DBG("[%s] s\n",__func__);
+
+ if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) {
+ DBG("[%s] e1\n",__func__);
return 1;
+ }
+
+ DBG("[%s] e2\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_can_trim);
int mmc_can_discard(struct mmc_card *card)
{
+ DBG("[%s] s\n",__func__);
/*
* As there's no way to detect the discard support bit at v4.5
* use the s/w feature support filed.
*/
- if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+ if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) {
+ DBG("[%s] e1\n",__func__);
return 1;
+ }
+ DBG("[%s] e2\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_can_discard);
int mmc_can_sanitize(struct mmc_card *card)
{
- if (!mmc_can_trim(card) && !mmc_can_erase(card))
+ DBG("[%s] s\n",__func__);
+ if (!mmc_can_trim(card) && !mmc_can_erase(card)) {
+ DBG("[%s] e1\n",__func__);
return 0;
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+ }
+ if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) {
+ DBG("[%s] e2\n",__func__);
return 1;
+ }
+ DBG("[%s] e3\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_can_sanitize);
int mmc_can_secure_erase_trim(struct mmc_card *card)
{
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
+ DBG("[%s] s\n",__func__);
+
+ if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) {
+ DBG("[%s] e1\n",__func__);
return 1;
+ }
+ DBG("[%s] e2\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_can_secure_erase_trim);
@@ -1754,10 +1997,16 @@ EXPORT_SYMBOL(mmc_can_secure_erase_trim);
int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
unsigned int nr)
{
- if (!card->erase_size)
+ DBG("[%s] s\n",__func__);
+ if (!card->erase_size) {
+ DBG("[%s] e1\n",__func__);
return 0;
- if (from % card->erase_size || nr % card->erase_size)
+ }
+ if (from % card->erase_size || nr % card->erase_size) {
+ DBG("[%s] e2\n",__func__);
return 0;
+ }
+ DBG("[%s] e3\n",__func__);
return 1;
}
EXPORT_SYMBOL(mmc_erase_group_aligned);
@@ -1769,6 +2018,8 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
unsigned int last_timeout = 0;
+ DBG("[%s] s\n",__func__);
+
if (card->erase_shift)
max_qty = UINT_MAX >> card->erase_shift;
else if (mmc_card_sd(card))
@@ -1791,11 +2042,15 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
qty += y;
} while (y);
- if (!qty)
+ if (!qty) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
- if (qty == 1)
+ if (qty == 1) {
+ DBG("[%s] e2\n",__func__);
return 1;
+ }
/* Convert qty to sectors */
if (card->erase_shift)
@@ -1805,6 +2060,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
else
max_discard = --qty * card->erase_size;
+ DBG("[%s] e3\n",__func__);
return max_discard;
}
@@ -1812,17 +2068,21 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
{
struct mmc_host *host = card->host;
unsigned int max_discard, max_trim;
-
- if (!host->max_discard_to)
+ DBG("[%s] s\n",__func__);
+ if (!host->max_discard_to) {
+ DBG("[%s] e1\n",__func__);
return UINT_MAX;
+ }
/*
* Without erase_group_def set, MMC erase timeout depends on clock
* frequence which can change. In that case, the best choice is
* just the preferred erase size.
*/
- if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+ if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1)) {
+ DBG("[%s] e2\n",__func__);
return card->pref_erase;
+ }
max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
if (mmc_can_trim(card)) {
@@ -1834,6 +2094,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
}
pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
mmc_hostname(host), max_discard, host->max_discard_to);
+ DBG("[%s] e3\n",__func__);
return max_discard;
}
EXPORT_SYMBOL(mmc_calc_max_discard);
@@ -1841,35 +2102,57 @@ EXPORT_SYMBOL(mmc_calc_max_discard);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
struct mmc_command cmd = {0};
+ int ret;
+
+ DBG("[%s] s\n",__func__);
- if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+ if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card)) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
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);
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ ret = mmc_wait_for_cmd(card->host, &cmd, 5);
+
+ /*return mmc_wait_for_cmd(card->host, &cmd, 5);*/
+ DBG("[%s] e1\n",__func__);
+ return ret;
}
EXPORT_SYMBOL(mmc_set_blocklen);
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ DBG("[%s] s\n",__func__);
+
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) {
+ DBG("[%s] e1\n",__func__);
return;
+ }
mmc_host_clk_hold(host);
host->ops->hw_reset(host);
mmc_host_clk_release(host);
+ DBG("[%s] e2\n",__func__);
}
int mmc_can_reset(struct mmc_card *card)
{
u8 rst_n_function;
- if (!mmc_card_mmc(card))
+ DBG("[%s] s\n",__func__);
+
+ if (!mmc_card_mmc(card)) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
rst_n_function = card->ext_csd.rst_n_function;
- if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+ if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) {
+ DBG("[%s] e2\n",__func__);
return 0;
+ }
+ DBG("[%s] e3\n",__func__);
return 1;
}
EXPORT_SYMBOL(mmc_can_reset);
@@ -1877,18 +2160,26 @@ EXPORT_SYMBOL(mmc_can_reset);
static int mmc_do_hw_reset(struct mmc_host *host, int check)
{
struct mmc_card *card = host->card;
-
- if (!host->bus_ops->power_restore)
+ DBG("[%s] s\n",__func__);
+ if (!host->bus_ops->power_restore) {
+ DBG("[%s] e1\n",__func__);
return -EOPNOTSUPP;
+ }
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) {
+ DBG("[%s] e2\n",__func__);
return -EOPNOTSUPP;
+ }
- if (!card)
+ if (!card) {
+ DBG("[%s] e3\n",__func__);
return -EINVAL;
-
- if (!mmc_can_reset(card))
+ }
+
+ if (!mmc_can_reset(card)) {
+ DBG("[%s] e4\n",__func__);
return -EOPNOTSUPP;
+ }
mmc_host_clk_hold(host);
mmc_set_clock(host, host->f_init);
@@ -1903,10 +2194,12 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (!err) {
mmc_host_clk_release(host);
+ DBG("[%s] e5\n",__func__);
return -ENOSYS;
}
}
@@ -1924,24 +2217,28 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
mmc_set_ios(host);
mmc_host_clk_release(host);
-
+ DBG("[%s] e6\n",__func__);
return host->bus_ops->power_restore(host);
}
int mmc_hw_reset(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
return mmc_do_hw_reset(host, 0);
}
EXPORT_SYMBOL(mmc_hw_reset);
int mmc_hw_reset_check(struct mmc_host *host)
-{
+{
+ DBG("[%s] s\n",__func__);
return mmc_do_hw_reset(host, 1);
}
EXPORT_SYMBOL(mmc_hw_reset_check);
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
+ DBG("[%s] s\n",__func__);
+
host->f_init = freq;
#ifdef CONFIG_MMC_DEBUG
@@ -1970,33 +2267,45 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
- if (!mmc_attach_sdio(host))
+ if (!mmc_attach_sdio(host)) {
+ DBG("[%s] e1\n",__func__);
return 0;
- if (!mmc_attach_sd(host))
+ }
+ if (!mmc_attach_sd(host)) {
+ DBG("[%s] e2\n",__func__);
return 0;
- if (!mmc_attach_mmc(host))
+ }
+ if (!mmc_attach_mmc(host)) {
+ DBG("[%s] e3\n",__func__);
return 0;
+ }
mmc_power_off(host);
+ DBG("[%s] e4\n",__func__);
return -EIO;
}
int _mmc_detect_card_removed(struct mmc_host *host)
{
int ret;
-
- if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+
+ DBG("[%s] s\n",__func__);
+ if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
- if (!host->card || mmc_card_removed(host->card))
+ if (!host->card || mmc_card_removed(host->card)) {
+ DBG("[%s] e2\n",__func__);
return 1;
+ }
ret = host->bus_ops->alive(host);
if (ret) {
mmc_card_set_removed(host->card);
pr_debug("%s: card remove detected\n", mmc_hostname(host));
}
-
+ DBG("[%s] e3\n",__func__);
return ret;
}
@@ -2004,20 +2313,25 @@ int mmc_detect_card_removed(struct mmc_host *host)
{
struct mmc_card *card = host->card;
int ret;
-
+
+ DBG("[%s] s\n",__func__);
+
WARN_ON(!host->claimed);
- if (!card)
+ if (!card) {
+ DBG("[%s] e1\n",__func__);
return 1;
-
+ }
ret = mmc_card_removed(card);
/*
* The card will be considered unchanged unless we have been asked to
* detect a change or host requires polling to provide card detection.
*/
if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
- !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+ !(host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+ DBG("[%s] e2\n",__func__);
return ret;
+ }
host->detect_change = 0;
if (!ret) {
@@ -2031,7 +2345,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
mmc_detect_change(host, 0);
}
}
-
+ DBG("[%s] e3\n",__func__);
return ret;
}
EXPORT_SYMBOL(mmc_detect_card_removed);
@@ -2043,80 +2357,110 @@ void mmc_rescan(struct work_struct *work)
container_of(work, struct mmc_host, detect.work);
int i;
bool extend_wakelock = false;
+ struct atsmb_host *atsmb_host = mmc_priv(host);
+ int retry = 5;
+
+ DBG("[%s] s\n",__func__);
+ host->card_scan_status = false;
if (host->rescan_disable)
return;
- mmc_bus_get(host);
+ while(retry > 0) {
+ retry--;
+ mmc_bus_get(host);
- /*
- * if there is a _removable_ card registered, check whether it is
- * still present
- */
- if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
- && !(host->caps & MMC_CAP_NONREMOVABLE))
- host->bus_ops->detect(host);
+ /*
+ * if there is a _removable_ card registered, check whether it is
+ * still present
+ */
+ if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+ && !(host->caps & MMC_CAP_NONREMOVABLE))
+ host->bus_ops->detect(host);
- host->detect_change = 0;
+ host->detect_change = 0;
- /* If the card was removed the bus will be marked
- * as dead - extend the wakelock so userspace
- * can respond */
- if (host->bus_dead)
- extend_wakelock = 1;
+ /* If the card was removed the bus will be marked
+ * as dead - extend the wakelock so userspace
+ * can respond */
+ if (host->bus_dead)
+ extend_wakelock = 1;
- /*
- * Let mmc_bus_put() free the bus/bus_ops if we've found that
- * the card is no longer present.
- */
- mmc_bus_put(host);
- mmc_bus_get(host);
+ /*
+ * Let mmc_bus_put() free the bus/bus_ops if we've found that
+ * the card is no longer present.
+ */
+ mmc_bus_put(host);
+ mmc_bus_get(host);
- /* if there still is a card present, stop here */
- if (host->bus_ops != NULL) {
+ /* if there still is a card present, stop here */
+ if (host->bus_ops != NULL) {
+ mmc_bus_put(host);
+ goto out;
+ }
+
+ /*
+ * Only we can add a new handler, so it's safe to
+ * release the lock here.
+ */
mmc_bus_put(host);
- goto out;
- }
- /*
- * Only we can add a new handler, so it's safe to
- * release the lock here.
- */
- mmc_bus_put(host);
+ if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+ goto out;
- if (host->ops->get_cd && host->ops->get_cd(host) == 0)
- goto out;
+ mmc_claim_host(host);
+ for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+ if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
+ extend_wakelock = true;
+ break;
+ }
+ if (freqs[i] <= host->f_min)
+ break;
+ }
+ mmc_release_host(host);
- mmc_claim_host(host);
- for (i = 0; i < ARRAY_SIZE(freqs); i++) {
- if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
- extend_wakelock = true;
- break;
+ out:
+ if (extend_wakelock)
+ wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
+ else
+ wake_unlock(&host->detect_wake_lock);
+ if (host->caps & MMC_CAP_NEEDS_POLL) {
+ wake_lock(&host->detect_wake_lock);
+ mmc_schedule_delayed_work(&host->detect, HZ);
}
- if (freqs[i] <= host->f_min)
+
+ DBG("[%s]retry = %d slot = %x power = %x\n",
+ __func__,retry,host->ops->get_slot_status(host),
+ host->ios.power_mode);
+
+ if((host->ops->get_slot_status(host) == 0) ||
+ (host->ios.power_mode != MMC_POWER_OFF))
break;
- }
- mmc_release_host(host);
- out:
- if (extend_wakelock)
- wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
- else
- wake_unlock(&host->detect_wake_lock);
- if (host->caps & MMC_CAP_NEEDS_POLL) {
- wake_lock(&host->detect_wake_lock);
- mmc_schedule_delayed_work(&host->detect, HZ);
+ msleep(1000);
+
}
+ if (host->ios.power_mode != MMC_POWER_OFF)
+ host->card_scan_status = true;
+ printk("SD%d Host Clock %dHz\n",host->wmt_host_index, atsmb_host->current_clock);
+
+ DBG("[%s] e\n",__func__);
}
-void mmc_start_host(struct mmc_host *host)
+void mmc_start_host(struct mmc_host *host,bool detect)
{
+ DBG("[%s] s\n",__func__);
+
mmc_power_off(host);
- mmc_detect_change(host, 0);
+ if (detect == true)
+ mmc_detect_change(host, 0);
+
+ DBG("[%s] e\n",__func__);
}
void mmc_stop_host(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
@@ -2142,6 +2486,7 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
mmc_release_host(host);
mmc_bus_put(host);
+ DBG("[%s] e1\n",__func__);
return;
}
mmc_bus_put(host);
@@ -2149,12 +2494,16 @@ void mmc_stop_host(struct mmc_host *host)
BUG_ON(host->card);
mmc_power_off(host);
+
+ DBG("[%s] e2\n",__func__);
}
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
+ DBG("[%s] s\n",__func__);
+
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: powering down\n", mmc_hostname(host), __func__);
#endif
@@ -2163,6 +2512,7 @@ int mmc_power_save_host(struct mmc_host *host)
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
mmc_bus_put(host);
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
}
@@ -2173,6 +2523,7 @@ int mmc_power_save_host(struct mmc_host *host)
mmc_power_off(host);
+ DBG("[%s] e2\n",__func__);
return ret;
}
EXPORT_SYMBOL(mmc_power_save_host);
@@ -2181,6 +2532,8 @@ int mmc_power_restore_host(struct mmc_host *host)
{
int ret;
+ DBG("[%s] s\n",__func__);
+
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: powering up\n", mmc_hostname(host), __func__);
#endif
@@ -2189,6 +2542,7 @@ int mmc_power_restore_host(struct mmc_host *host)
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
mmc_bus_put(host);
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
}
@@ -2196,7 +2550,7 @@ int mmc_power_restore_host(struct mmc_host *host)
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
-
+ DBG("[%s] e2\n",__func__);
return ret;
}
EXPORT_SYMBOL(mmc_power_restore_host);
@@ -2205,8 +2559,12 @@ int mmc_card_awake(struct mmc_host *host)
{
int err = -ENOSYS;
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ DBG("[%s] s\n",__func__);
+
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
mmc_bus_get(host);
@@ -2214,7 +2572,8 @@ int mmc_card_awake(struct mmc_host *host)
err = host->bus_ops->awake(host);
mmc_bus_put(host);
-
+
+ DBG("[%s] e2\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_card_awake);
@@ -2223,8 +2582,12 @@ int mmc_card_sleep(struct mmc_host *host)
{
int err = -ENOSYS;
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ DBG("[%s] s\n",__func__);
+
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
mmc_bus_get(host);
@@ -2233,6 +2596,7 @@ int mmc_card_sleep(struct mmc_host *host)
mmc_bus_put(host);
+ DBG("[%s] e2\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_card_sleep);
@@ -2241,8 +2605,13 @@ int mmc_card_can_sleep(struct mmc_host *host)
{
struct mmc_card *card = host->card;
- if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
+ DBG("[%s] s\n",__func__);
+ if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3) {
+ DBG("[%s] e1\n",__func__);
return 1;
+ }
+
+ DBG("[%s] e2\n",__func__);
return 0;
}
EXPORT_SYMBOL(mmc_card_can_sleep);
@@ -2254,9 +2623,12 @@ int mmc_flush_cache(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int err = 0;
+ DBG("[%s] s\n",__func__);
- if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+ if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) {
+ DBG("[%s] e1\n",__func__);
return err;
+ }
if (mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0) &&
@@ -2267,7 +2639,7 @@ int mmc_flush_cache(struct mmc_card *card)
pr_err("%s: cache flush error %d\n",
mmc_hostname(card->host), err);
}
-
+ DBG("[%s] e2\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_flush_cache);
@@ -2282,10 +2654,14 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
struct mmc_card *card = host->card;
unsigned int timeout;
int err = 0;
+
+ DBG("[%s] s\n",__func__);
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
- mmc_card_is_removable(host))
+ mmc_card_is_removable(host)) {
+ DBG("[%s] e1\n",__func__);
return err;
+ }
mmc_claim_host(host);
if (card && mmc_card_mmc(card) &&
@@ -2306,7 +2682,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
}
}
mmc_release_host(host);
-
+ DBG("[%s] e2\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_cache_ctrl);
@@ -2321,8 +2697,12 @@ int mmc_suspend_host(struct mmc_host *host)
{
int err = 0;
- if (mmc_bus_needs_resume(host))
+ DBG("[%s] s\n",__func__);
+
+ if (mmc_bus_needs_resume(host)) {
+ DBG("[%s] e1\n",__func__);
return 0;
+ }
if (cancel_delayed_work(&host->detect))
wake_unlock(&host->detect_wake_lock);
@@ -2361,6 +2741,7 @@ int mmc_suspend_host(struct mmc_host *host)
mmc_power_off(host);
out:
+ DBG("[%s] e2\n",__func__);
return err;
}
@@ -2374,10 +2755,13 @@ int mmc_resume_host(struct mmc_host *host)
{
int err = 0;
+ DBG("[%s] s\n",__func__);
+
mmc_bus_get(host);
if (mmc_bus_manual_resume(host)) {
host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
mmc_bus_put(host);
+ DBG("[%s] e1\n",__func__);
return 0;
}
@@ -2398,6 +2782,9 @@ int mmc_resume_host(struct mmc_host *host)
pm_runtime_enable(&host->card->dev);
}
}
+ //kevin add for suspend&resume
+ mmc_set_ios(host);
+
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
if (err) {
@@ -2409,7 +2796,7 @@ int mmc_resume_host(struct mmc_host *host)
}
host->pm_flags &= ~MMC_PM_KEEP_POWER;
mmc_bus_put(host);
-
+ DBG("[%s] e2\n",__func__);
return err;
}
EXPORT_SYMBOL(mmc_resume_host);
@@ -2425,6 +2812,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
+ DBG("[%s] s\n",__func__);
switch (mode) {
case PM_HIBERNATION_PREPARE:
@@ -2467,14 +2855,37 @@ int mmc_pm_notify(struct notifier_block *notify_block,
host->rescan_disable = 0;
host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
spin_unlock_irqrestore(&host->lock, flags);
- mmc_detect_change(host, 0);
+ if(!(host->bus_dead))
+ mmc_detect_change(host, 0);
}
-
+ DBG("[%s] e\n",__func__);
return 0;
}
#endif
+void mmc_force_remove_card(struct mmc_host *host)
+{
+ DBG("[%s] s\n",__func__);
+ mmc_bus_get(host);
+
+ if (host->bus_ops && !host->bus_dead) {
+
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ }
+ mmc_bus_put(host);
+ mmc_power_off(host);
+ DBG("[%s] e\n",__func__);
+ return ;
+}
+EXPORT_SYMBOL(mmc_force_remove_card);
+
+
#ifdef CONFIG_MMC_EMBEDDED_SDIO
void mmc_set_embedded_sdio_data(struct mmc_host *host,
struct sdio_cis *cis,
@@ -2482,10 +2893,12 @@ void mmc_set_embedded_sdio_data(struct mmc_host *host,
struct sdio_embedded_func *funcs,
int num_funcs)
{
+ DBG("[%s] s\n",__func__);
host->embedded_sdio_data.cis = cis;
host->embedded_sdio_data.cccr = cccr;
host->embedded_sdio_data.funcs = funcs;
host->embedded_sdio_data.num_funcs = num_funcs;
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
@@ -2495,9 +2908,13 @@ static int __init mmc_init(void)
{
int ret;
+ DBG("[%s] s\n",__func__);
+
workqueue = alloc_ordered_workqueue("kmmcd", 0);
- if (!workqueue)
+ if (!workqueue) {
+ DBG("[%s] e1\n",__func__);
return -ENOMEM;
+ }
ret = mmc_register_bus();
if (ret)
@@ -2511,6 +2928,7 @@ static int __init mmc_init(void)
if (ret)
goto unregister_host_class;
+ DBG("[%s] e2\n",__func__);
return 0;
unregister_host_class:
@@ -2520,15 +2938,18 @@ unregister_bus:
destroy_workqueue:
destroy_workqueue(workqueue);
+ DBG("[%s] e3\n",__func__);
return ret;
}
static void __exit mmc_exit(void)
{
+ DBG("[%s] s\n",__func__);
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
+ DBG("[%s] e\n",__func__);
}
subsys_initcall(mmc_init);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/core.h b/ANDROID_3.4.5/drivers/mmc/core/core.h
index 3bdafbca..1e26016a 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/core.h
+++ b/ANDROID_3.4.5/drivers/mmc/core/core.h
@@ -57,7 +57,7 @@ static inline void mmc_delay(unsigned int ms)
}
void mmc_rescan(struct work_struct *work);
-void mmc_start_host(struct mmc_host *host);
+void mmc_start_host(struct mmc_host *host, bool detect);
void mmc_stop_host(struct mmc_host *host);
int _mmc_detect_card_removed(struct mmc_host *host);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/host.c b/ANDROID_3.4.5/drivers/mmc/core/host.c
index dd7b1203..37384d1c 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/host.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/host.c
@@ -29,10 +29,19 @@
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
+
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ DBG("[%s] s\n",__func__);
kfree(host);
+ DBG("[%s] e\n",__func__);
}
static struct class mmc_host_class = {
@@ -42,12 +51,20 @@ static struct class mmc_host_class = {
int mmc_register_host_class(void)
{
- return class_register(&mmc_host_class);
+ int ret;
+
+ DBG("[%s] s\n",__func__);
+ ret = class_register(&mmc_host_class);
+ DBG("[%s] e\n",__func__);
+ //return class_register(&mmc_host_class);
+ return ret;
}
void mmc_unregister_host_class(void)
{
+ DBG("[%s] s\n",__func__);
class_unregister(&mmc_host_class);
+ DBG("[%s] e\n",__func__);
}
static DEFINE_IDR(mmc_host_idr);
@@ -58,6 +75,7 @@ static ssize_t clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ DBG("[%s] s\n",__func__);
return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
}
@@ -67,12 +85,17 @@ static ssize_t clkgate_delay_store(struct device *dev,
struct mmc_host *host = cls_dev_to_mmc_host(dev);
unsigned long flags, value;
- if (kstrtoul(buf, 0, &value))
+ DBG("[%s] s\n",__func__);
+
+ if (kstrtoul(buf, 0, &value)) {
+ DBG("[%s] e1\n",__func__);
return -EINVAL;
+ }
spin_lock_irqsave(&host->clk_lock, flags);
host->clkgate_delay = value;
spin_unlock_irqrestore(&host->clk_lock, flags);
+ DBG("[%s] e2\n",__func__);
return count;
}
@@ -89,10 +112,13 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
unsigned long freq = host->ios.clock;
unsigned long flags;
+ DBG("[%s] s\n",__func__);
+
if (!freq) {
pr_debug("%s: frequency set to 0 in disable function, "
"this means the clock is already disabled.\n",
mmc_hostname(host));
+ DBG("[%s] e1\n",__func__);
return;
}
/*
@@ -114,6 +140,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
} else {
/* New users appeared while waiting for this work */
spin_unlock_irqrestore(&host->clk_lock, flags);
+ DBG("[%s] e2\n",__func__);
return;
}
mutex_lock(&host->clk_gate_mutex);
@@ -127,6 +154,8 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
}
spin_unlock_irqrestore(&host->clk_lock, flags);
mutex_unlock(&host->clk_gate_mutex);
+
+ DBG("[%s] e3\n",__func__);
}
/*
@@ -136,8 +165,9 @@ static void mmc_host_clk_gate_work(struct work_struct *work)
{
struct mmc_host *host = container_of(work, struct mmc_host,
clk_gate_work.work);
-
+ DBG("[%s] s\n",__func__);
mmc_host_clk_gate_delayed(host);
+ DBG("[%s] e\n",__func__);
}
/**
@@ -151,7 +181,8 @@ static void mmc_host_clk_gate_work(struct work_struct *work)
void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
-
+ DBG("[%s] s\n",__func__);
+
/* cancel any clock gating work scheduled by mmc_host_clk_release() */
cancel_delayed_work_sync(&host->clk_gate_work);
mutex_lock(&host->clk_gate_mutex);
@@ -165,6 +196,7 @@ void mmc_host_clk_hold(struct mmc_host *host)
host->clk_requests++;
spin_unlock_irqrestore(&host->clk_lock, flags);
mutex_unlock(&host->clk_gate_mutex);
+ DBG("[%s] e\n",__func__);
}
/**
@@ -173,9 +205,12 @@ void mmc_host_clk_hold(struct mmc_host *host)
*/
static bool mmc_host_may_gate_card(struct mmc_card *card)
{
+ DBG("[%s] s\n",__func__);
/* If there is no card we may gate it */
- if (!card)
+ if (!card) {
+ DBG("[%s] e1\n",__func__);
return true;
+ }
/*
* Don't gate SDIO cards! These need to be clocked at all times
* since they may be independent systems generating interrupts
@@ -184,6 +219,7 @@ static bool mmc_host_may_gate_card(struct mmc_card *card)
* gate the clock, because there is somebody out there that may still
* be using it.
*/
+ DBG("[%s] e2\n",__func__);
return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
}
@@ -198,6 +234,7 @@ static bool mmc_host_may_gate_card(struct mmc_card *card)
void mmc_host_clk_release(struct mmc_host *host)
{
unsigned long flags;
+ DBG("[%s] s\n",__func__);
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_requests--;
@@ -206,6 +243,8 @@ void mmc_host_clk_release(struct mmc_host *host)
queue_delayed_work(system_nrt_wq, &host->clk_gate_work,
msecs_to_jiffies(host->clkgate_delay));
spin_unlock_irqrestore(&host->clk_lock, flags);
+
+ DBG("[%s] e\n",__func__);
}
/**
@@ -218,6 +257,7 @@ unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
unsigned long freq;
unsigned long flags;
+ DBG("[%s] s\n",__func__);
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated)
@@ -225,6 +265,8 @@ unsigned int mmc_host_clk_rate(struct mmc_host *host)
else
freq = host->ios.clock;
spin_unlock_irqrestore(&host->clk_lock, flags);
+
+ DBG("[%s] e\n",__func__);
return freq;
}
@@ -234,6 +276,7 @@ unsigned int mmc_host_clk_rate(struct mmc_host *host)
*/
static inline void mmc_host_clk_init(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
host->clk_requests = 0;
/* Hold MCI clock for 8 cycles by default */
host->clk_delay = 8;
@@ -246,6 +289,7 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
spin_lock_init(&host->clk_lock);
mutex_init(&host->clk_gate_mutex);
+ DBG("[%s] e\n",__func__);
}
/**
@@ -254,6 +298,7 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
*/
static inline void mmc_host_clk_exit(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
/*
* Wait for any outstanding gate and then make sure we're
* ungated before exiting.
@@ -264,6 +309,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
mmc_host_clk_hold(host);
/* There should be only one user now */
WARN_ON(host->clk_requests > 1);
+ DBG("[%s] e\n",__func__);
}
static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
@@ -304,13 +350,18 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
struct mmc_host *host;
+ DBG("[%s] s\n",__func__);
- if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
+ if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) {
+ DBG("[%s] e1\n",__func__);
return NULL;
+ }
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
- if (!host)
+ if (!host) {
+ DBG("[%s] e2\n",__func__);
return NULL;
+ }
spin_lock(&mmc_host_lock);
err = idr_get_new(&mmc_host_idr, host, &host->index);
@@ -347,10 +398,12 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->max_blk_size = 512;
host->max_blk_count = PAGE_CACHE_SIZE / 512;
+ DBG("[%s] e3\n",__func__);
return host;
free:
kfree(host);
+ DBG("[%s] e4\n",__func__);
return NULL;
}
@@ -364,16 +417,18 @@ EXPORT_SYMBOL(mmc_alloc_host);
* prepared to start servicing requests before this function
* completes.
*/
-int mmc_add_host(struct mmc_host *host)
+int mmc_add_host(struct mmc_host *host, bool detect)
{
int err;
-
+ DBG("[%s] s\n",__func__);
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
err = device_add(&host->class_dev);
- if (err)
+ if (err) {
+ DBG("[%s] e1\n",__func__);
return err;
+ }
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
@@ -382,10 +437,11 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_host_clk_sysfs_init(host);
- mmc_start_host(host);
+ mmc_start_host(host, detect);
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
register_pm_notifier(&host->pm_notify);
+ DBG("[%s] e2\n",__func__);
return 0;
}
@@ -401,6 +457,7 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
unregister_pm_notifier(&host->pm_notify);
@@ -415,6 +472,7 @@ void mmc_remove_host(struct mmc_host *host)
led_trigger_unregister_simple(host->led);
mmc_host_clk_exit(host);
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_remove_host);
@@ -427,12 +485,14 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
+ DBG("[%s] s\n",__func__);
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
wake_lock_destroy(&host->detect_wake_lock);
put_device(&host->class_dev);
+ DBG("[%s] e\n",__func__);
}
EXPORT_SYMBOL(mmc_free_host);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/mmc.c b/ANDROID_3.4.5/drivers/mmc/core/mmc.c
index 54df5adc..0eb26c64 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/mmc.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/mmc.c
@@ -1320,7 +1320,17 @@ static void mmc_detect(struct mmc_host *host)
err = _mmc_detect_card_removed(host);
mmc_release_host(host);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ if (err || (host->card_attath_status == card_attach_status_change)) {
+ host->card_attath_status = card_attach_status_unchange;
+ mmc_remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+ }
+#else
if (err) {
mmc_remove(host);
@@ -1329,6 +1339,7 @@ static void mmc_detect(struct mmc_host *host)
mmc_power_off(host);
mmc_release_host(host);
}
+#endif
}
/*
@@ -1375,6 +1386,11 @@ static int mmc_resume(struct mmc_host *host)
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ if (err)
+ host->card_attath_status = card_attach_status_change;
+#endif
+
return err;
}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c b/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c
index 69370f49..cdd16e5e 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c
@@ -112,8 +112,9 @@ int mmc_go_idle(struct mmc_host *host)
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
-
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
+ cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+
err = mmc_wait_for_cmd(host, &cmd, 0);
mmc_delay(1);
@@ -137,7 +138,8 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -258,8 +260,9 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
data.blksz = len;
data.blocks = 1;
data.flags = MMC_DATA_READ;
@@ -392,7 +395,8 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.cmd_timeout_ms = timeout_ms;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
@@ -436,7 +440,8 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@@ -496,7 +501,8 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = len;
data.blocks = 1;
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd.c b/ANDROID_3.4.5/drivers/mmc/core/sd.c
index 7c76a455..5dbafd8e 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/sd.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/sd.c
@@ -1100,6 +1100,16 @@ static void mmc_sd_detect(struct mmc_host *host)
#endif
mmc_release_host(host);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ if (err || (host->card_attath_status == card_attach_status_change)) {
+ host->card_attath_status = card_attach_status_unchange;
+ mmc_sd_remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+ }
+#else
if (err) {
mmc_sd_remove(host);
@@ -1108,6 +1118,7 @@ static void mmc_sd_detect(struct mmc_host *host)
mmc_power_off(host);
mmc_release_host(host);
}
+#endif
}
/*
@@ -1163,6 +1174,11 @@ static int mmc_sd_resume(struct mmc_host *host)
#endif
mmc_release_host(host);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ if (err)
+ host->card_attath_status = card_attach_status_change;
+#endif
+
return err;
}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c b/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c
index 274ef00b..e01d12a3 100644
--- a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c
+++ b/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c
@@ -34,10 +34,12 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
if (card) {
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
}
err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -159,7 +161,8 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
else
cmd.arg = ocr;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+ 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);
@@ -204,7 +207,8 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
- cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
+ //cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
@@ -273,7 +277,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 8;
data.blocks = 1;
@@ -324,7 +329,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
cmd.arg = mode << 31 | 0x00FFFFFF;
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 64;
data.blocks = 1;
@@ -369,7 +375,8 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
cmd.opcode = SD_APP_SD_STATUS;
cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 64;
data.blocks = 1;
diff --git a/ANDROID_3.4.5/drivers/mmc/host/Kconfig b/ANDROID_3.4.5/drivers/mmc/host/Kconfig
index 2bc06e73..e7b73ea5 100644
--- a/ANDROID_3.4.5/drivers/mmc/host/Kconfig
+++ b/ANDROID_3.4.5/drivers/mmc/host/Kconfig
@@ -619,3 +619,28 @@ config MMC_USHC
Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards.
+
+config MMC_ATSMB
+ tristate "WonderMedia ATSMB(AHB To MMC/SD BUS)"
+ help
+ This selects the WMT Secure digital and Multimedia card Interface.
+ If you have a machine with WonderMedia ATSMB, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_ATSMB1
+ tristate "WonderMedia ATSMB1(AHB To MMC/SD1 BUS)"
+ help
+ This selects the WMT Secure digital and Multimedia card Interface.
+ If you have a machine with WonderMedia ATSMB1, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_ATSMB2
+ tristate "WonderMedia ATSMB2(AHB To MMC/SD2 BUS)"
+ help
+ This selects the WMT Secure digital and Multimedia card Interface.
+ If you have a machine with WonderMedia ATSMB2, say Y or M here.
+
+ If unsure, say N.
+
diff --git a/ANDROID_3.4.5/drivers/mmc/host/Makefile b/ANDROID_3.4.5/drivers/mmc/host/Makefile
index 3e7e26d0..b46a087b 100644
--- a/ANDROID_3.4.5/drivers/mmc/host/Makefile
+++ b/ANDROID_3.4.5/drivers/mmc/host/Makefile
@@ -57,3 +57,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
endif
+
+obj-$(CONFIG_MMC_ATSMB) += mmc_atsmb.o
+obj-$(CONFIG_MMC_ATSMB1) += mmc_atsmb1.o
+obj-$(CONFIG_MMC_ATSMB2) += mmc_atsmb2.o
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c
new file mode 100755
index 00000000..150b7b12
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c
@@ -0,0 +1,2837 @@
+/*++
+linux/drivers/mmc/host/mmc_atsmb.c
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/memory.h>
+#include <mach/hardware.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include "mmc_atsmb.h"
+//#include <mach/multicard.h>
+#include <mach/irqs.h>
+#include <linux/regulator/consumer.h>
+
+#define mprintk
+
+#if 0
+#define DBG(host, fmt, args...) \
+ printk("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
+#endif
+#define ATSMB_TIMEOUT_TIME (HZ*2)
+
+
+static struct delayed_work mmc_work;
+
+static int g_atsmb_regulator;
+static struct regulator *atsmb_regulator;
+
+
+//add by jay,for modules support
+static u64 wmt_sdmmc_dma_mask = 0xffffffffUL;
+static struct resource wmt_sdmmc_resources[] = {
+ [0] = {
+ .start = SD0_SDIO_MMC_BASE_ADDR,
+ .end = (SD0_SDIO_MMC_BASE_ADDR + 0x3FF),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SDC0,
+ .end = IRQ_SDC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_SDC0_DMA,
+ .end = IRQ_SDC0_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-s*/
+ [3] = {
+ .start = IRQ_PMC_WAKEUP,
+ .end = IRQ_PMC_WAKEUP,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-e*/
+};
+
+struct kobject *atsmb_kobj;
+struct mmc_host *mmc_host_attr = NULL;
+//
+static void atsmb_release(struct device * dev) {}
+
+/*#ifdef CONFIG_MMC_DEBUG*/
+#define MORE_INFO
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#define DBGR(x...) do { } while (0)
+#else
+#define DBG(x...) do { } while (0)
+#define DBGR(x...) do { } while (0)
+#endif
+
+/* when Read CRC error occur, and clear read CRC error by software reset.*/
+void atsmb_copy_reg(int direct)
+{
+ static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ static u32 CMD_ARG, CURBLK_CNT;
+
+ /*direct 0: copy register to memory; 1: copy memory to register.*/
+ if (direct == 0) {
+ CTL = *ATSMB0_CTL;
+ CMD_IDX = *ATSMB0_CMD_IDX;
+ RSP_TYPE = *ATSMB0_RSP_TYPE;
+ CMD_ARG = *ATSMB0_CMD_ARG;
+ BUS_MODE = *ATSMB0_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE;
+ CTL2 = *ATSMB0_CTL2;
+ BLK_LEN = *ATSMB0_BLK_LEN;
+ BLK_CNT = *ATSMB0_BLK_CNT;
+ RSP_0 = *ATSMB0_RSP_0;
+ RSP_1 = *ATSMB0_RSP_1;
+ RSP_2 = *ATSMB0_RSP_2;
+ RSP_3 = *ATSMB0_RSP_3;
+ RSP_4 = *ATSMB0_RSP_4;
+ RSP_5 = *ATSMB0_RSP_5;
+ RSP_6 = *ATSMB0_RSP_6;
+ RSP_7 = *ATSMB0_RSP_7;
+ RSP_8 = *ATSMB0_RSP_8;
+ RSP_9 = *ATSMB0_RSP_9;
+ RSP_10 = *ATSMB0_RSP_10;
+ RSP_11 = *ATSMB0_RSP_11;
+ RSP_12 = *ATSMB0_RSP_12;
+ RSP_13 = *ATSMB0_RSP_13;
+ RSP_14 = *ATSMB0_RSP_14;
+ RSP_15 = *ATSMB0_RSP_15;
+ CURBLK_CNT = *ATSMB0_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB0_INT_MASK_0;
+ INT_MASK_1 = *ATSMB0_INT_MASK_1;
+ SD_STS_0 = *ATSMB0_SD_STS_0;
+ SD_STS_1 = *ATSMB0_SD_STS_1;
+ SD_STS_2 = *ATSMB0_SD_STS_2;
+ SD_STS_3 = *ATSMB0_SD_STS_3;
+ RSP_TOUT = *ATSMB0_RSP_TOUT;
+ CLK_SEL = *ATSMB0_CLK_SEL;
+ EXT_CTL = *ATSMB0_EXT_CTL;
+ EXT_CTL_1 = *ATSMB0_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB0_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB0_TIMER_VAL;
+ } else {
+ *ATSMB0_CTL = CTL;
+ *ATSMB0_CMD_IDX = CMD_IDX;
+ *ATSMB0_RSP_TYPE = RSP_TYPE;
+ *ATSMB0_CMD_ARG = CMD_ARG;
+ *ATSMB0_BUS_MODE = BUS_MODE;
+ *ATSMB0_EXT_BUS_MODE = EXT_BUS_MODE;
+ *ATSMB0_CTL2 = CTL2;
+ *ATSMB0_BLK_LEN = BLK_LEN;
+ *ATSMB0_BLK_CNT = BLK_CNT;
+ *ATSMB0_RSP_0 = RSP_0;
+ *ATSMB0_RSP_1 = RSP_1;
+ *ATSMB0_RSP_2 = RSP_2;
+ *ATSMB0_RSP_3 = RSP_3;
+ *ATSMB0_RSP_4 = RSP_4;
+ *ATSMB0_RSP_5 = RSP_5;
+ *ATSMB0_RSP_6 = RSP_6;
+ *ATSMB0_RSP_7 = RSP_7;
+ *ATSMB0_RSP_8 = RSP_8;
+ *ATSMB0_RSP_9 = RSP_9;
+ *ATSMB0_RSP_10 = RSP_10;
+ *ATSMB0_RSP_11 = RSP_11;
+ *ATSMB0_RSP_12 = RSP_12;
+ *ATSMB0_RSP_13 = RSP_13;
+ *ATSMB0_RSP_14 = RSP_14;
+ *ATSMB0_RSP_15 = RSP_15;
+ *ATSMB0_CURBLK_CNT = CURBLK_CNT;
+ *ATSMB0_INT_MASK_0 = INT_MASK_0;
+ *ATSMB0_INT_MASK_1 = INT_MASK_1;
+ *ATSMB0_SD_STS_0 = SD_STS_0;
+ *ATSMB0_SD_STS_1 = SD_STS_1;
+ *ATSMB0_SD_STS_2 = SD_STS_2;
+ *ATSMB0_SD_STS_3 = SD_STS_3;
+ *ATSMB0_RSP_TOUT = RSP_TOUT;
+ *ATSMB0_CLK_SEL = CLK_SEL;
+ *ATSMB0_EXT_CTL = EXT_CTL;
+ *ATSMB0_EXT_CTL_1 = EXT_CTL_1;
+ *ATSMB0_EXT_CTL_2 = EXT_CTL_2;
+ *ATSMB0_SHDW_BLKLEN = SHDW_BLKLEN;
+ *ATSMB0_MAN_TUNE_VAL = MAN_TUNE_VAL;
+ *ATSMB0_SD_WRI_TUNE = SD_WRI_TUNE;
+ *ATSMB0_TIMER_VAL = TIMER_VAL;
+ }
+}
+
+#if 0
+void atsmb_dump_reg(void)
+{
+ u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
+ u32 CURBLK_CNT;
+
+ CTL = *ATSMB0_CTL;
+ CMD_IDX = *ATSMB0_CMD_IDX;
+ RSP_TYPE = *ATSMB0_RSP_TYPE;
+ CMD_ARG = *ATSMB0_CMD_ARG;
+ BUS_MODE = *ATSMB0_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE;
+ CTL2 = *ATSMB0_CTL2;
+ BLK_LEN = *ATSMB0_BLK_LEN;
+ BLK_CNT = *ATSMB0_BLK_CNT;
+ RSP_0 = *ATSMB0_RSP_0;
+ RSP_1 = *ATSMB0_RSP_1;
+ RSP_2 = *ATSMB0_RSP_2;
+ RSP_3 = *ATSMB0_RSP_3;
+ RSP_4 = *ATSMB0_RSP_4;
+ RSP_5 = *ATSMB0_RSP_5;
+ RSP_6 = *ATSMB0_RSP_6;
+ RSP_7 = *ATSMB0_RSP_7;
+ RSP_8 = *ATSMB0_RSP_8;
+ RSP_9 = *ATSMB0_RSP_9;
+ RSP_10 = *ATSMB0_RSP_10;
+ RSP_11 = *ATSMB0_RSP_11;
+ RSP_12 = *ATSMB0_RSP_12;
+ RSP_13 = *ATSMB0_RSP_13;
+ RSP_14 = *ATSMB0_RSP_14;
+ RSP_15 = *ATSMB0_RSP_15;
+ CURBLK_CNT = *ATSMB0_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB0_INT_MASK_0;
+ INT_MASK_1 = *ATSMB0_INT_MASK_1;
+ SD_STS_0 = *ATSMB0_SD_STS_0;
+ SD_STS_1 = *ATSMB0_SD_STS_1;
+ SD_STS_2 = *ATSMB0_SD_STS_2;
+ SD_STS_3 = *ATSMB0_SD_STS_3;
+ RSP_TOUT = *ATSMB0_RSP_TOUT;
+ CLK_SEL = *ATSMB0_CLK_SEL;
+ EXT_CTL = *ATSMB0_EXT_CTL;
+ EXT_CTL_1 = *ATSMB0_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB0_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB0_TIMER_VAL;
+
+ PDMA_GCR = *ATSMB0_PDMA_GCR;
+ PDMA_IER = *ATSMB0_PDMA_IER;
+ PDMA_ISR = *ATSMB0_PDMA_ISR;
+ PDMA_DESPR = *ATSMB0_PDMA_DESPR;
+ PDMA_RBR = *ATSMB0_PDMA_RBR;
+ PDMA_DAR = *ATSMB0_PDMA_DAR;
+ PDMA_BAR = *ATSMB0_PDMA_BAR;
+ PDMA_CPR = *ATSMB0_PDMA_CPR;
+ PDMA_CCR = *ATSMB0_PDMA_CCR;
+
+ DBGR("\n+---------------------------Registers----------------------------+\n");
+
+ DBGR("%16s = 0x%8x |", "CTL", CTL);
+ DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
+
+ DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
+ DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
+
+ DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
+ DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
+
+ DBGR("%16s = 0x%8x |", "CTL2", CTL2);
+ DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
+
+ DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
+ DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
+
+ DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
+ DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
+
+ DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
+ DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
+
+ DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
+ DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
+
+ DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
+ DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
+
+ DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
+ DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
+
+ DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
+ DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
+
+ DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
+ DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
+
+ DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
+
+ DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
+ DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
+
+ DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
+ DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
+
+ DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
+
+ DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
+
+ DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
+ DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
+
+ DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
+ DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
+
+ DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
+ DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
+
+ DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
+ DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
+ DBGR("\n+----------------------------------------------------------------+\n");
+}
+#else
+void atsmb_dump_reg(void) {}
+#endif
+
+unsigned int fmax0 = 515633;
+unsigned int MMC0_DRIVER_VERSION;
+int SD0_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/
+int SDXC0_function;
+static int SD0_detect_pol = 0;
+static int SD0_detect_pulldown = 0;
+static int SD0_speed = 0;
+//add by kevin guan
+int SD0_ro_disable = 0;
+
+int SCC_ID(void){
+ unsigned short val;
+
+ val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
+ return val;
+}
+
+int get_chip_version(void) /*2008/05/01 janshiue modify for A1 chip*/
+{
+ u32 tmp;
+
+ tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
+ tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
+ return tmp;
+}
+
+void get_driver_version(void)
+{
+ if (SCC_ID() == 0x3426) {
+ if (get_chip_version() < 0xA1)
+ MMC0_DRIVER_VERSION = MMC_DRV_3426_A0;
+ else if (get_chip_version() == 0xA1)
+ MMC0_DRIVER_VERSION = MMC_DRV_3426_A1;
+ else
+ MMC0_DRIVER_VERSION = MMC_DRV_3426_A2;
+ } else if (SCC_ID() == 0x3437) {
+ if (get_chip_version() < 0xA1)
+ MMC0_DRIVER_VERSION = MMC_DRV_3437_A0;
+ else
+ MMC0_DRIVER_VERSION = MMC_DRV_3437_A1;
+ } else if (SCC_ID() == 0x3429) {
+ MMC0_DRIVER_VERSION = MMC_DRV_3429;
+ } else if (SCC_ID() == 0x3451) {
+ if (get_chip_version() < 0xA1)
+ MMC0_DRIVER_VERSION = MMC_DRV_3451_A0;
+ } else if (SCC_ID() == 0x3465) {
+ MMC0_DRIVER_VERSION = MMC_DRV_3465;
+ } else if (SCC_ID() == 0x3445) {
+ MMC0_DRIVER_VERSION = MMC_DRV_3445;
+ } else if (SCC_ID() == 0x3481) {
+ MMC0_DRIVER_VERSION = MMC_DRV_3481;
+ } else if (SCC_ID() == 0x3498) {
+ MMC0_DRIVER_VERSION = MMC_DRV_3498;
+ }
+}
+/*2008/10/6 RichardHsu-e*/
+
+/**********************************************************************
+Name : atsmb_alloc_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline int atsmb_alloc_desc(struct atsmb_host *host,
+ unsigned int bytes)
+{
+ void *DescPool = NULL;
+ DBG("[%s] s\n",__func__);
+
+ DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
+ if (!DescPool) {
+ DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ DBG("[%s] e1\n",__func__);
+ return -1;
+ }
+ DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ host->DescVirAddr = (unsigned long *)DescPool;
+ host->DescSize = bytes;
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_config_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline void atsmb_config_desc(unsigned long *DescAddr,
+ unsigned long *BufferAddr,
+ unsigned long Blk_Cnt)
+{
+
+ int i = 0 ;
+ unsigned long *CurDes = DescAddr;
+ DBG("[%s] s\n",__func__);
+
+ /* the first Descriptor store for 1 Block data
+ * (512 bytes)
+ */
+ for (i = 0 ; i < 3 ; i++) {
+ atsmb_init_short_desc(CurDes, 0x80, BufferAddr, 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
+ }
+ if (Blk_Cnt > 1) {
+ atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
+ /* the following Descriptor store the rest Blocks data
+ * (Blk_Cnt - 1) * 512 bytes
+ */
+ atsmb_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
+ BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ } else {
+ atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb_config_dma
+Function : To set des/src address, byte count to transfer, and DMA channel settings,
+ and DMA ctrl. register.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb_config_dma(unsigned long config_dir,
+ unsigned long dma_mask,
+ struct atsmb_host *host)
+{
+
+ DBG("[%s] s\n",__func__);
+ /* Enable DMA */
+ *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ /*open interrupt*/
+ *ATSMB0_PDMA_IER = SD_PDMA_IER_INT_EN;
+ /*Make sure host could co-work with DMA*/
+ *ATSMB0_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
+
+ /*Set timer timeout value*/
+ /*If clock is 390KHz*/
+ if (host->current_clock < 400000)
+ *ATSMB0_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
+ else
+ *ATSMB0_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
+
+ /*clear all DMA INT status for safety*/
+ *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /* hook desc */
+ *ATSMB0_PDMA_DESPR = host->DescPhyAddr;
+ if (config_dir == DMA_CFG_WRITE)
+ *ATSMB0_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
+ else
+ *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
+
+ host->DmaIntMask = dma_mask; /*save success event*/
+
+ *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_RUN;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb_set_dma_end
+Function : To set all descriptor end bit for removing card when PDMA
+ don't transfer data done. let PDMA transfer done
+Calls :
+Called by :
+Parameter :
+Author : Eason Chien
+History : 2013/05/16
+***********************************************************************/
+void atsmb_set_dma_end(unsigned long *DescAddr, unsigned int bytes)
+{
+ int i = 0;
+ struct SD_PDMA_DESC_S *CurDes_S;
+ CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
+ DBG("[%s] s\n", __func__);
+ DBG("[%s] byte = %d, size of %d\n", __func__, bytes, sizeof(struct SD_PDMA_DESC_S));
+
+ CurDes_S += 255;
+
+ for (i = 255; i >=0 ;i--) {
+ /* Set end bit of all descriptor and let PDMA finish as soon as possible */
+ CurDes_S->end = 1;
+ DBG("[%s] %d CurDes 0x%x, 0x%x, e=%x\n", __func__, i, CurDes_S, *CurDes_S);
+ CurDes_S -= 1;
+ }
+ DBG("[%s] e\n", __func__);
+}
+
+/**********************************************************************
+Name : atsmb_prep_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb_prep_cmd(struct atsmb_host *host,
+ u32 opcode,
+ u32 arg,
+ unsigned int flags,
+ u16 blk_len,
+ u16 blk_cnt,
+ unsigned char int_maks_0,
+ unsigned char int_mask_1,
+ unsigned char cmd_type,
+ unsigned char op)
+{
+ DBG("[%s] s\n",__func__);
+ DBG("[%s] s opcode = %u arg = 0x%x flags = 0x%x\n",__func__,opcode,arg,flags);
+ /*set cmd operation code and arguments.*/
+ host->opcode = opcode;
+ *ATSMB0_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
+ *ATSMB0_CMD_ARG = arg;
+
+#if 0 /* Fixme to support SPI mode, James Tian*/
+ if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
+ else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1;
+ else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b;
+ else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2;
+ else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3;
+ else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
+ *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ else
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
+#endif
+
+#if 1
+ /*set cmd response type*/
+ switch (flags) {
+ case MMC_RSP_NONE | MMC_CMD_AC:
+ case MMC_RSP_NONE | MMC_CMD_BC:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ case MMC_RSP_R1 | MMC_CMD_ADTC:
+ case MMC_RSP_R1 | MMC_CMD_AC:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1;
+ break;
+ case MMC_RSP_R1B | MMC_CMD_AC:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b;
+ break;
+ case MMC_RSP_R2 | MMC_CMD_BCR:
+ case MMC_RSP_R2 | MMC_CMD_AC:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2;
+ break;
+ case MMC_RSP_R3 | MMC_CMD_BCR:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3;
+ break;
+ case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
+ *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
+ ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ break;
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5;
+ break;
+ case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4;
+ break;
+ default:
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ }
+#endif
+ /*SDIO cmd 52 , 53*/
+ if ((opcode == SD_IO_RW_DIRECT) ||
+ (opcode == SD_IO_RW_EXTENDED)) {
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5;
+ *ATSMB0_RSP_TYPE |= BIT6;
+ }
+ /*SDIO cmd 5*/
+ if ((opcode == SD_IO_SEND_OP_COND) &&
+ ((flags & (MMC_RSP_PRESENT|
+ MMC_RSP_136|
+ MMC_RSP_CRC|
+ MMC_RSP_BUSY|
+ MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
+ *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4;
+ *ATSMB0_RSP_TYPE |= BIT6;
+ }
+
+ /*reset Response FIFO*/
+ *ATSMB0_CTL |= 0x08;
+
+ /* SD Host enable Clock */
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+
+ /*Set Cmd-Rsp Timeout to be maximum value.*/
+ *ATSMB0_RSP_TOUT = 0xFE;
+
+ /*clear all status registers for safety*/
+ *ATSMB0_SD_STS_0 |= 0xff;
+ *ATSMB0_SD_STS_1 |= 0xff;
+ *ATSMB0_SD_STS_2 |= 0xff;
+ //*ATSMB0_SD_STS_2 |= 0x7f;
+ *ATSMB0_SD_STS_3 |= 0xff;
+
+ //set block length and block count for cmd requesting data
+ *ATSMB0_BLK_LEN &=~(0x0fff);
+ *ATSMB0_BLK_LEN |= blk_len;
+ //*ATSMB0_SHDW_BLKLEN = blk_len;
+ *ATSMB0_BLK_CNT = blk_cnt;
+
+
+ *ATSMB0_INT_MASK_0 |= int_maks_0;
+ *ATSMB0_INT_MASK_1 |= int_mask_1;
+
+ //Set Auto stop for Multi-block access
+ if(cmd_type == 3 || cmd_type == 4) {
+ //auto stop command set.
+ *ATSMB0_EXT_CTL |= 0x01;
+
+/*
+ * Enable transaction abort.
+ * When CRC error occurs, CMD 12 would be automatically issued.
+ * That is why we cannot enable R/W CRC error INTs.
+ * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
+ */
+/* Don't auto issue stop command when write command error,
+* because auto stop command can freezs PDMA. msut let PDMA transfer done.
+* 2013/05/15 by Eason
+*/
+ if (cmd_type == 4)
+ *ATSMB0_BLK_LEN |= 0x0800;
+ }
+
+ /*Set read or write*/
+ if (op == 1)
+ *ATSMB0_CTL &= ~(0x04);
+ else if (op == 2)
+ *ATSMB0_CTL |= 0x04;
+
+ /*for Non data access command, command type is 0.*/
+ *ATSMB0_CTL &= 0x0F;
+ *ATSMB0_CTL |= (cmd_type<<4);
+ DBG("[%s] e\n",__func__);
+}
+
+static inline void atsmb_issue_cmd(void)
+{
+ *ATSMB0_CTL |= ATSMB_START;
+ wmb();
+}
+/**********************************************************************
+Name : atsmb_request_end
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void
+atsmb_request_end(struct atsmb_host *host, struct mmc_request *mrq)
+{
+ DBG("[%s] s\n",__func__);
+ /*
+ * Need to drop the host lock here; mmc_request_done may call
+ * back into the driver...
+ */
+ //kevin delete spin lock
+ //spin_unlock(&host->lock);
+ /*DBG("100");*/
+ mmc_request_done(host->mmc, mrq);
+ /*DBG("101\n");*/
+ //kevin delete spin lock
+ //spin_lock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb_data_done
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb_wait_done(void *data)
+{
+ struct atsmb_host *host = (struct atsmb_host *) data;
+ DBG("[%s] s\n",__func__);
+
+ WARN_ON(host->done_data == NULL);
+ complete(host->done_data);
+ host->done_data = NULL;
+ host->done = NULL;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb_start_data
+Function : If we start data, there must be only four cases.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb_start_data(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+ unsigned char cmd_type = 0;
+ unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
+ unsigned char mask_0 = 0;
+ unsigned char mask_1 = 0;
+ unsigned long dma_mask = 0;
+
+ struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+
+ unsigned int total_blks = 0; /*total block number to transfer*/
+ u32 card_addr = 0;
+ unsigned long dma_len = 0;
+ unsigned long total_dma_len = 0;
+ dma_addr_t dma_phy = 0; /* physical address used for DMA*/
+ unsigned int dma_times = 0; /*times dma need to transfer*/
+ unsigned int dma_loop = 0;
+ unsigned int sg_num = 0;
+ int loop_cnt = 10000;
+ unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
+
+ DBG("[%s] s\n",__func__);
+ data->bytes_xfered = 0;
+ cmd->error = 0;
+ data->error = 0;
+
+ /*for loop*/
+ sg = data->sg;
+ sg_len = data->sg_len;
+
+ dma_times = (sg_len / MAX_DESC_NUM);
+ if (sg_len % MAX_DESC_NUM)
+ dma_times++;
+ DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
+ card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
+ total_blks = data->blocks;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+
+ for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
+ DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
+ if (dma_loop < dma_times)
+ sg_transfer_len = MAX_DESC_NUM;
+ else
+ sg_transfer_len = sg_len;
+ DBG("sg_transfer_len = %d\n", sg_transfer_len);
+ /*
+ *Firstly, check and wait till card is in the transfer state.
+ *For our hardware, we can not consider
+ *the card has successfully tranfered its state from data/rcv to trans,
+ *when auto stop INT occurs.
+ */
+ loop_cnt = 10000;
+ do {
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED)
+ break;
+ loop_cnt--;
+ WARN_ON(loop_cnt == 0);
+ host->done_data = &complete;
+ host->done = &atsmb_wait_done;
+ host->soft_timeout = 1;
+ atsmb_prep_cmd(host,
+ MMC_SEND_STATUS,
+ (host->mmc->card->rca)<<16,
+ MMC_RSP_R1 | MMC_CMD_AC,
+ 0,
+ 0,
+ 0, /*mask_0*/
+ ATSMB_RSP_DONE_EN
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN,
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb_issue_cmd();
+ DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB0_INT_MASK_1);
+ DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB0_SD_STS_1);
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ WARN_ON(host->soft_timeout == 1);
+ if (host->soft_timeout == 1) {
+ DBG("%s soft_timeout.\n", __func__);
+ atsmb_dump_reg();
+ }
+ if (cmd->error != MMC_ERR_NONE) {
+ cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("Getting Status failed.\n");
+ goto end;
+ }
+ } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
+ /*SDIO read/write*/
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ /*Single Block read/write*/
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ } else {
+ /*Multiple Block read/write*/
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 6;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 5;
+ op = 2;
+ mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ }
+
+ } else {
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ if (data->flags & MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_SINGLE_BLOCK;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_BLOCK;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ } else { /*more than one*/
+ if (data->flags&MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_MULTIPLE_BLOCK;
+ cmd_type = 4;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ cmd_type = 3;
+ op = 2;
+ mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ }
+ }
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb_wait_done;
+ /*sleep till ISR wakes us*/
+ host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
+
+ total_dma_len = 0;
+ DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
+ memset(host->DescVirAddr, 0, host->DescSize);
+ for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ total_dma_len = total_dma_len + dma_len;
+ DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
+ sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
+ /*2009/01/15 janshiue add*/
+ if (sg_num < sg_transfer_len - 1) {
+ /* means the last descporitor */
+ atsmb_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 0);
+ } else {
+ atsmb_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 1);
+ }
+ /*2009/01/15 janshiue add*/
+
+ }
+ /*operate our hardware*/
+ atsmb_prep_cmd(host,
+ host->opcode,
+ /*arg, may be byte addressed, may be block addressed.*/
+ card_addr,
+ cmd->flags,
+ data->blksz - 1, /* in fact, it is useless.*/
+ /* for single one, it is useless. but for multi one, */
+ /* it would be used to tell auto stop function whether it is done.*/
+ total_dma_len/(data->blksz),
+ mask_0,
+ mask_1,
+ cmd_type,
+ op);
+
+ atsmb_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
+ dma_mask,
+ host);
+
+ atsmb_issue_cmd();
+ wait_for_completion_timeout(&complete,
+ ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
+
+ /* When the address of request plus length equal card bound,
+ * force this stop command response as pass. Eason 2012/4/20 */
+ if (cmd->resp[0] == 0x80000b00) {
+ /*This caes used for SD2.0 and after MMC4.1 version*/
+ if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
+ card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
+ printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
+ }
+
+ /* This caes used for SD1.0 and before MMC 4.1 */
+ if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
+ card_addr,data->blksz,(total_dma_len/data->blksz));*/
+ }
+ }
+
+ if (host->soft_timeout == 1) {
+ atsmb_dump_reg();
+ //*ATSMB0_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ /*disable INT */
+ *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+ cmd->error = -ETIMEDOUT;
+ data->error = -ETIMEDOUT;
+ }
+
+ WARN_ON(host->soft_timeout == 1);
+
+ /*check everything goes okay or not*/
+ if (cmd->error != MMC_ERR_NONE
+ || data->error != MMC_ERR_NONE) {
+ DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
+ cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
+ goto end;
+ }
+// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
+ card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
+ data->bytes_xfered += total_dma_len;
+
+
+ }
+// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+ WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
+ host->opcode = 0;
+end:
+ dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ spin_lock(&host->lock);
+ atsmb_request_end(host, host->mrq);
+ spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+
+/**********************************************************************
+Name : atsmb_cmd_with_data_back
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb_cmd_with_data_back(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+ DBG("[%s] s\n",__func__);
+ /*for loop*/
+ sg = host->data->sg;
+ sg_len = host->data->sg_len;
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb_wait_done;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
+
+ /*2009/01/15 janshiue add*/
+ memset(host->DescVirAddr, 0, host->DescSize);
+ atsmb_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
+ /*2009/01/15 janshiue add*/
+ /*prepare for cmd*/
+ atsmb_prep_cmd(host, /*host*/
+ host->cmd->opcode, /*opcode*/
+ host->cmd->arg, /*arg*/
+ host->cmd->flags, /*flags*/
+ sg_dma_len(sg)-1, /*block length*/
+ 0, /*block size: It looks like useless*/
+ 0, /*int_mask_0*/
+ (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
+ |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
+ 2, /*cmd_type*/
+ 1); /*op*/
+
+ atsmb_config_dma(DMA_CFG_READ,
+ SD_PDMA_CCR_Evt_success,
+ host);
+ atsmb_issue_cmd();
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
+ ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ spin_lock(&host->lock);
+ atsmb_request_end(host, host->mrq);
+ spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb_start_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb_start_cmd(struct atsmb_host *host)
+{
+ unsigned char int_mask_0,int_mask_1;
+ int_mask_0 = 0;
+ int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
+
+ DBG("[%s] s\n",__func__);
+
+ atsmb_prep_cmd(host,
+ host->cmd->opcode,
+ host->cmd->arg,
+ host->cmd->flags,
+ 0, /*useless*/
+ 0, /*useless*/
+ int_mask_0, /*mask_0*/
+ int_mask_1, /*mask_1*/
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb_issue_cmd();
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb_fmt_check_rsp
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb_fmt_check_rsp(struct atsmb_host *host)
+{
+
+ u8 tmp_resp[4] = {0};
+ int i, j, k;
+ DBG("[%s] s\n",__func__);
+ if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
+ for (j = 0, k = 1; j < 4; j++, k++)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k));
+
+ host->cmd->resp[0] = (tmp_resp[0] << 24) |
+ (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
+ } else {
+ for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
+ for (j = 0; j < 4; j++) {
+ if (k < 16)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k));
+ else /* k =16*/
+ tmp_resp[j] = *(ATSMB0_RSP_0);
+ k++;
+ }
+ host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
+ (tmp_resp[2]<<8) | (tmp_resp[3]);
+ }
+ }
+
+ /*
+ * For the situation that we need response,
+ * but response registers give us all zeros, we consider this operation timeout.
+ */
+ if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
+ if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
+ && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
+ host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
+ }
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb_get_slot_status
+Function : Our host only supports one slot.
+Calls :
+Called by :
+Parameter :
+returns : 1: in slot; 0: not in slot.
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb_get_slot_status(struct mmc_host *mmc)
+{
+// struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+// unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ status_0 = *ATSMB0_SD_STS_0;
+// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
+ if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+ if(SD0_detect_pol)
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
+ else
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
+
+ DBG("[%s] e1\n",__func__);
+ return ret;
+ } else {
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
+ DBG("[%s] e2\n",__func__);
+ return ret;
+ }
+ DBG("[%s] e3\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_init_short_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
+{
+ struct SD_PDMA_DESC_S *CurDes_S;
+ DBG("[%s] s\n",__func__);
+ CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
+ CurDes_S->ReqCount = ReqCount;
+ CurDes_S->i = 0;
+ CurDes_S->format = 0;
+ CurDes_S->DataBufferAddr = BufferAddr;
+ if (End) {
+ CurDes_S->end = 1;
+ CurDes_S->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_init_long_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
+{
+ struct SD_PDMA_DESC_L *CurDes_L;
+ DBG("[%s] s\n",__func__);
+ CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
+ CurDes_L->ReqCount = ReqCount;
+ CurDes_L->i = 0;
+ CurDes_L->format = 1;
+ CurDes_L->DataBufferAddr = BufferAddr;
+ CurDes_L->BranchAddr = BranchAddr;
+ if (End) {
+ CurDes_L->end = 1;
+ CurDes_L->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_dma_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static irqreturn_t atsmb_dma_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3;
+ u32 pdma_event_code = 0;
+ DBG("[%s] s\n",__func__);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+ /*Get INT status*/
+ status_0 = *ATSMB0_SD_STS_0;
+ status_1 = *ATSMB0_SD_STS_1;
+ status_2 = *ATSMB0_SD_STS_2;
+ status_3 = *ATSMB0_SD_STS_3;
+ /* after WM3426 A0 using PDMA */
+ if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+
+ pdma_event_code = *ATSMB0_PDMA_CCR & SD_PDMA_CCR_EvtCode;
+
+ /* clear INT status to notify HW clear EventCode*/
+ *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*printk("dma_isr event code = %X\n", *ATSMB0_PDMA_CCR);*/
+ /*We expect cmd with data sending back or read single block cmd run here.*/
+ if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
+ /*means need to update the data->error and cmd->error*/
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
+ if (host->data != NULL) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ DBG("dma_isr host->data is NULL\n");
+ /*disable INT*/
+ *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ goto out;
+ }
+ }
+ /*else do nothing*/
+ DBG("dma_isr PDMA OK\n");
+ /*atsmb_dump_reg();*/
+ }
+ /*But unluckily, we should also be prepare for all kinds of error situation.*/
+ else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("** dma_isr PDMA fail** event code = %X\n", *ATSMB0_PDMA_CCR);
+ atsmb_dump_reg();
+ }
+
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
+ atsmb_fmt_check_rsp(host);
+
+ /*disable INT*/
+ *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ }
+
+ /*wake up some one who is sleeping.*/
+ if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
+ if (host->done_data) {/* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb_request_end(host, host->mrq); /*for cmd with data sending back.*/
+ }
+
+out:
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e\n",__func__);
+ return IRQ_HANDLED;
+}
+
+/**********************************************************************
+Name : atsmb_regular_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t atsmb_regular_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
+ u32 pdma_sts;
+
+ DBG("[%s] s\n",__func__);
+ WARN_ON(host == NULL);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+
+ /*Get INT status*/
+ status_0 = *ATSMB0_SD_STS_0;
+ status_1 = *ATSMB0_SD_STS_1;
+ status_2 = *ATSMB0_SD_STS_2;
+ status_3 = *ATSMB0_SD_STS_3;
+
+ mask_0 = *ATSMB0_INT_MASK_0;
+ mask_1 = *ATSMB0_INT_MASK_1;
+ /*******************************************************
+ card insert interrupt
+ ********************************************************/
+ if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
+ /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
+ && (*ATSMB0_INT_MASK_0 & 0x80)) {
+
+ if (host->mmc->ops->get_slot_status(host->mmc)) {
+ host->mmc->scan_retry = 3;
+ host->mmc->card_scan_status = false;
+ } else {
+ host->mmc->scan_retry = 0;
+ host->mmc->card_scan_status = false;
+ }
+
+ mmc_detect_change(host->mmc, HZ/2);
+ /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
+ //*ATSMB0_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
+ /*Then we clear the INT status*/
+ //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
+ *ATSMB0_SD_STS_0 |= ATSMB_DEVICE_INSERT;
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e1\n",__func__);
+ return IRQ_HANDLED;
+ }
+
+ if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
+ spin_unlock(&host->lock);
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
+
+ enable_irq(irq);
+ DBG("[%s] e2\n",__func__);
+
+ return IRQ_HANDLED;
+ }
+ spin_lock(&host->lock);
+ }
+ pdma_sts = *ATSMB0_PDMA_CCR;
+
+ if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e3\n",__func__);
+ return IRQ_HANDLED;
+ }
+ /*******************************************************
+ command interrupt.
+ *******************************************************/
+ /*for write single block*/
+ if (host->opcode == MMC_WRITE_BLOCK) {
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err1\n",__func__);
+ atsmb_dump_reg();
+ }
+ } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
+ if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
+ && (status_0 & ATSMB_MULTI_XFER_DONE)) {
+ /*If CRC error occurs, I think this INT would not occrs.*/
+ /*okay, that is what we want.*/
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err2\n",__func__);
+ atsmb_dump_reg();
+
+ }
+ } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err3\n",__func__);
+ atsmb_dump_reg();
+ } else if (host->opcode == SD_IO_RW_EXTENDED){
+ /*Write operation*/
+ if (*ATSMB0_CTL & BIT2) {
+ if ((*ATSMB0_CTL & 0xf0) == 0x10) { /*single block write*/
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+
+ } else if ((*ATSMB0_CTL & 0xf0) == 0x50) {
+ if ((status_0 & ATSMB_MULTI_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ }
+ else {
+ /*Read operation*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err5\n",__func__);
+ }
+
+
+ } else {
+/* command, not request data*/
+/* the command which need data sending back,*/
+/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
+/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
+ if (host->data && host->opcode != MMC_SEND_STATUS) {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err6\n",__func__);
+ atsmb_dump_reg();
+ } else { /* Just command, no need data sending back.*/
+ if (status_1 & ATSMB_RSP_DONE) {
+ /*Firstly, check data-response is busy or not.*/
+ if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
+ int i = 10000;
+
+ while (status_2 & ATSMB_RSP_BUSY) {
+ status_2 = *ATSMB0_SD_STS_2;
+ if (--i == 0)
+ break;
+ DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
+ }
+ if (i == 0)
+ printk("[MMC driver] Error :SD data-response always busy!");
+ }
+#if 1
+/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
+/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
+/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
+ if (!atsmb_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
+ host->cmd->retries = 0; /* No retry.*/
+// host->cmd->error = MMC_ERR_INVALID;
+ host->cmd->error = -EINVAL;
+ } else
+#endif
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
+// host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
+ DBG("[%s] err7\n",__func__);
+ } else {/*or RSP CRC error*/
+// host->cmd->error = MMC_ERR_BADCRC;
+ host->cmd->error = -EILSEQ;
+ DBG("[%s] err8\n",__func__);
+ }
+ atsmb_dump_reg();
+ }
+ }
+ }
+ atsmb_fmt_check_rsp(host);
+
+ /*disable INT */
+ *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+
+ /*clear INT status. In fact, we will clear again before issuing new command.*/
+ *ATSMB0_SD_STS_0 |= status_0;
+ *ATSMB0_SD_STS_1 |= status_1;
+
+ /* when read CRC error occur, and the status can't write one to clear.
+ * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
+ if ((*ATSMB0_SD_STS_1 & BIT6) == 0x40) {
+ DBG("[%s] host0 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
+ /* Save SD card register */
+ atsmb_copy_reg(0);
+ /* Software reset */
+ *ATSMB0_BUS_MODE |= BIT7;
+ /* restore SD card register */
+ atsmb_copy_reg(1);
+ }
+
+ if (*ATSMB0_PDMA_ISR & SD_PDMA_IER_INT_STS)
+ *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*wake up some one who is sleeping.*/
+ if (host->done_data) { /* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb_request_end(host, host->mrq); /*for cmd without data.*/
+
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e4\n",__func__);
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(atsmb_regular_isr);
+
+/**********************************************************************
+Name : atsmb_get_ro
+Function :.
+Calls :
+Called by :
+Parameter :
+returns : 0 : write protection is disabled. 1: write protection is enabled.
+Author : Leo Lee
+History :
+***********************************************************************/
+int atsmb_get_ro(struct mmc_host *mmc)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+ unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+ //add by kevin guan
+ if(SD0_ro_disable)
+ return 0;
+ spin_lock_irqsave(&host->lock, flags);
+ status_0 = *ATSMB0_SD_STS_0;
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
+ ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb_dump_host_regs
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb_dump_host_regs(struct mmc_host *mmc)
+{
+ DBG("[%s] s\n",__func__);
+ atsmb_dump_reg();
+ DBG("[%s] e\n",__func__);
+}
+EXPORT_SYMBOL(atsmb_dump_host_regs);
+
+/**********************************************************************
+Name : atsmb_enable_sdio_irq
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ DBG("[%s] s enable = %d *ATSMB0_INT_MASK_1 = %x\n",__func__,enable,*ATSMB0_INT_MASK_1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (enable) {
+ *ATSMB0_INT_MASK_1 |= ATSMB_SDIO_EN;
+ } else {
+ *ATSMB0_INT_MASK_1 &= ~ATSMB_SDIO_EN;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+
+}
+/**********************************************************************
+Name : atsmb_request
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ DBG("[%s] s\n",__func__);
+
+ /* May retry process comes here.*/
+ host->mrq = mrq;
+ host->data = mrq->data;
+ host->cmd = mrq->cmd;
+ host->done_data = NULL;
+ host->done = NULL;
+
+ /*for data request*/
+ if (host->data) {
+ if (host->cmd->opcode == MMC_WRITE_BLOCK
+ || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
+ || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
+ || host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ atsmb_start_data(host);
+ } else {
+ atsmb_cmd_with_data_back(host);
+ }
+ } else {
+ atsmb_start_cmd(host);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb_set_clock
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Eason Chien
+History :2012/7/19
+***********************************************************************/
+static int atsmb_set_clock(struct mmc_host *mmc, unsigned int clock)
+{
+ int clock_multiplier = 1;
+ DBG("clock = %u\n",clock);
+
+ if (*ATSMB0_EXT_BUS_MODE & BIT4) /*Enable DDR50*/
+ clock_multiplier = 2;
+
+ if(SD0_speed){
+ if (clock == mmc->f_min) {
+ DBG("[%s]ATSMB Host 390KHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390);
+ }
+ else if (clock >= 208000000) {
+ DBG("[%s]ATSMB Host 208MHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+
+
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ DBG("[%s] *DPCTL = 0x%x DPCTL = 0x%x\n",
+ __func__, SD0_DPCTL_4BYTE_ADDR, SD0_DPCTL_4BYTE_VAL);
+ DBG("[%s] *DNCTL = 0x%x DNCTL = 0x%x\n",
+ __func__, SD0_DNCTL_4BYTE_ADDR, SD0_DNCTL_4BYTE_VAL);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80);
+ } else if (clock >= 100000000) {
+ DBG("[%s]ATSMB Host 100MHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80);
+ } else if (clock >= 50000000) {
+ DBG("[%s]ATSMB Host 50MHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 45 * clock_multiplier);
+ } else if ((clock >= 25000000) && (clock < 50000000)) {
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ DBG("[%s]ATSMB Host 25MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier);
+ } else if ((clock >= 20000000) && (clock < 25000000)) {
+ DBG("[%s]ATSMB Host 20MHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier);
+ } else {
+ DBG("[%s]ATSMB Host 390KHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier);
+ }
+ }else{
+ if (clock == mmc->f_min) {
+ DBG("[%s]ATSMB Host 390KHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390);
+ }else if (clock >= 25000000) {
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ DBG("[%s]ATSMB Host 25MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier);
+ } else if ((clock >= 20000000) && (clock < 25000000)) {
+ DBG("[%s]ATSMB Host 20MHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier);
+ } else {
+ DBG("[%s]ATSMB Host 390KHz\n", __func__);
+ if ((*ATSMB0_CTL2 & BIT3) == 0) {
+ DBG("[%s] 1.8V clock = %u\n",__func__,clock);
+
+ /*Set DPCTL 010 DNCTL 001*/
+ SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
+ SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
+ }
+ return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier);
+ }
+ }
+}
+
+static void atsmb_enable_power(struct atsmb_host *host, unsigned long flags)
+{
+ int result;
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (g_atsmb_regulator) {
+ if (regulator_is_enabled(atsmb_regulator) == 0) {
+ DBG("[%s] Turn on power\n", __FUNCTION__);
+ result = regulator_enable(atsmb_regulator);
+ if (result != 0)
+ printk(KERN_ALERT "[%s] regulator_enable FAIL\n", __FUNCTION__);
+ }
+ } else {
+ GPIO_OD_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_POWER;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+}
+
+static void atsmb_disable_power(struct atsmb_host *host, unsigned long flags)
+{
+ int result;
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (g_atsmb_regulator) {
+ if (regulator_is_enabled(atsmb_regulator) == 1) {
+ DBG("[%s] Turn off power\n", __FUNCTION__);
+ result = regulator_disable(atsmb_regulator);
+ if (result != 0)
+ printk(KERN_ALERT "[%s] regulator_disable FAIL\n", __FUNCTION__);
+ }
+ } else {
+ GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ /*set internal pull up*/
+ PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ /*disable SD0 power*/
+ GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+}
+
+/**********************************************************************
+Name : atsmb_set_ios
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ DBG("[%s] s\n",__func__);
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (ios->power_mode == MMC_POWER_OFF) {
+ if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
+ /* set all descriptor end bit for removing card when
+ * PDMA don't transfer data done. let PDMA transfer done
+ */
+ atsmb_set_dma_end(host->DescVirAddr, host->DescSize);
+
+ /* stop SD output clock */
+ *ATSMB0_BUS_MODE &= ~(ATSMB_CST);
+
+ /* disable SD Card power */
+ /*set SD0 power pin as GPO pin*/
+ atsmb_disable_power(host, flags);
+
+ /* Disable Pull up/down resister of SD Bus */
+ /*GPIO_PULL_CTRL_GP13_XDIO_BYTE_VAL &= ~SD0_PIN; marked by eason 2012/3/29*/
+
+ /* Config SD0 to GPIO */
+ GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN;
+
+ /* SD0 all pins output low */
+ GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
+
+ /* Config SD0 to GPO */
+ GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN;
+
+ }
+
+ } else if (ios->power_mode == MMC_POWER_UP) {
+ if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
+ /* disable SD Card power */
+ /*set SD0 power pin as GPO pin*/
+ GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+
+ /*set internal pull up*/
+ PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+ /*disable SD0 power*/
+ GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
+
+ /* Config SD PIN share, WM3498 SD0 no share pin */
+ /*PIN_SHARING_SEL_4BYTE_VAL &= ~GPIO_SD0_PinShare; */
+
+ /* do not config GPIO_SD0_CD because ISR has already run,
+ * config card detect will issue ISR storm.
+ */
+ /*
+ GPIO_OD_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
+ GPIO_OC_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
+ GPIO_CTRL_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
+ */
+ *ATSMB0_CTL2 |= BIT3; /*Set 3.3V*/
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
+ *ATSMB0_EXT_BUS_MODE &= ~BIT4; /*Disable DDR50*/
+
+ /*Set 18SEL as function pin*/
+ GPIO_CTRL_GP12_SPI_BYTE_VAL &= ~GPIO_SD0_18SEL;
+
+
+ /* Config SD to GPIO */
+ GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN;
+
+ /* SD all pins output low */
+ GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
+
+ /* Config SD to GPO */
+ GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN;
+
+ /* Pull up/down resister of SD Bus */
+ /*Disable Clock & CMD Pull enable*/
+ PULL_EN_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Clock | GPIO_SD0_Command);
+
+ /*Set CD ,WP ,DATA pin pull up*/
+ if (SD0_detect_pulldown)
+ PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD;
+ else
+ PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
+ PULL_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect);
+
+ /*Enable CD ,WP ,DATA internal pull*/
+ PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
+ PULL_EN_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect);
+
+ /*Set SD0 PAD signal drive strength as 0*/
+ SD0_DPCTL_4BYTE_VAL = 0;
+ SD0_DNCTL_4BYTE_VAL = 0;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(100);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* enable SD Card Power */
+ atsmb_enable_power(host, flags);
+
+ /* enable SD output clock */
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Config SD0 back to function */
+ GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
+ GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD;
+ }
+ } else {
+ /*nothing to do when powering on.*/
+ }
+
+ host->current_clock = atsmb_set_clock(mmc,ios->clock);
+
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ *ATSMB0_EXT_CTL |= BIT2;
+ } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ *ATSMB0_BUS_MODE |= ATSMB_BUS_WIDTH_4;
+ *ATSMB0_EXT_CTL &= ~BIT2;
+ } else {
+ *ATSMB0_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
+ *ATSMB0_EXT_CTL &= ~BIT2;
+ }
+
+/*
+#define MMC_TIMING_LEGACY 0
+#define MMC_TIMING_MMC_HS 1
+#define MMC_TIMING_SD_HS 2
+#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
+#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
+#define MMC_TIMING_UHS_SDR50 3
+#define MMC_TIMING_UHS_SDR104 4
+#define MMC_TIMING_UHS_DDR50 5
+#define MMC_TIMING_MMC_HS200 6
+*/
+ DBG("[%s]timing = 0x%x clock = %u\n", __func__, ios->timing, ios->clock);
+
+ if (ios->timing == MMC_TIMING_LEGACY) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
+ } else if (ios->timing == MMC_TIMING_MMC_HS) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
+ } else if (ios->timing == MMC_TIMING_SD_HS) {
+ *ATSMB0_EXT_CTL |= BIT7; /*HIGH SPEED MODE*/
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
+ } else if (ios->timing == MMC_TIMING_UHS_SDR12) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ /*UHS Mode Select = 000 SDR12*/
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
+ } else if (ios->timing == MMC_TIMING_UHS_SDR25) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ /*UHS Mode Select = 001 SDR25*/
+ *ATSMB0_CTL2 |= BIT0;
+ *ATSMB0_CTL2 &= ~(BIT1 | BIT2);
+ } else if (ios->timing == MMC_TIMING_UHS_SDR50) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ /*UHS Mode Select = 010 SDR50*/
+ *ATSMB0_CTL2 |= BIT1;
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT2);
+ } else if (ios->timing == MMC_TIMING_UHS_SDR104) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ /*UHS Mode Select = 011 SDR104*/
+ *ATSMB0_CTL2 |= (BIT0 | BIT1);
+ *ATSMB0_CTL2 &= ~BIT2;
+ } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+ /*UHS Mode Select = 100 DDR50*/
+ *ATSMB0_CTL2 |= BIT2;
+ *ATSMB0_CTL2 &= ~(BIT0 | BIT1);
+ *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
+ /* enable SD output clock */
+ *ATSMB0_BUS_MODE &= ~ATSMB_CST;
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
+ /* enable SD output clock */
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+ } else
+ *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
+
+/* spin_unlock_irqrestore(&host->lock, flags);
+ msleep(100);
+ spin_lock_irqsave(&host->lock, flags); */
+
+ DBG("[%s] *ATSMB0_CTL2 = 0x%x *ATSMB0_EXT_CTL = 0x%x *ATSMB0_EXT_BUS_MODE = 0x%x\n",
+ __func__, *ATSMB0_CTL2, *ATSMB0_EXT_CTL, *ATSMB0_EXT_BUS_MODE);
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+}
+
+int atsmb_start_signal_voltage_switch(struct mmc_host *host, struct mmc_ios *ios)
+{
+ DBG("[%s] s\n",__func__);
+
+ if(ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+ /*Set CMD ,DATA0~3 pin as GPO low*/
+ /* SD0 all pins output low */
+ GPIO_OD_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Command | GPIO_SD0_Data);
+ /* Config SD0 to GPO */
+ GPIO_OC_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data);;
+ /* Config SD0 to GPIO */
+ GPIO_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data);
+
+
+ /*Wait for 1ms*/
+ msleep(1);
+
+ /*Stop Clock*/
+ *ATSMB0_BUS_MODE &= ~(ATSMB_CST);
+
+
+ /*Enable clock & Set 1.8V*/
+ *ATSMB0_CTL2 &= ~BIT3;
+
+ /*Wait for 10ms*/
+ msleep(100);
+
+ /*Enable Clock*/
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+
+
+ /*Set CMD DATA0~3 pin as function pin*/
+ GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Command;
+ GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Data;
+
+
+ DBG("Set SD0 1.8v = 0x%x\n",ios->signal_voltage);
+
+ return 0;
+ } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330){
+ *ATSMB0_CTL2 |= BIT3;
+ DBG("Set SD0 3.3v = 0x%x\n",ios->signal_voltage);
+ return 0;
+ }
+
+ printk("Set voltage error = 0x%x\n",ios->signal_voltage);
+ return -EIO;
+ DBG("[%s] e\n",__func__);
+}
+
+static const struct mmc_host_ops atsmb_ops = {
+ .request = atsmb_request,
+ .set_ios = atsmb_set_ios,
+ .get_ro = atsmb_get_ro,
+ .get_slot_status = atsmb_get_slot_status,
+ .dump_host_regs = atsmb_dump_host_regs,
+ .enable_sdio_irq = atsmb_enable_sdio_irq,
+ .start_signal_voltage_switch = atsmb_start_signal_voltage_switch,
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+/**********************************************************************
+Name :atsmb_probe
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int __init atsmb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = NULL;
+ struct atsmb_host *atsmb_host = NULL;
+ struct resource *resource = NULL;
+ int irq[2] = {0};
+ int ret = 0;
+
+ DBG("[%s] s\n",__func__);
+ if (!pdev) {
+ ret = -EINVAL; /* Invalid argument */
+ goto the_end;
+ }
+
+ /*Enable SD host clock*/
+ auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0);
+
+ if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
+ /* Pull up/down resister of SD CD */
+ if(SD0_detect_pulldown)
+ PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD; /*pull down CD*/
+ else
+ PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; /*pull up CD*/
+ PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
+
+ /* config CardDetect pin to SD function */
+ GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD;
+ }
+
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ ret = -ENXIO; /* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
+ goto the_end;
+ }
+#if 0
+ if (!request_mem_region(resource->start, SZ_1K, MMC0_DRIVER_NAME)) {
+ ret = -EBUSY;
+ printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
+ goto the_end ;
+ }
+#endif
+ irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
+ irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
+
+ if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
+ ret = -ENXIO;/* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
+ goto rls_region;
+ }
+
+ /*allocate a standard msp_host structure attached with a atsmb structure*/
+ mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
+ if (!mmc_host) {
+ ret = -ENOMEM;
+ printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
+ goto rls_region;
+ }
+ mmc_host->wmt_host_index = 0; /*to identify host number*/
+
+ dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
+ atsmb_host = mmc_priv(mmc_host);
+
+ mmc_host->ops = &atsmb_ops;
+
+ mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+
+ mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
+ mmc_host->f_max = 100000000; /* Set max frequency 100MHz*/
+
+ if (SDXC0_function == 1) {
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ
+ | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR;
+ /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
+ } else {
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ;
+ /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
+ }
+
+ mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
+
+ /*1MB per each request */
+ /*we have a 16 bit block number register, and block length is 512 bytes.*/
+ mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
+ mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
+ mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
+ mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
+
+ /*set the specified host -- ATSMB*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ mmc_host->card_attath_status = card_attach_status_unchange;
+#endif
+ sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
+#if 0
+ atsmb_host->base = ioremap(resource->start, SZ_1K);
+ if (!atsmb_host->base) {
+ printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
+ ret = -ENOMEM;
+ goto fr_host;
+ }
+#endif
+ atsmb_host->base = (void *)resource->start;
+ atsmb_host->mmc = mmc_host;
+ spin_lock_init(&atsmb_host->lock);
+ atsmb_host->res = resource;/* for atsmb_remove*/
+
+ /*disable all interrupt and clear status by resetting controller.*/
+ *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB0_BLK_LEN &= ~(0xa000);
+ *ATSMB0_SD_STS_0 |= 0xff;
+ *ATSMB0_SD_STS_1 |= 0xff;
+
+ /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
+ //if (MMC0_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+
+ atsmb_host->regular_irq = irq[0];
+ atsmb_host->dma_irq = irq[1];
+
+ ret = request_irq(atsmb_host->regular_irq,
+ atsmb_regular_isr,
+ IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
+ MMC0_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
+ goto unmap;
+ }
+
+ ret = request_irq(atsmb_host->dma_irq,
+ atsmb_dma_isr,
+ IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
+ MMC0_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
+ goto fr_regular_isr;
+ }
+
+ /* config CardDetect pin to SD function */
+ /*GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD; add by eason 2012/3/29*/
+
+ /*wait card detect status change*/
+ //msleep(10);
+
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB0_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
+ *ATSMB0_SD_STS_0 |= 0xff;
+ *ATSMB0_INT_MASK_0 |= 0x80; /*or 0x40?*/
+
+ /*allocation dma descriptor*/
+ ret = atsmb_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
+ if (ret == -1) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
+ goto fr_dma_isr;
+ }
+ printk(KERN_INFO "WMT ATSMB (AHB To SD/MMC Bus) controller registered!\n");
+
+ if (SD0_function == SDIO_WIFI)
+ mmc_add_host(mmc_host,false);
+ else
+ mmc_add_host(mmc_host,true);
+
+ mmc_host_attr = mmc_host;
+
+ DBG("[%s] e1\n",__func__);
+ return 0;
+
+fr_dma_isr:
+ free_irq(atsmb_host->dma_irq, atsmb_host);
+fr_regular_isr:
+ free_irq(atsmb_host->regular_irq, atsmb_host);
+unmap:
+ //iounmap(atsmb_host->base);
+//fr_host:
+ dev_set_drvdata(dev, NULL);
+ mmc_free_host(mmc_host);
+rls_region:
+ //release_mem_region(resource->start, SZ_1K);
+the_end:
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB0 probe Failed!\n") ;
+ DBG("[%s] e2\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb_remove
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
+ struct atsmb_host *atsmb_host;
+
+ DBG("[%s] s\n",__func__);
+ atsmb_host = mmc_priv(mmc_host);
+ if (!mmc_host || !atsmb_host) {
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB0 remove method failed!\n");
+ DBG("[%s] e1\n",__func__);
+ return -ENXIO;
+ }
+ mmc_remove_host(mmc_host);
+
+ /*disable interrupt by resetting controller -- for safey*/
+ *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB0_BLK_LEN &= ~(0xa000);
+ *ATSMB0_SD_STS_0 |= 0xff;
+ *ATSMB0_SD_STS_1 |= 0xff;
+
+ (void)free_irq(atsmb_host->regular_irq, atsmb_host);
+ (void)free_irq(atsmb_host->dma_irq, atsmb_host);
+ (void)iounmap(atsmb_host->base);
+ (void)release_mem_region(atsmb_host->res->start, SZ_1K);
+ dev_set_drvdata(dev, NULL);
+ /*free dma descriptor*/
+ dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
+ atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
+ (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_shutdown
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb_shutdown(struct platform_device *pdev)
+{
+ /*atsmb_shutdown don't be used now.*/
+ /*struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
+
+ DBG("[%s] s\n",__func__);
+ if (SD0_function != SDIO_WIFI) {
+ /*Disable card detect interrupt*/
+ *ATSMB0_INT_MASK_0 &= ~0x80;
+ }
+ DBG("[%s] e\n",__func__);
+
+}
+
+/**********************************************************************
+Name : atsmb_suspend
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+#ifdef CONFIG_PM
+static int atsmb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ if (mmc) {
+ /*struct atsmb_host *host = mmc_priv(mmc);*/
+ ret = mmc_suspend_host(mmc);
+ if (ret == 0) {
+ /*disable all interrupt and clear status by resetting controller. */
+ *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB0_BLK_LEN &= ~(0xa000);
+ *ATSMB0_SD_STS_0 |= 0xff;
+ *ATSMB0_SD_STS_1 |= 0xff;
+
+ }
+ /*disable source clock*/
+ auto_pll_divisor(DEV_SDMMC0, CLK_DISABLE, 0, 0);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*clean SD card attatch status change*/
+ PMCWS_VAL |= BIT19;
+ mmc->card_attath_status = card_attach_status_unchange;
+#endif
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb_resume
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb_resume(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ /*
+ * enable interrupt, DMA, etc.
+ * Supply power to slot.
+ */
+ if (mmc) {
+ /*enable source clock*/
+ auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0);
+
+ udelay(1);
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB0_BLK_LEN |= (0xa000);
+ *ATSMB0_INT_MASK_0 |= 0x80; /* or 40?*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*modify SD card attatch status change*/
+ if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) {
+ /*card change when suspend mode*/
+ mmc->card_attath_status = card_attach_status_change;
+ /*clean SD card attatch status change*/
+ PMCWS_VAL |= BIT19;
+ }
+#endif
+ ret = mmc_resume_host(mmc);
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+#else
+#define atsmb_suspend NULL
+#define atsmb_resume NULL
+#endif
+
+static struct platform_driver atsmb_driver = {
+ .driver.name = "sdmmc",
+ //.probe = atsmb_probe,
+ .remove = atsmb_remove,
+ .shutdown = atsmb_shutdown,
+ .suspend = atsmb_suspend,
+ .resume = atsmb_resume,
+};
+
+static struct platform_device wmt_sdmmc_device = {
+ .name = "sdmmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &wmt_sdmmc_dma_mask,
+ .coherent_dma_mask = ~0,
+ .release = atsmb_release,
+ },
+ .num_resources = ARRAY_SIZE(wmt_sdmmc_resources),
+ .resource = wmt_sdmmc_resources,
+};
+
+
+static ssize_t atsmb_state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+ int card_state;
+
+ DBG("[%s] s\n",__func__);
+ if (mmc_host_attr->card != NULL)
+ card_state = 1;
+ else
+ card_state = 0;
+ DBG("[%s]card_state = %d\n",__func__,card_state);
+ ret = sprintf(buf, "%d\n", card_state);
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+
+static ssize_t atsmb_state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int val;
+ DBG("[%s] s\n",__func__);
+ if (sscanf(buf, "%d", &val) == 1) {
+ DBG("[%s] val = %d\n",__func__,val);
+ if ((val == 1) && (mmc_host_attr->card == NULL)) {
+ DBG("[%s]add card\n",__func__);
+ mmc_detect_change(mmc_host_attr, 0);
+ msleep(500);
+ } else if ((val == 0) && (mmc_host_attr->card != NULL)) {
+ DBG("[%s]remove card\n",__func__);
+ mmc_force_remove_card(mmc_host_attr);
+ }
+ DBG("[%s] e1\n",__func__);
+ return n;
+ }
+ DBG("[%s] e2\n",__func__);
+ return -EINVAL;
+}
+
+static struct kobj_attribute atsmb_state_attr = { \
+ .attr = { \
+ .name = __stringify(state), \
+ .mode = 0755, \
+ }, \
+ .show = atsmb_state_show, \
+ .store = atsmb_state_store, \
+};
+
+static struct attribute * g[] = {
+ &atsmb_state_attr.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = g,
+};
+ //kevin add to check tf card stats every 1 sec
+
+static void wmt_mmc_work(struct work_struct *work)
+{
+
+ static int card_state_save = -1;
+ if(mmc_host_attr!=NULL){
+ struct atsmb_host *host = mmc_priv(mmc_host_attr);
+ int card_state;
+ if (mmc_host_attr->card != NULL)
+ card_state = 1;
+ else
+ card_state = 0;
+
+
+ //printk("check %d %d\n",atsmb_get_slot_status(host->mmc),card_state);
+ if(atsmb_get_slot_status(host->mmc)!=card_state){
+ //the second time error,goto detect or remove card
+ if(card_state_save == card_state){
+
+ //printk("xxxxxxxxxxxxxxxxxxxxxxxxcatch error %dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n",card_state);
+ mmc_detect_change(mmc_host_attr, 0);
+
+ }
+ //mark status error
+ card_state_save =card_state;
+ }else
+ card_state_save = -1;
+
+ }
+ schedule_delayed_work(&mmc_work, 1*HZ);
+}
+static int __init atsmb_init(void)
+{
+ int ret;
+
+ int retval;
+ unsigned char buf[80];
+ int varlen = 80;
+ char *varname = "wmt.sd0.param";
+ int temp = 0, sd_enable = 1; /*0 :disable 1:enable*/
+ unsigned char colon;
+ DBG("[%s] s\n",__func__);
+
+#ifdef CONFIG_MTD_WMT_SF
+ /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%x%c%d%c%d%c%d%c%d", &temp, &colon, &SD0_function,&colon,&SD0_detect_pol,&colon,&SD0_detect_pulldown,&colon,&SD0_speed);
+ printk(KERN_ALERT "wmt.sd0.param = %x%c%d%c%d%c%d%c%d\n", temp, colon, SD0_function,colon,SD0_detect_pol,colon,SD0_detect_pulldown,colon,SD0_speed);
+ sd_enable = temp & 0xf;
+ SDXC0_function = (temp >> 4) & 0xf;
+ printk(KERN_ALERT "SD0 ebable = %x, SDXC = %x, function = %x\n",
+ sd_enable, SDXC0_function, SD0_function);
+
+ if (SD0_function < 0 || SD0_function >= SD_MAX_FUN) {
+ sd_enable = 1;
+ SD0_function = 0;
+ printk(KERN_ALERT "wmt.sd0.param func err\n");
+ }
+ if (colon != ':') {
+ sd_enable = 1;
+ printk(KERN_ALERT "wmt.sd0.param colon err\n");
+ }
+
+ } else {
+ printk(KERN_ALERT "Default wmt.sd0.param = %x:%d\n", temp, SD0_function);
+ }
+
+ //add by kevin guan
+ retval = wmt_getsyspara("wmt.sd0.ro.disable", buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%d", &SD0_ro_disable);
+ printk(KERN_ALERT "SD0_ro_disable %d\n",SD0_ro_disable);
+ }
+
+#endif
+ /*SD function disable*/
+ if (sd_enable != 1) {
+ return -ENODEV;
+ }
+
+
+ get_driver_version();
+
+ if (platform_device_register(&wmt_sdmmc_device))//add by jay,for modules support
+ return -1;
+ //ret = platform_driver_register(&atsmb_driver);
+
+ /* Register regulator for SD host power switch */
+ atsmb_regulator = regulator_get(NULL, "ldo4");
+ if (IS_ERR(atsmb_regulator))
+ g_atsmb_regulator = 0;
+ else
+ g_atsmb_regulator = 1;
+ printk("[SD/MMC]use_regulator = %d\n", g_atsmb_regulator);
+
+ /* Force to disable ldo4 regulator, because Power switch is turned on, default */
+ if (g_atsmb_regulator) {
+ ret = regulator_force_disable(atsmb_regulator);
+ if (ret != 0)
+ printk(KERN_ALERT "[%s] get regulator Fail, ret = %d\n", __FUNCTION__, ret);
+ }
+
+ ret = platform_driver_probe(&atsmb_driver, atsmb_probe);
+
+ atsmb_kobj = kobject_create_and_add("mmc0", NULL);
+ if (!atsmb_kobj)
+ return -ENOMEM;
+
+
+ {
+ //add by kevin guan
+ int detect_disable = 0;
+ retval = wmt_getsyspara("wmt.sd0.detect.disable", buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%d", &detect_disable);
+ printk(KERN_ALERT "detect_disable %d\n",detect_disable);
+ }
+
+ if(detect_disable){
+ //tf slot without detect pin.
+ //do nothing;
+ }else{
+ //kevin add to check tf card stats every 1 sec
+ INIT_DELAYED_WORK(&mmc_work, wmt_mmc_work);
+ schedule_delayed_work(&mmc_work, 1*HZ);
+ }
+ }
+
+ return sysfs_create_group(atsmb_kobj, &attr_group);
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+
+static void __exit atsmb_exit(void)
+{
+ DBG("[%s] s\n",__func__);
+ (void)platform_driver_unregister(&atsmb_driver);
+ (void)platform_device_unregister(&wmt_sdmmc_device);//add by jay,for modules support
+ DBG("[%s] e\n",__func__);
+}
+
+module_init(atsmb_init);
+module_exit(atsmb_exit);
+module_param(fmax0, uint, 0444);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [AHB to SD/MMC Bridge] driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h
new file mode 100755
index 00000000..845b1116
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h
@@ -0,0 +1,691 @@
+/*++
+linux/drivers/mmc/host/mmc_atsmb.h
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+
+
+#ifndef __MMC_ATSMB_H
+#define __MMC_ATSMB_H
+
+#define MMC0_DRIVER_NAME "sdmmc"
+#define MMC1_DRIVER_NAME "sdmmc1"
+#define MMC2_DRIVER_NAME "sdmmc2"
+
+
+
+#define MMC_ERR_NONE 0 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */
+#define MMC_ERR_FAILED 4 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */
+/***************Driver version****************/
+#define MMC_DRV_3357_A0_A3 0
+#define MMC_DRV_3357_A4_A7 1
+#define MMC_DRV_3358 2
+#define MMC_DRV_3359 3
+#define MMC_DRV_3400_A0 4
+#define MMC_DRV_3400_A1 5
+#define MMC_DRV_3426_A0 6
+#define MMC_DRV_3426_A1 7
+#define MMC_DRV_3426_A2 8
+#define MMC_DRV_3437_A0 9
+#define MMC_DRV_3437_A1 10
+#define MMC_DRV_3429 11
+#define MMC_DRV_3451_A0 12
+#define MMC_DRV_3465 13
+#define MMC_DRV_3445 14
+#define MMC_DRV_3481 15
+#define MMC_DRV_3498 16
+/************** INT and Base address*****************/
+/*special settings for each one*/
+
+#define MMC_ATSMB0_BASE SD0_SDIO_MMC_BASE_ADDR
+#define MMC_ATMSB0_END (SD0_SDIO_MMC_BASE_ADDR + 0x3FF)
+
+#define MMC_ATSMB1_BASE SD1_SDIO_MMC_BASE_ADDR
+#define MMC_ATMSB1_END (SD1_SDIO_MMC_BASE_ADDR + 0x3FF)
+
+#define MMC_ATSMB2_BASE SD2_SDIO_MMC_BASE_ADDR
+#define MMC_ATMSB2_END (SD2_SDIO_MMC_BASE_ADDR + 0x3FF)
+
+
+/************** INT and Base address*****************/
+
+/* SD0 pin */
+#define GPIO_SD0_CD BIT4
+#define GPIO_SD0_Data (BIT6 | BIT5 | BIT4 | BIT3)
+#define GPIO_SD0_WriteProtect BIT2
+#define GPIO_SD0_Command BIT1
+#define GPIO_SD0_Clock BIT0
+#define GPIO_SD0_POWER BIT7
+#define GPIO_SD0_18SEL BIT4
+
+/* SD1 pin */
+#define GPIO_SD1_Data (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
+#define GPIO_SD1_Command BIT1
+#define GPIO_SD1_Clock BIT0
+#define GPIO_SD1_CD BIT6
+#define GPIO_SD1_WriteProtect BIT5
+#define GPIO_SD1_POWER BIT4
+#define GPIO_SD1_RSTN BIT3
+
+/* SD2 pin */
+#define GPIO_SD2_Data (BIT3 | BIT2 | BIT1 | BIT0)
+#define GPIO_SD2_Command BIT4
+#define GPIO_SD2_Clock BIT5
+#define GPIO_SD2_CD BIT0
+#define GPIO_SD2_WriteProtect BIT7
+#define GPIO_SD2_POWER BIT6
+
+/* SDIO Power pin */
+#define SDIO_WIFI_PWR BIT2
+#define SDIO_WIFI_INT BIT3
+#define SOIO_WIFI_WAKE_FUN BIT27
+
+#define SD0_PIN (GPIO_SD0_Clock | GPIO_SD0_Command | GPIO_SD0_WriteProtect | GPIO_SD0_Data)
+#define SD1_PIN (GPIO_SD1_Clock | GPIO_SD1_Command | GPIO_SD1_WriteProtect | GPIO_SD1_RSTN)
+#define SD2_PIN (GPIO_SD2_Clock | GPIO_SD2_Command | GPIO_SD2_WriteProtect | GPIO_SD2_Data)
+
+/* PIN share switch */
+#define GPIO_SD1_PinShare BIT11
+#define GPIO_SD2_PinShare BIT28
+
+#define SD0_CARD_PWR BIT1
+#define SD1_CARD_PWR BIT2
+#define SD2_CARD_PWR BIT3
+
+/* IO Deive Strength and Slew Rate*/
+#define SD0_IO_Slew_Rate BIT1
+#define SD0_IO_Drive_Strength BIT0
+
+
+
+/*common settings*/
+
+#define NR_SG 128
+
+/*=============================================*/
+/* WMT ATSMB Register Offset*/
+/*=============================================*/
+#define _CTL 0x00 /* 1 byte*/
+#define _CMD_IDX 0x01 /* 1 byte*/
+#define _RSP_TYPE 0x02 /* 1 byte*/
+
+#define _CMD_ARG 0x04 /* 4 bytes*/
+#define _BUS_MODE 0x08 /* 1 byte*/
+#define _EXT_BUS_MODE 0x09 /* 1 byte*/
+#define _CTL2 0x0a /* 2 bytes*/
+#define _BLK_LEN 0x0c /* 2 bytes*/
+#define _BLK_CNT 0x0e /* 2 bytes*/
+#define _RSP_0 0x10 /* 1 bytes*/
+#define _RSP_1 0x11 /* 1 bytes*/
+#define _RSP_2 0x12 /* 1 bytes*/
+#define _RSP_3 0x13 /* 1 bytes*/
+#define _RSP_4 0x14 /* 1 bytes*/
+#define _RSP_5 0x15 /* 1 bytes*/
+#define _RSP_6 0x16 /* 1 bytes*/
+#define _RSP_7 0x17 /* 1 bytes*/
+#define _RSP_8 0x18 /* 1 bytes*/
+#define _RSP_9 0x19 /* 1 bytes*/
+#define _RSP_10 0x1a /* 1 bytes*/
+#define _RSP_11 0x1b /* 1 bytes*/
+#define _RSP_12 0x1c /* 1 bytes*/
+#define _RSP_13 0x1d /* 1 bytes*/
+#define _RSP_14 0x1e /* 1 bytes*/
+#define _RSP_15 0x1f /* 1 bytes*/
+
+#define _CURBLK_CNT 0x20 /* 4 bytes*/
+#define _INT_MASK_0 0x24 /* 1 byte*/
+#define _INT_MASK_1 0x25 /* 1 byte*/
+
+#define _SD_STS_0 0x28 /* 1 byte*/
+#define _SD_STS_1 0x29 /* 1 byte*/
+#define _SD_STS_2 0x2a /* 1 byte*/
+#define _SD_STS_3 0x2b /* 1 byte*/
+#define _RSP_TOUT 0x2c /* 1 byte*/
+
+#define _CLK_SEL 0x30 /* 1 byte*/ /*Not used*/
+
+#define _EXT_CTL 0x34 /* 1 byte*/
+#define _EXT_CTL_1 0x35 /* 1 byte*/
+#define _EXT_CTL_2 0x36 /* 1 byte*/
+
+#define _SHDW_BLKLEN 0x38 /* 2 bytes*/
+#define _MAN_TUNE_VAL 0x3a /* 1 byte*/
+#define _SD_WRI_TUNE 0x3b /* 1 byte*/
+#define _TIMER_VAL 0x3c /* 2 bytes*/
+
+
+#define _PDMA_GCR 0x100
+#define _PDMA_IER 0x104
+#define _PDMA_ISR 0x108
+#define _PDMA_DESPR 0x10C
+#define _PDMA_RBR 0x110
+#define _PDMA_DAR 0x114
+#define _PDMA_BAR 0x118
+#define _PDMA_CPR 0x11C
+#define _PDMA_CCR 0X120
+
+
+/*=========================================*/
+/* SD0 PDMA related Registers */
+/*=========================================*/
+#define ATSMB0_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB0_BASE))
+#define ATSMB0_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB0_BASE))
+
+
+/*=========================================*/
+/* SD0 Register pointer. */
+/*=========================================*/
+#define ATSMB0_CTL (REG8_PTR(_CTL + MMC_ATSMB0_BASE))
+#define ATSMB0_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB0_BASE))
+#define ATSMB0_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB0_BASE))
+#define ATSMB0_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB0_BASE))
+#define ATSMB0_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB0_BASE))
+#define ATSMB0_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB0_BASE))
+#define ATSMB0_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB0_BASE))
+#define ATSMB0_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB0_BASE))
+#define ATSMB0_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB0_BASE))
+
+#define ATSMB0_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB0_BASE))
+#define ATSMB0_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB0_BASE))
+#define ATSMB0_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB0_BASE))
+#define ATSMB0_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB0_BASE))
+#define ATSMB0_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB0_BASE))
+#define ATSMB0_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB0_BASE))
+#define ATSMB0_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB0_BASE))
+
+#define ATSMB0_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB0_BASE))
+#define ATSMB0_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB0_BASE))
+#define ATSMB0_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB0_BASE))
+#define ATSMB0_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB0_BASE))
+#define ATSMB0_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB0_BASE))
+
+#define ATSMB0_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB0_BASE))
+#define ATSMB0_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB0_BASE))
+#define ATSMB0_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB0_BASE))
+#define ATSMB0_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB0_BASE))
+
+//#define ATSMB0_INT (REG8_PTR(0xd8140056))
+
+
+
+
+/*=========================================*/
+/* SD1 PDMA related Registers */
+/*=========================================*/
+#define ATSMB1_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB1_BASE))
+#define ATSMB1_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB1_BASE))
+
+
+/*=========================================*/
+/* SD1 Register pointer. */
+/*=========================================*/
+#define ATSMB1_CTL (REG8_PTR(_CTL + MMC_ATSMB1_BASE))
+#define ATSMB1_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB1_BASE))
+#define ATSMB1_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB1_BASE))
+#define ATSMB1_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB1_BASE))
+#define ATSMB1_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB1_BASE))
+#define ATSMB1_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB1_BASE))
+#define ATSMB1_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB1_BASE))
+#define ATSMB1_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB1_BASE))
+#define ATSMB1_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB1_BASE))
+
+#define ATSMB1_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB1_BASE))
+#define ATSMB1_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB1_BASE))
+#define ATSMB1_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB1_BASE))
+#define ATSMB1_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB1_BASE))
+#define ATSMB1_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB1_BASE))
+#define ATSMB1_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB1_BASE))
+#define ATSMB1_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB1_BASE))
+
+#define ATSMB1_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB1_BASE))
+#define ATSMB1_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB1_BASE))
+#define ATSMB1_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB1_BASE))
+#define ATSMB1_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB1_BASE))
+#define ATSMB1_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB1_BASE))
+
+#define ATSMB1_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB1_BASE))
+#define ATSMB1_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB1_BASE))
+#define ATSMB1_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB1_BASE))
+#define ATSMB1_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB1_BASE))
+
+
+
+/*=========================================*/
+/* SD2 PDMA related Registers */
+/*=========================================*/
+#define ATSMB2_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB2_BASE))
+#define ATSMB2_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB2_BASE))
+
+
+/*=========================================*/
+/* SD2 Register pointer. */
+/*=========================================*/
+#define ATSMB2_CTL (REG8_PTR(_CTL + MMC_ATSMB2_BASE))
+#define ATSMB2_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB2_BASE))
+#define ATSMB2_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB2_BASE))
+#define ATSMB2_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB2_BASE))
+#define ATSMB2_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB2_BASE))
+#define ATSMB2_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB2_BASE))
+#define ATSMB2_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB2_BASE))
+#define ATSMB2_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB2_BASE))
+#define ATSMB2_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB2_BASE))
+
+#define ATSMB2_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB2_BASE))
+#define ATSMB2_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB2_BASE))
+#define ATSMB2_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB2_BASE))
+#define ATSMB2_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB2_BASE))
+#define ATSMB2_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB2_BASE))
+#define ATSMB2_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB2_BASE))
+#define ATSMB2_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB2_BASE))
+
+#define ATSMB2_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB2_BASE))
+#define ATSMB2_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB2_BASE))
+#define ATSMB2_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB2_BASE))
+#define ATSMB2_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB2_BASE))
+#define ATSMB2_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB2_BASE))
+
+#define ATSMB2_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB2_BASE))
+#define ATSMB2_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB2_BASE))
+#define ATSMB2_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB2_BASE))
+#define ATSMB2_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB2_BASE))
+
+
+/*=========================================*/
+/* Register usage const*/
+/*=========================================*/
+/*================================================================================*/
+/**/
+/* SD Host Register Bit Fields*/
+/**/
+/*================================================================================*/
+/**/
+/* Control Register*/
+#define ATSMB_START 0x1
+#define ATSMB_SPISTP BIT1
+#define ATSMB_RXTX BIT2
+#define ATSMB_FFRST BIT3
+#define ATSMB_CT (BIT4|BIT5|BIT6|BIT7)
+/**/
+/* Command Index Register*/
+
+/**/
+/*Response Type Register*/
+#define ATSMB_RT (BIT0|BIT1|BIT2|BIT3)
+#define ATSMB_RY BIT4
+
+/**/
+/* Command Argument Register 0,1,2,3*/
+
+/**/
+/* Bus Mode Register*/
+#define ATSMB_SPI BIT0
+#define ATSMB_BUS_WIDTH_4 BIT1
+#define ATSMB_RW BIT2
+#define ATSMB_SPICRC BIT3
+#define ATSMB_CST BIT4
+#define ATSMB_SPICS BIT5
+#define ATSMB_SDPWR BIT6
+#define ATSMB_SFTRST BIT7
+
+/**/
+/* Block Length Register 0,1*/
+#define ATSMB_BS_L (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7)
+#define ATSMB_BS_H (BIT8|BIT9|BIT10)
+#define ATSMB_CFD BIT4
+#define ATSMB_INTEN BIT7
+
+/**/
+/* Block Count Register 0,1*/
+
+/**/
+/* Response Register*/
+
+/**/
+/* Data Register*/
+
+/**/
+/* Interrupt Mask Register 0*/
+#define ATSMB_THIE BIT0
+#define ATSMB_TEIE BIT1
+#define ATSMB_TAIE BIT2
+#define ATSMB_RHIE BIT3
+#define ATSMB_MULTI_XFER_DONE_EN BIT4
+#define ATSMB_BLOCK_XFER_DONE_EN BIT5
+#define ATSMB_CDIE BIT6
+#define ATSMB_DEVICE_INSERT_EN BIT7
+
+/**/
+/* Interrupt Mask Register 1*/
+#define ATSMB_SDIO_EN BIT0
+#define ATSMB_RSP_DONE_EN BIT1
+#define ATSMB_RSP_TIMEOUT_EN BIT2
+#define ATSMB_AUTO_STOP_EN BIT3
+#define ATSMB_DATA_TIMEOUT_EN BIT4
+#define ATSMB_RSP_CRC_ERR_EN BIT5
+#define ATSMB_READ_CRC_ERR_EN BIT6
+#define ATSMB_WRITE_CRC_ERR_EN BIT7
+
+/**/
+/* SD Status Register 0*/
+#define ATSMB_TH BIT0
+#define ATSMB_WRITE_PROTECT BIT1 /* 1. write protected is disabled.*/
+#define ATSMB_CARD_NOT_IN_SLOT BIT2
+#define ATSMB_CARD_NOT_IN_SLOT_GPI BIT3
+#define ATSMB_MULTI_XFER_DONE BIT4
+#define ATSMB_BLOCK_XFER_DONE BIT5
+#define ATSMB_SD_CD BIT6 /* what is its purpose?*/
+#define ATSMB_DEVICE_INSERT BIT7
+
+/**/
+/* SD Status Register 1*/
+#define ATSMB_SDIO_INT BIT0
+#define ATSMB_RSP_DONE BIT1
+#define ATSMB_RSP_TIMEOUT BIT2
+#define ATSMB_AUTO_STOP BIT3
+#define ATSMB_DATA_TIMEOUT BIT4
+#define ATSMB_RSP_CRC_ERR BIT5
+#define ATSMB_READ_CRC_ERR BIT6
+#define ATSMB_WRITE_CRC_ERR BIT7
+
+/**/
+/* SD Status Register 2*/
+#define ATSMB_RSP_BUSY BIT5
+#define ATSMB_CLK_FREEZ_STS BIT6
+#define ATSMB_CLK_FREEZ_EN BIT7
+
+
+/* SD Response types*/
+#define ATMSB_TYPE_R0 0 /* NONE response*/
+#define ATMSB_TYPE_R1 1 /* Basic response format*/
+#define ATMSB_TYPE_R2 2 /* R2 response. Used by ALL_SEND_CID(CMD2),*/
+/* SEND_CID(CMD10) and SEND_CSD(CMD9)*/
+#define ATMSB_TYPE_R3 3 /* R3 response. Used by SEND_APP_OP_COND(ACMD41)*/
+#define ATMSB_TYPE_R6 6 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/
+#define ATMSB_TYPE_R7 7 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/
+#define ATMSB_TYPE_R1b 9
+#define ATMSB_TYPE_R5 5
+#define ATMSB_TYPE_R4 4
+
+/*
+ * SD PDMA
+ */
+struct SD_PDMA_REG {
+ unsigned long DMA_GCR; /* Rx00 */
+ unsigned long DMA_IER; /* Rx04 */
+ unsigned long DMA_ISR; /* Rx08 */
+ unsigned long *DMA_DESPR; /* Rx0C */
+ unsigned long DMA_RBR; /* Rx10 */
+ unsigned long DMA_DAR; /* Rx14 */
+ unsigned long DMA_BAR; /* Rx18 */
+ unsigned long DMA_CPR; /* Rx1C */
+ unsigned long DMA_CCR; /* RX20 */
+ unsigned long resv[5]; /* RX2C-3C */
+};
+/*
+ * SD PDMA - DMA_GCR : DMA Global Control Register
+ */
+#define SD_PDMA_GCR_DMA_EN 0x00000001 /* [0] -- DMA controller enable*/
+#define SD_PDMA_GCR_SOFTRESET 0x00000100 /* [8] -- Software rest*/
+
+/*
+ * SD PDMA - DMA_IER : DMA Interrupt Enable Register
+ */
+#define SD_PDMA_IER_INT_EN 0x00000001 /* [0] --DMA interrupt enable */
+/*
+ * SD PDMA - DMA_ISR : DMA Interrupt Status Register
+ */
+#define SD_PDMA_IER_INT_STS 0x00000001 /* [0] -- DMA interrupt status */
+/*
+ * SD PDMA - DMA_DESPR : DMA Descriptor base address Pointer Register
+ */
+
+/*
+ * SD PDMA - DMA_RBR : DMA Residual Bytes Register
+ */
+#define SD_PDMA_RBR_End 0x80000000 /* [0] -- DMA interrupt status */
+#define SD_PDMA_RBR_Format 0x40000000 /* [0] -- DMA interrupt status */
+/*
+ * SD PDMA - DMA_DAR : DMA Data Address Register
+ */
+
+/*
+ * SD PDMA - DMA_BAR : DMA Rbanch Address Register
+ */
+
+/*
+ * SD PDMA - DMA_CPR : DMA Command Pointer Register
+ */
+
+/*
+ * SD PDMA - DMA_CCR : DMAContext Control Register for Channel 0
+ */
+#define SD_PDMA_READ 0x00
+#define SD_PDMA_WRITE 0x01
+#define SD_PDMA_CCR_RUN 0x00000080
+#define SD_PDMA_CCR_IF_to_peripheral 0x00000000
+#define SD_PDMA_CCR_peripheral_to_IF 0x00400000
+#define SD_PDMA_CCR_EvtCode 0x0000000f
+#define SD_PDMA_CCR_Evt_no_status 0x00000000
+#define SD_PDMA_CCR_Evt_ff_underrun 0x00000001
+#define SD_PDMA_CCR_Evt_ff_overrun 0x00000002
+#define SD_PDMA_CCR_Evt_desp_read 0x00000003
+#define SD_PDMA_CCR_Evt_data_rw 0x00000004
+#define SD_PDMA_CCR_Evt_early_end 0x00000005
+#define SD_PDMA_CCR_Evt_success 0x0000000f
+
+/*
+ * PDMA Descriptor short
+ */
+struct SD_PDMA_DESC_S{
+ unsigned long volatile ReqCount : 16; /* bit 0 -15 -Request count */
+ unsigned long volatile i : 1; /* bit 16 -interrupt */
+ unsigned long volatile reserve : 13; /* bit 17-29 -reserved */
+ unsigned long volatile format : 1; /* bit 30 -The descriptor format */
+ unsigned long volatile end : 1; /* bit 31 -End flag of descriptor list*/
+ unsigned long volatile *DataBufferAddr; /* bit 31 -Data Buffer address */
+} ;
+
+/*
+ * PDMA Descriptor long
+ */
+struct SD_PDMA_DESC_L{
+ unsigned long volatile ReqCount:16; /* bit 0-15-Request count */
+ unsigned long volatile i:1; /* bit 16 -interrupt*/
+ unsigned long volatile reserve:13; /* bit 17-29-reserved*/
+ unsigned long volatile format:1; /* bit 30-The descriptor format */
+ unsigned long volatile end:1; /* bit 31 -End flag of descriptor list*/
+ unsigned long volatile *DataBufferAddr; /* bit 31-0 -Data Buffer address*/
+ unsigned long volatile *BranchAddr; /* bit 31-2-Descriptor Branch address*/
+ unsigned long volatile reserve0; /* bit 31-0-reserved*/
+};
+
+
+/**/
+/* DMA usage const for Rx08[Config]*/
+/**/
+#define DMA_CFG_WRITE 0x0
+#define DMA_CFG_READ 0x10000
+/*
+#define DMA_CFG_8B 0x00
+#define DMA_CFG_16B 0x01
+#define DMA_CFG_32B 0x02
+
+#define DMA_CFG_SINGLE 0x00
+#define DMA_CFG_INC4 0x10
+#define DMA_CFG_INC8 0x20
+
+#define DMA_CFG_DATA 0x100
+#define DMA_CFG_PRIVILEDGE 0x200
+#define DMA_CFG_BUFFER 0x400
+#define DMA_CFG_CACHE 0x800
+
+#define DMA_CFG_INC 0x1000
+#define DMA_CFG_READ 0x10000
+#define DMA_CFG_WRITE 0x0
+
+#define DMA_CFG_NOINT 0x0
+#define DMA_CFG_ENTCINT 0x100000
+#define DMA_CFG_ENXFERINT 0x200000
+#define DMA_CFG_ENERRINT 0x400000
+#define DMA_CFG_ENFIFOINT 0x800000
+
+//
+// DMA usage const for RxC[Control]
+//
+#define DMA_CTL_ENABLE 0x1
+#define DMA_CTL_SOFTREQ 0x10
+
+//
+// DMA usage const for Rx10[Status]
+//
+#define DMA_STS_TC 0x1
+#define DMA_STS_AHB_ERROR 0x4
+#define DMA_STS_FIFO_EMPTY 0x8
+#define DMA_STS_BULK_COMPLETE 0x2
+*/
+/*=========================================*/
+/* structure definition.*/
+/*=========================================*/
+struct atsmb_host {
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct resource *res;
+ void *base;
+ int regular_irq;
+ int dma_irq;
+ /* 2009/01/13 janshiue-s */
+ unsigned long *DescVirAddr;
+ dma_addr_t DescPhyAddr;
+ unsigned int DescSize;
+ unsigned long *BufVirAddr;
+ dma_addr_t BufPhyAddr;
+ unsigned long DmaIntMask;
+ /* 2009/01/13 janshiue-s */
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 pwr;
+ struct mmc_platform_data *plat;
+ unsigned int sg_len;
+ /* pio stuff */
+ struct scatterlist *sg_ptr;
+ unsigned int sg_off;
+ unsigned int size;
+ /* to support sg, we need little loops when requesting data*/
+ u32 opcode;
+ /*this code may different from the one in command. Eg. When we are accessing data*/
+ unsigned char soft_timeout;
+ void *done_data; /* completion data */
+ void (*done)(void *data);/* completion function */
+ int current_clock;
+
+};
+
+#define MAX_DESC_NUM 256
+
+enum WMT_SD_FUN {
+ SD_MMC,
+ SDIO_WIFI,
+ SD_MAX_FUN
+};
+
+int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, int End);
+int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
+
+int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, int End);
+int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
+
+int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, int End);
+int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
+
+
+#endif /* __MMC_ATSMB_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c
new file mode 100755
index 00000000..2cfefbcd
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c
@@ -0,0 +1,2405 @@
+/*++
+linux/drivers/mmc/host/mmc_atsmb1.c
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/memory.h>
+#include <mach/hardware.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include "mmc_atsmb.h"
+//#include <mach/multicard.h>
+#include <mach/irqs.h>
+
+#define mprintk
+
+/* chcek emmc card is fist boot, 1:fisrt boot, 0:suspend/resume */
+int atsmb1_first_boot;
+#if 0
+#define DBG(host, fmt, args...) \
+ pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
+#endif
+#define ATSMB_TIMEOUT_TIME (HZ*2)
+
+//add by jay,for modules support
+static u64 wmt_sdmmc1_dma_mask = 0xffffffffUL;
+static struct resource wmt_sdmmc1_resources[] = {
+ [0] = {
+ .start = SD1_SDIO_MMC_BASE_ADDR,
+ .end = (SD1_SDIO_MMC_BASE_ADDR + 0x3FF),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SDC1,
+ .end = IRQ_SDC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_SDC1_DMA,
+ .end = IRQ_SDC1_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-s*/
+ [3] = {
+ .start = IRQ_PMC_WAKEUP,
+ .end = IRQ_PMC_WAKEUP,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-e*/
+};
+
+
+//
+static void atsmb1_release(struct device * dev) {}
+
+/*#ifdef CONFIG_MMC_DEBUG*/
+#define MORE_INFO
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#define DBGR(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#define DBGR(x...) do { } while (0)
+#endif
+
+/* when Read CRC error occur, and clear read CRC error by software reset.*/
+void atsmb1_copy_reg(int direct)
+{
+ static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ static u32 CMD_ARG, CURBLK_CNT;
+
+ /*direct 0: copy register to memory; 1: copy memory to register.*/
+ if (direct == 0) {
+ CTL = *ATSMB1_CTL;
+ CMD_IDX = *ATSMB1_CMD_IDX;
+ RSP_TYPE = *ATSMB1_RSP_TYPE;
+ CMD_ARG = *ATSMB1_CMD_ARG;
+ BUS_MODE = *ATSMB1_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE;
+ CTL2 = *ATSMB1_CTL2;
+ BLK_LEN = *ATSMB1_BLK_LEN;
+ BLK_CNT = *ATSMB1_BLK_CNT;
+ RSP_0 = *ATSMB1_RSP_0;
+ RSP_1 = *ATSMB1_RSP_1;
+ RSP_2 = *ATSMB1_RSP_2;
+ RSP_3 = *ATSMB1_RSP_3;
+ RSP_4 = *ATSMB1_RSP_4;
+ RSP_5 = *ATSMB1_RSP_5;
+ RSP_6 = *ATSMB1_RSP_6;
+ RSP_7 = *ATSMB1_RSP_7;
+ RSP_8 = *ATSMB1_RSP_8;
+ RSP_9 = *ATSMB1_RSP_9;
+ RSP_10 = *ATSMB1_RSP_10;
+ RSP_11 = *ATSMB1_RSP_11;
+ RSP_12 = *ATSMB1_RSP_12;
+ RSP_13 = *ATSMB1_RSP_13;
+ RSP_14 = *ATSMB1_RSP_14;
+ RSP_15 = *ATSMB1_RSP_15;
+ CURBLK_CNT = *ATSMB1_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB1_INT_MASK_0;
+ INT_MASK_1 = *ATSMB1_INT_MASK_1;
+ SD_STS_0 = *ATSMB1_SD_STS_0;
+ SD_STS_1 = *ATSMB1_SD_STS_1;
+ SD_STS_2 = *ATSMB1_SD_STS_2;
+ SD_STS_3 = *ATSMB1_SD_STS_3;
+ RSP_TOUT = *ATSMB1_RSP_TOUT;
+ CLK_SEL = *ATSMB1_CLK_SEL;
+ EXT_CTL = *ATSMB1_EXT_CTL;
+ EXT_CTL_1 = *ATSMB1_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB1_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB1_TIMER_VAL;
+ } else {
+ *ATSMB1_CTL = CTL;
+ *ATSMB1_CMD_IDX = CMD_IDX;
+ *ATSMB1_RSP_TYPE = RSP_TYPE;
+ *ATSMB1_CMD_ARG = CMD_ARG;
+ *ATSMB1_BUS_MODE = BUS_MODE;
+ *ATSMB1_EXT_BUS_MODE = EXT_BUS_MODE;
+ *ATSMB1_CTL2 = CTL2;
+ *ATSMB1_BLK_LEN = BLK_LEN;
+ *ATSMB1_BLK_CNT = BLK_CNT;
+ *ATSMB1_RSP_0 = RSP_0;
+ *ATSMB1_RSP_1 = RSP_1;
+ *ATSMB1_RSP_2 = RSP_2;
+ *ATSMB1_RSP_3 = RSP_3;
+ *ATSMB1_RSP_4 = RSP_4;
+ *ATSMB1_RSP_5 = RSP_5;
+ *ATSMB1_RSP_6 = RSP_6;
+ *ATSMB1_RSP_7 = RSP_7;
+ *ATSMB1_RSP_8 = RSP_8;
+ *ATSMB1_RSP_9 = RSP_9;
+ *ATSMB1_RSP_10 = RSP_10;
+ *ATSMB1_RSP_11 = RSP_11;
+ *ATSMB1_RSP_12 = RSP_12;
+ *ATSMB1_RSP_13 = RSP_13;
+ *ATSMB1_RSP_14 = RSP_14;
+ *ATSMB1_RSP_15 = RSP_15;
+ *ATSMB1_CURBLK_CNT = CURBLK_CNT;
+ *ATSMB1_INT_MASK_0 = INT_MASK_0;
+ *ATSMB1_INT_MASK_1 = INT_MASK_1;
+ *ATSMB1_SD_STS_0 = SD_STS_0;
+ *ATSMB1_SD_STS_1 = SD_STS_1;
+ *ATSMB1_SD_STS_2 = SD_STS_2;
+ *ATSMB1_SD_STS_3 = SD_STS_3;
+ *ATSMB1_RSP_TOUT = RSP_TOUT;
+ *ATSMB1_CLK_SEL = CLK_SEL;
+ *ATSMB1_EXT_CTL = EXT_CTL;
+ *ATSMB1_EXT_CTL_1 = EXT_CTL_1;
+ *ATSMB1_EXT_CTL_2 = EXT_CTL_2;
+ *ATSMB1_SHDW_BLKLEN = SHDW_BLKLEN;
+ *ATSMB1_MAN_TUNE_VAL = MAN_TUNE_VAL;
+ *ATSMB1_SD_WRI_TUNE = SD_WRI_TUNE;
+ *ATSMB1_TIMER_VAL = TIMER_VAL;
+ }
+}
+
+#if 0
+void atsmb1_dump_reg(struct atsmb_host *host)
+{
+ u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
+ u32 CURBLK_CNT;
+
+ CTL = *ATSMB1_CTL;
+ CMD_IDX = *ATSMB1_CMD_IDX;
+ RSP_TYPE = *ATSMB1_RSP_TYPE;
+ CMD_ARG = *ATSMB1_CMD_ARG;
+ BUS_MODE = *ATSMB1_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE;
+ CTL2 = *ATSMB1_CTL2;
+ BLK_LEN = *ATSMB1_BLK_LEN;
+ BLK_CNT = *ATSMB1_BLK_CNT;
+ RSP_0 = *ATSMB1_RSP_0;
+ RSP_1 = *ATSMB1_RSP_1;
+ RSP_2 = *ATSMB1_RSP_2;
+ RSP_3 = *ATSMB1_RSP_3;
+ RSP_4 = *ATSMB1_RSP_4;
+ RSP_5 = *ATSMB1_RSP_5;
+ RSP_6 = *ATSMB1_RSP_6;
+ RSP_7 = *ATSMB1_RSP_7;
+ RSP_8 = *ATSMB1_RSP_8;
+ RSP_9 = *ATSMB1_RSP_9;
+ RSP_10 = *ATSMB1_RSP_10;
+ RSP_11 = *ATSMB1_RSP_11;
+ RSP_12 = *ATSMB1_RSP_12;
+ RSP_13 = *ATSMB1_RSP_13;
+ RSP_14 = *ATSMB1_RSP_14;
+ RSP_15 = *ATSMB1_RSP_15;
+ CURBLK_CNT = *ATSMB1_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB1_INT_MASK_0;
+ INT_MASK_1 = *ATSMB1_INT_MASK_1;
+ SD_STS_0 = *ATSMB1_SD_STS_0;
+ SD_STS_1 = *ATSMB1_SD_STS_1;
+ SD_STS_2 = *ATSMB1_SD_STS_2;
+ SD_STS_3 = *ATSMB1_SD_STS_3;
+ RSP_TOUT = *ATSMB1_RSP_TOUT;
+ CLK_SEL = *ATSMB1_CLK_SEL;
+ EXT_CTL = *ATSMB1_EXT_CTL;
+ EXT_CTL_1 = *ATSMB1_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB1_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB1_TIMER_VAL;
+
+ PDMA_GCR = *ATSMB1_PDMA_GCR;
+ PDMA_IER = *ATSMB1_PDMA_IER;
+ PDMA_ISR = *ATSMB1_PDMA_ISR;
+ PDMA_DESPR = *ATSMB1_PDMA_DESPR;
+ PDMA_RBR = *ATSMB1_PDMA_RBR;
+ PDMA_DAR = *ATSMB1_PDMA_DAR;
+ PDMA_BAR = *ATSMB1_PDMA_BAR;
+ PDMA_CPR = *ATSMB1_PDMA_CPR;
+ PDMA_CCR = *ATSMB1_PDMA_CCR;
+
+ DBGR("\n+---------------------------Registers----------------------------+\n");
+
+ DBGR("%16s = 0x%8x |", "CTL", CTL);
+ DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
+
+ DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
+ DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
+
+ DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
+ DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
+
+ DBGR("%16s = 0x%8x |", "CTL2", CTL2);
+ DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
+
+ DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
+ DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
+
+ DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
+ DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
+
+ DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
+ DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
+
+ DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
+ DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
+
+ DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
+ DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
+
+ DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
+ DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
+
+ DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
+ DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
+
+ DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
+ DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
+
+ DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
+
+ DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
+ DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
+
+ DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
+ DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
+
+ DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
+
+ DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
+
+ DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
+ DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
+
+ DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
+ DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
+
+ DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
+ DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
+
+ DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
+ DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
+ DBGR("\n+----------------------------------------------------------------+\n");
+}
+#else
+void atsmb1_dump_reg(struct atsmb_host *host) {}
+#endif
+
+unsigned int fmax1 = 515633;
+unsigned int MMC1_DRIVER_VERSION;
+int SD1_function = 0; /*0: normal SD/MMC card reader*/
+int SDXC1_function;
+
+
+int SCC1_ID(void){
+ unsigned short val;
+
+ val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
+ return val;
+}
+
+int get_chip_version1(void) /*2008/05/01 janshiue modify for A1 chip*/
+{
+ u32 tmp;
+
+ tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
+ tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
+ return tmp;
+}
+
+void get_driver_version1(void)
+{
+ if (SCC1_ID() == 0x3426) {
+ if (get_chip_version1() < 0xA1)
+ MMC1_DRIVER_VERSION = MMC_DRV_3426_A0;
+ else if (get_chip_version1() == 0xA1)
+ MMC1_DRIVER_VERSION = MMC_DRV_3426_A1;
+ else
+ MMC1_DRIVER_VERSION = MMC_DRV_3426_A2;
+ } else if (SCC1_ID() == 0x3437) {
+ if (get_chip_version1() < 0xA1)
+ MMC1_DRIVER_VERSION = MMC_DRV_3437_A0;
+ else
+ MMC1_DRIVER_VERSION = MMC_DRV_3437_A1;
+ } else if (SCC1_ID() == 0x3429) {
+ MMC1_DRIVER_VERSION = MMC_DRV_3429;
+ } else if (SCC1_ID() == 0x3451) {
+ if (get_chip_version1() < 0xA1)
+ MMC1_DRIVER_VERSION = MMC_DRV_3451_A0;
+ } else if (SCC1_ID() == 0x3465) {
+ MMC1_DRIVER_VERSION = MMC_DRV_3465;
+ } else if (SCC1_ID() == 0x3445) {
+ MMC1_DRIVER_VERSION = MMC_DRV_3445;
+ } else if (SCC1_ID() == 0x3481) {
+ MMC1_DRIVER_VERSION = MMC_DRV_3481;
+ } else if (SCC1_ID() == 0x3498) {
+ MMC1_DRIVER_VERSION = MMC_DRV_3498;
+ }
+}
+/*2008/10/6 RichardHsu-e*/
+
+/**********************************************************************
+Name : atsmb1_alloc_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline int atsmb1_alloc_desc(struct atsmb_host *host,
+ unsigned int bytes)
+{
+ void *DescPool = NULL;
+ DBG("[%s] s\n",__func__);
+
+ DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
+ if (!DescPool) {
+ DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ DBG("[%s] e1\n",__func__);
+ return -1;
+ }
+ DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ host->DescVirAddr = (unsigned long *)DescPool;
+ host->DescSize = bytes;
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb1_config_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline void atsmb1_config_desc(unsigned long *DescAddr,
+ unsigned long *BufferAddr,
+ unsigned long Blk_Cnt)
+{
+
+ int i = 0 ;
+ unsigned long *CurDes = DescAddr;
+ DBG("[%s] s\n",__func__);
+
+ /* the first Descriptor store for 1 Block data
+ * (512 bytes)
+ */
+ for (i = 0 ; i < 3 ; i++) {
+ atsmb1_init_short_desc(CurDes, 0x80, BufferAddr, 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
+ }
+ if (Blk_Cnt > 1) {
+ atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
+ /* the following Descriptor store the rest Blocks data
+ * (Blk_Cnt - 1) * 512 bytes
+ */
+ atsmb1_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
+ BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ } else {
+ atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb1_config_dma
+Function : To set des/src address, byte count to transfer, and DMA channel settings,
+ and DMA ctrl. register.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb1_config_dma(unsigned long config_dir,
+ unsigned long dma_mask,
+ struct atsmb_host *host)
+{
+ DBG("[%s] s\n",__func__);
+
+ /* Enable DMA */
+ *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ /*open interrupt*/
+ *ATSMB1_PDMA_IER = SD_PDMA_IER_INT_EN;
+ /*Make sure host could co-work with DMA*/
+ *ATSMB1_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
+ /*Set timer timeout value*/
+
+ /*If clock is 390KHz*/
+ if (host->current_clock < 400000)
+ *ATSMB1_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
+ else
+ *ATSMB1_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
+
+ /*clear all DMA INT status for safety*/
+ *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /* hook desc */
+ *ATSMB1_PDMA_DESPR = host->DescPhyAddr;
+ if (config_dir == DMA_CFG_WRITE)
+ *ATSMB1_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
+ else
+ *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
+
+ host->DmaIntMask = dma_mask; /*save success event*/
+
+ *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_RUN;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb1_prep_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb1_prep_cmd(struct atsmb_host *host,
+ u32 opcode,
+ u32 arg,
+ unsigned int flags,
+ u16 blk_len,
+ u16 blk_cnt,
+ unsigned char int_maks_0,
+ unsigned char int_mask_1,
+ unsigned char cmd_type,
+ unsigned char op)
+{
+ DBG("[%s] s\n",__func__);
+
+ /*set cmd operation code and arguments.*/
+ host->opcode = opcode;
+ *ATSMB1_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
+ *ATSMB1_CMD_ARG = arg;
+
+#if 0 /* Fixme to support SPI mode, James Tian*/
+ if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
+ else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1;
+ else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b;
+ else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2;
+ else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3;
+ else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
+ *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ else
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
+#endif
+
+#if 1
+ /*set cmd response type*/
+ switch (flags) {
+ case MMC_RSP_NONE | MMC_CMD_AC:
+ case MMC_RSP_NONE | MMC_CMD_BC:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ case MMC_RSP_R1 | MMC_CMD_ADTC:
+ case MMC_RSP_R1 | MMC_CMD_AC:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1;
+ break;
+ case MMC_RSP_R1B | MMC_CMD_AC:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b;
+ break;
+ case MMC_RSP_R2 | MMC_CMD_BCR:
+ case MMC_RSP_R2 | MMC_CMD_AC:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2;
+ break;
+ case MMC_RSP_R3 | MMC_CMD_BCR:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3;
+ break;
+ case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
+ *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
+ ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ break;
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5;
+ break;
+ case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4;
+ break;
+ default:
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ }
+#endif
+ /*SDIO cmd 52 , 53*/
+ if ((opcode == SD_IO_RW_DIRECT) ||
+ (opcode == SD_IO_RW_EXTENDED)) {
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5;
+ *ATSMB1_RSP_TYPE |= BIT6;
+ }
+ /*SDIO cmd 5*/
+ if ((opcode == SD_IO_SEND_OP_COND) &&
+ ((flags & (MMC_RSP_PRESENT|
+ MMC_RSP_136|
+ MMC_RSP_CRC|
+ MMC_RSP_BUSY|
+ MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
+ *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4;
+ *ATSMB1_RSP_TYPE |= BIT6;
+ }
+
+ /*reset Response FIFO*/
+ *ATSMB1_CTL |= 0x08;
+
+ /* SD Host enable Clock */
+ *ATSMB1_BUS_MODE |= ATSMB_CST;
+
+ /*Set Cmd-Rsp Timeout to be maximum value.*/
+ *ATSMB1_RSP_TOUT = 0xFE;
+
+ /*clear all status registers for safety*/
+ *ATSMB1_SD_STS_0 |= 0xff;
+ *ATSMB1_SD_STS_1 |= 0xff;
+ *ATSMB1_SD_STS_2 |= 0xff;
+ //*ATSMB1_SD_STS_2 |= 0x7f;
+ *ATSMB1_SD_STS_3 |= 0xff;
+
+ //set block length and block count for cmd requesting data
+ *ATSMB1_BLK_LEN &=~(0x07ff);
+ *ATSMB1_BLK_LEN |= blk_len;
+ //*ATSMB1_SHDW_BLKLEN = blk_len;
+ *ATSMB1_BLK_CNT = blk_cnt;
+
+
+ *ATSMB1_INT_MASK_0 |= int_maks_0;
+ *ATSMB1_INT_MASK_1 |= int_mask_1;
+
+ //Set Auto stop for Multi-block access
+ if(cmd_type == 3 || cmd_type == 4)
+ {
+ //auto stop command set.
+ *ATSMB1_EXT_CTL |= 0x01;
+
+/*
+ * Enable transaction abort.
+ * When CRC error occurs, CMD 12 would be automatically issued.
+ * That is why we cannot enable R/W CRC error INTs.
+ * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
+ */
+ *ATSMB1_BLK_LEN |= 0x0800;
+ }
+
+ /*Set read or write*/
+ if (op == 1)
+ *ATSMB1_CTL &= ~(0x04);
+ else if (op == 2)
+ *ATSMB1_CTL |= 0x04;
+
+ /*for Non data access command, command type is 0.*/
+ *ATSMB1_CTL &= 0x0F;
+ *ATSMB1_CTL |= (cmd_type<<4);
+ DBG("[%s] e\n",__func__);
+}
+
+static inline void atsmb1_issue_cmd(void)
+{
+ *ATSMB1_CTL |= ATSMB_START;
+ wmb();
+}
+/**********************************************************************
+Name : atsmb1_request_end
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void
+atsmb1_request_end(struct atsmb_host *host, struct mmc_request *mrq)
+{
+ DBG("[%s] s\n",__func__);
+ /*
+ * Need to drop the host lock here; mmc_request_done may call
+ * back into the driver...
+ */
+ spin_unlock(&host->lock);
+ /*DBG("100");*/
+ mmc_request_done(host->mmc, mrq);
+ /*DBG("101\n");*/
+ spin_lock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb1_data_done
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb1_wait_done(void *data)
+{
+ struct atsmb_host *host = (struct atsmb_host *) data;
+ DBG("[%s] s\n",__func__);
+
+ WARN_ON(host->done_data == NULL);
+ complete(host->done_data);
+ host->done_data = NULL;
+ host->done = NULL;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb1_start_data
+Function : If we start data, there must be only four cases.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb1_start_data(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+ unsigned char cmd_type = 0;
+ unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
+ unsigned char mask_0 = 0;
+ unsigned char mask_1 = 0;
+ unsigned long dma_mask = 0;
+
+ struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+
+ unsigned int total_blks = 0; /*total block number to transfer*/
+ u32 card_addr = 0;
+ unsigned long dma_len = 0;
+ unsigned long total_dma_len = 0;
+ dma_addr_t dma_phy = 0; /* physical address used for DMA*/
+ unsigned int dma_times = 0; /*times dma need to transfer*/
+ unsigned int dma_loop = 0;
+ unsigned int sg_num = 0;
+ int loop_cnt = 10000;
+ unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
+
+ DBG("[%s] s\n",__func__);
+ data->bytes_xfered = 0;
+ cmd->error = 0;
+ data->error = 0;
+
+ /*for loop*/
+ sg = data->sg;
+ sg_len = data->sg_len;
+
+ dma_times = (sg_len / MAX_DESC_NUM);
+ if (sg_len % MAX_DESC_NUM)
+ dma_times++;
+ DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
+ card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
+ total_blks = data->blocks;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+
+ for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
+ DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
+ if (dma_loop < dma_times)
+ sg_transfer_len = MAX_DESC_NUM;
+ else
+ sg_transfer_len = sg_len;
+ DBG("sg_transfer_len = %d\n", sg_transfer_len);
+ /*
+ *Firstly, check and wait till card is in the transfer state.
+ *For our hardware, we can not consider
+ *the card has successfully tranfered its state from data/rcv to trans,
+ *when auto stop INT occurs.
+ */
+ loop_cnt = 10000;
+ do {
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED)
+ break;
+ loop_cnt--;
+ WARN_ON(loop_cnt == 0);
+ host->done_data = &complete;
+ host->done = &atsmb1_wait_done;
+ host->soft_timeout = 1;
+ atsmb1_prep_cmd(host,
+ MMC_SEND_STATUS,
+ (host->mmc->card->rca)<<16,
+ MMC_RSP_R1 | MMC_CMD_AC,
+ 0,
+ 0,
+ 0, /*mask_0*/
+ ATSMB_RSP_DONE_EN
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN,
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb1_issue_cmd();
+ DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB1_INT_MASK_1);
+ DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB1_SD_STS_1);
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ WARN_ON(host->soft_timeout == 1);
+ if (host->soft_timeout == 1) {
+ DBG("%s soft_timeout.\n", __func__);
+ atsmb1_dump_reg(host);
+ }
+ if (cmd->error != MMC_ERR_NONE) {
+ cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("Getting Status failed.\n");
+ goto end;
+ }
+ } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
+ /*SDIO read/write*/
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ /*Single Block read/write*/
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ } else {
+ /*Multiple Block read/write*/
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 6;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 5;
+ op = 2;
+ mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ }
+
+ } else {
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ if (data->flags & MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_SINGLE_BLOCK;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_BLOCK;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ } else { /*more than one*/
+ if (data->flags&MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_MULTIPLE_BLOCK;
+ cmd_type = 4;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ cmd_type = 3;
+ op = 2;
+ mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ }
+ }
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb1_wait_done;
+ /*sleep till ISR wakes us*/
+ host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
+
+ total_dma_len = 0;
+ DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
+ memset(host->DescVirAddr, 0, host->DescSize);
+ for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ total_dma_len = total_dma_len + dma_len;
+ DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
+ sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
+ /*2009/01/15 janshiue add*/
+ if (sg_num < sg_transfer_len - 1) {
+ /* means the last descporitor */
+ atsmb1_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 0);
+ } else {
+ atsmb1_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 1);
+ }
+ /*2009/01/15 janshiue add*/
+
+ }
+ /*operate our hardware*/
+ atsmb1_prep_cmd(host,
+ host->opcode,
+ /*arg, may be byte addressed, may be block addressed.*/
+ card_addr,
+ cmd->flags,
+ data->blksz - 1, /* in fact, it is useless.*/
+ /* for single one, it is useless. but for multi one, */
+ /* it would be used to tell auto stop function whether it is done.*/
+ total_dma_len/(data->blksz),
+ mask_0,
+ mask_1,
+ cmd_type,
+ op);
+
+ atsmb1_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
+ dma_mask,
+ host);
+
+ atsmb1_issue_cmd();
+ wait_for_completion_timeout(&complete,
+ ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
+
+ /* When the address of request plus length equal card bound,
+ * force this stop command response as pass. Eason 2012/4/20 */
+ if (cmd->resp[0] == 0x80000b00) {
+ /*This caes used for SD2.0 and after MMC4.1 version*/
+ if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
+ card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
+ printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
+ }
+
+ /* This caes used for SD1.0 and before MMC 4.1 */
+ if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
+ card_addr,data->blksz,(total_dma_len/data->blksz));*/
+ }
+ }
+
+ if (host->soft_timeout == 1) {
+ atsmb1_dump_reg(host);
+ //*ATSMB1_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ /*disable INT */
+ *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+ cmd->error = -ETIMEDOUT;
+ data->error = -ETIMEDOUT;
+ }
+
+ WARN_ON(host->soft_timeout == 1);
+
+ /*check everything goes okay or not*/
+ if (cmd->error != MMC_ERR_NONE
+ || data->error != MMC_ERR_NONE) {
+ DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
+ cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
+ goto end;
+ }
+// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
+ card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
+ data->bytes_xfered += total_dma_len;
+
+
+ }
+// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
+ host->opcode = 0;
+end:
+ dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ spin_lock(&host->lock);
+ atsmb1_request_end(host, host->mrq);
+ spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+
+/**********************************************************************
+Name : atsmb1_cmd_with_data_back
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb1_cmd_with_data_back(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+ DBG("[%s] s\n",__func__);
+ /*for loop*/
+ sg = host->data->sg;
+ sg_len = host->data->sg_len;
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb1_wait_done;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
+
+ /*2009/01/15 janshiue add*/
+ memset(host->DescVirAddr, 0, host->DescSize);
+ atsmb1_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
+ /*2009/01/15 janshiue add*/
+ /*prepare for cmd*/
+ atsmb1_prep_cmd(host, /*host*/
+ host->cmd->opcode, /*opcode*/
+ host->cmd->arg, /*arg*/
+ host->cmd->flags, /*flags*/
+ sg_dma_len(sg)-1, /*block length*/
+ 0, /*block size: It looks like useless*/
+ 0, /*int_mask_0*/
+ (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
+ |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
+ 2, /*cmd_type*/
+ 1); /*op*/
+
+ atsmb1_config_dma(DMA_CFG_READ,
+ SD_PDMA_CCR_Evt_success,
+ host);
+ atsmb1_issue_cmd();
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
+ ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+ spin_lock(&host->lock);
+ atsmb1_request_end(host, host->mrq);
+ spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb1_start_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb1_start_cmd(struct atsmb_host *host)
+{
+ unsigned char int_mask_0,int_mask_1;
+ int_mask_0 = 0;
+ int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
+
+ DBG("[%s] s\n",__func__);
+
+ atsmb1_prep_cmd(host,
+ host->cmd->opcode,
+ host->cmd->arg,
+ host->cmd->flags,
+ 0, /*useless*/
+ 0, /*useless*/
+ int_mask_0, /*mask_0*/
+ int_mask_1, /*mask_1*/
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb1_issue_cmd();
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb1_fmt_check_rsp
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb1_fmt_check_rsp(struct atsmb_host *host)
+{
+
+ u8 tmp_resp[4] = {0};
+ int i, j, k;
+ DBG("[%s] s\n",__func__);
+ if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
+ for (j = 0, k = 1; j < 4; j++, k++)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k));
+
+ host->cmd->resp[0] = (tmp_resp[0] << 24) |
+ (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
+ } else {
+ for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
+ for (j = 0; j < 4; j++) {
+ if (k < 16)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k));
+ else /* k =16*/
+ tmp_resp[j] = *(ATSMB1_RSP_0);
+ k++;
+ }
+ host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
+ (tmp_resp[2]<<8) | (tmp_resp[3]);
+ }
+ }
+
+ /*
+ * For the situation that we need response,
+ * but response registers give us all zeros, we consider this operation timeout.
+ */
+ if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
+ if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
+ && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
+ host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
+ }
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb1_get_slot_status
+Function : Our host only supports one slot.
+Calls :
+Called by :
+Parameter :
+returns : 1: in slot; 0: not in slot.
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb1_get_slot_status(struct mmc_host *mmc)
+{
+// struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+// unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ status_0 = *ATSMB1_SD_STS_0;
+// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
+ if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
+ DBG("[%s] e1\n",__func__);
+ return ret;
+ } else {
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
+ DBG("[%s] e2\n",__func__);
+ return ret;
+ }
+ DBG("[%s] e3\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb1_init_short_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
+{
+ struct SD_PDMA_DESC_S *CurDes_S;
+ DBG("[%s] s\n",__func__);
+ CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
+ CurDes_S->ReqCount = ReqCount;
+ CurDes_S->i = 0;
+ CurDes_S->format = 0;
+ CurDes_S->DataBufferAddr = BufferAddr;
+ if (End) {
+ CurDes_S->end = 1;
+ CurDes_S->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_init_long_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
+{
+ struct SD_PDMA_DESC_L *CurDes_L;
+ DBG("[%s] s\n",__func__);
+ CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
+ CurDes_L->ReqCount = ReqCount;
+ CurDes_L->i = 0;
+ CurDes_L->format = 1;
+ CurDes_L->DataBufferAddr = BufferAddr;
+ CurDes_L->BranchAddr = BranchAddr;
+ if (End) {
+ CurDes_L->end = 1;
+ CurDes_L->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb1_dma_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static irqreturn_t atsmb1_dma_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3;
+ u32 pdma_event_code = 0;
+ DBG("[%s] s\n",__func__);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+ /*Get INT status*/
+ status_0 = *ATSMB1_SD_STS_0;
+ status_1 = *ATSMB1_SD_STS_1;
+ status_2 = *ATSMB1_SD_STS_2;
+ status_3 = *ATSMB1_SD_STS_3;
+ /* after WM3426 A0 using PDMA */
+ if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+
+ pdma_event_code = *ATSMB1_PDMA_CCR & SD_PDMA_CCR_EvtCode;
+
+ /* clear INT status to notify HW clear EventCode*/
+ *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*printk("dma_isr event code = %X\n", *ATSMB1_PDMA_CCR);*/
+ /*We expect cmd with data sending back or read single block cmd run here.*/
+ if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
+ /*means need to update the data->error and cmd->error*/
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
+ if ( host->data != NULL) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ DBG("dma_isr1 host->data is NULL\n");
+ /*disable INT*/
+ *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ goto out;
+ }
+ }
+ /*else do nothing*/
+ DBG("dma_isr PDMA OK\n");
+ /*atsmb1_dump_reg(host);*/
+ }
+ /*But unluckily, we should also be prepare for all kinds of error situation.*/
+ else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB1_PDMA_CCR);
+ atsmb1_dump_reg(host);
+ }
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
+ atsmb1_fmt_check_rsp(host);
+
+ /*disable INT*/
+ *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ }
+
+ /*wake up some one who is sleeping.*/
+ if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
+ if (host->done_data) {/* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb1_request_end(host, host->mrq); /*for cmd with data sending back.*/
+ }
+
+out:
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e\n",__func__);
+ return IRQ_HANDLED;
+}
+
+/**********************************************************************
+Name : atsmb1_regular_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t atsmb1_regular_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
+ u32 pdma_sts;
+
+ DBG("[%s] s\n",__func__);
+ WARN_ON(host == NULL);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+
+ /*Get INT status*/
+ status_0 = *ATSMB1_SD_STS_0;
+ status_1 = *ATSMB1_SD_STS_1;
+ status_2 = *ATSMB1_SD_STS_2;
+ status_3 = *ATSMB1_SD_STS_3;
+
+ mask_0 = *ATSMB1_INT_MASK_0;
+ mask_1 = *ATSMB1_INT_MASK_1;
+ /*******************************************************
+ card insert interrupt
+ ********************************************************/
+ if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
+ /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
+ && (*ATSMB1_INT_MASK_0 & 0x80)) {
+
+ if (host->mmc->ops->get_slot_status(host->mmc)) {
+ host->mmc->scan_retry = 3;
+ host->mmc->card_scan_status = false;
+ } else {
+ host->mmc->scan_retry = 0;
+ host->mmc->card_scan_status = false;
+ }
+
+ mmc_detect_change(host->mmc, HZ/2);
+ /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
+ //*ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
+ /*Then we clear the INT status*/
+ //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
+ *ATSMB1_SD_STS_0 |= ATSMB_DEVICE_INSERT;
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e1\n",__func__);
+ return IRQ_HANDLED;
+ }
+
+ if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
+ spin_unlock(&host->lock);
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
+
+ enable_irq(irq);
+ DBG("[%s] e2\n",__func__);
+
+ return IRQ_HANDLED;
+ }
+ spin_lock(&host->lock);
+ }
+ pdma_sts = *ATSMB1_PDMA_CCR;
+
+ if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e3\n",__func__);
+ return IRQ_HANDLED;
+ }
+ /*******************************************************
+ command interrupt.
+ *******************************************************/
+ /*for write single block*/
+ if (host->opcode == MMC_WRITE_BLOCK) {
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err1\n",__func__);
+ atsmb1_dump_reg(host);
+ }
+ } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
+ if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
+ && (status_0 & ATSMB_MULTI_XFER_DONE)) {
+ /*If CRC error occurs, I think this INT would not occrs.*/
+ /*okay, that is what we want.*/
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err2\n",__func__);
+ atsmb1_dump_reg(host);
+
+ }
+ } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err3\n",__func__);
+ atsmb1_dump_reg(host);
+ } else if (host->opcode == SD_IO_RW_EXTENDED){
+ /*Write operation*/
+ if (*ATSMB1_CTL & BIT2) {
+ if ((*ATSMB1_CTL & 0xf0) == 0x10) { /*single block write*/
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+
+ } else if ((*ATSMB1_CTL & 0xf0) == 0x50) {
+ if ((status_0 & ATSMB_MULTI_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ }
+ else {
+ /*Read operation*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err5\n",__func__);
+ }
+
+
+ } else {
+/* command, not request data*/
+/* the command which need data sending back,*/
+/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
+/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
+ if (host->data && host->opcode != MMC_SEND_STATUS) {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err6\n",__func__);
+ atsmb1_dump_reg(host);
+ } else { /* Just command, no need data sending back.*/
+ if (status_1 & ATSMB_RSP_DONE) {
+ /*Firstly, check data-response is busy or not.*/
+ if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
+ int i = 10000;
+
+ while (status_2 & ATSMB_RSP_BUSY) {
+ status_2 = *ATSMB1_SD_STS_2;
+ if (--i == 0)
+ break;
+ DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
+ }
+ if (i == 0)
+ printk("[MMC driver] Error :SD data-response always busy!");
+ }
+#if 1
+/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
+/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
+/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
+ if (!atsmb1_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
+ host->cmd->retries = 0; /* No retry.*/
+// host->cmd->error = MMC_ERR_INVALID;
+ host->cmd->error = -EINVAL;
+ } else
+#endif
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
+// host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
+ DBG("[%s] err7\n",__func__);
+ } else {/*or RSP CRC error*/
+// host->cmd->error = MMC_ERR_BADCRC;
+ host->cmd->error = -EILSEQ;
+ DBG("[%s] err8\n",__func__);
+ }
+ atsmb1_dump_reg(host);
+ }
+ }
+ }
+ atsmb1_fmt_check_rsp(host);
+
+ /*disable INT */
+ *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+
+ /*clear INT status. In fact, we will clear again before issuing new command.*/
+ *ATSMB1_SD_STS_0 |= status_0;
+ *ATSMB1_SD_STS_1 |= status_1;
+
+ /* when read CRC error occur, and the status can't write one to clear.
+ * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
+ if ((*ATSMB1_SD_STS_1 & BIT6) == 0x40) {
+ DBG("[%s] host1 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
+ /* Save SD card register */
+ atsmb1_copy_reg(0);
+ /* Software reset */
+ *ATSMB1_BUS_MODE |= BIT7;
+ /* restore SD card register */
+ atsmb1_copy_reg(1);
+ }
+
+ if (*ATSMB1_PDMA_ISR & SD_PDMA_IER_INT_STS)
+ *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*wake up some one who is sleeping.*/
+ if (host->done_data) { /* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb1_request_end(host, host->mrq); /*for cmd without data.*/
+
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e4\n",__func__);
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(atsmb1_regular_isr);
+
+/**********************************************************************
+Name : atsmb1_get_ro
+Function :.
+Calls :
+Called by :
+Parameter :
+returns : 0 : write protection is disabled. 1: write protection is enabled.
+Author : Leo Lee
+History :
+***********************************************************************/
+int atsmb1_get_ro(struct mmc_host *mmc)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+ unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+ spin_lock_irqsave(&host->lock, flags);
+ status_0 = *ATSMB1_SD_STS_0;
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
+ ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb1_dump_host_regs
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb1_dump_host_regs(struct mmc_host *mmc)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ DBG("[%s] s\n",__func__);
+ atsmb1_dump_reg(host);
+ DBG("[%s] e\n",__func__);
+}
+EXPORT_SYMBOL(atsmb1_dump_host_regs);
+
+/**********************************************************************
+Name : atsmb_enable_sdio_irq
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb1_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ DBG("[%s] s enable = %d *ATSMB1_INT_MASK_1 = %x\n",__func__,enable,*ATSMB1_INT_MASK_1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (enable) {
+ *ATSMB1_INT_MASK_1 |= ATSMB_SDIO_EN;
+ } else {
+ *ATSMB1_INT_MASK_1 &= ~ATSMB_SDIO_EN;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+
+}
+/**********************************************************************
+Name : atsmb_request
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb1_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ DBG("[%s] s\n",__func__);
+
+ /* May retry process comes here.*/
+ host->mrq = mrq;
+ host->data = mrq->data;
+ host->cmd = mrq->cmd;
+ host->done_data = NULL;
+ host->done = NULL;
+
+ /*for data request*/
+ if (host->data) {
+ if (host->cmd->opcode == MMC_WRITE_BLOCK
+ || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
+ || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
+ || host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ atsmb1_start_data(host);
+ } else {
+ atsmb1_cmd_with_data_back(host);
+ }
+ } else {
+ atsmb1_start_cmd(host);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb1_set_clock
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Eason Chien
+History :2012/7/19
+***********************************************************************/
+static int atsmb1_set_clock(struct mmc_host *mmc, unsigned int clock)
+{
+ int clock_multiplier = 1;
+ DBG("clock = %u\n",clock);
+
+ if (*ATSMB1_EXT_BUS_MODE & BIT4) /*Enable DDR50*/
+ clock_multiplier = 2;
+
+ if (clock == mmc->f_min) {
+ DBG("[%s]ATSMB1 Host 400KHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier);
+ } else if (clock >= 50000000) {
+ DBG("[%s]ATSMB1 Host 50MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 45 * clock_multiplier);
+ } else if ((clock >= 25000000) && (clock < 50000000)) {
+ DBG("[%s]ATSMB1 Host 25MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 24 * clock_multiplier);
+ } else if ((clock >= 20000000) && (clock < 25000000)) {
+ DBG("[%s]ATSMB1 Host 20MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 20 * clock_multiplier);
+ } else {
+ DBG("[%s]ATSMB1 Host 390KHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier);
+ }
+}
+
+/**********************************************************************
+Name : atsmb1_set_ios
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb1_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ unsigned int strapping;
+
+ DBG("[%s] s\n",__func__);
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (ios->power_mode == MMC_POWER_OFF) {
+ if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
+ if (atsmb1_first_boot) {
+ /*nothing to do for GPIO setting when first boot.*/
+ } else {
+ /* stop SD output clock */
+ *ATSMB1_BUS_MODE &= ~(ATSMB_CST);
+
+ /* disable SD1 Card power */
+ /*set SD1 power pin as GPO pin*/
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+ GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+ /*set internal pull up*/
+ PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
+ /*disable SD1 power*/
+ GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+
+ /* Config SD1 to GPIO */
+ GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
+
+ /* SD1 all pins output low */
+ GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
+ GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
+
+ /* Config SD1 to GPIO */
+ GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
+ GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
+
+ /*Set SD1 CMD pin pull low because SD1CMD has no gpio pin, check with Jim*/
+ /*PULL_CTRL_GP14_NAND_BYTE_VAL &= ~GPIO_SD1_Command;
+ PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_Command;*/
+ }
+ }
+ } else if (ios->power_mode == MMC_POWER_UP) {
+ if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
+ if (atsmb1_first_boot) {
+ /*nothing to do for GPIO setting when first boot.*/
+ } else {
+ /* disable SD Card power */
+ /*set SD1 power pin as GPO pin*/
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+ GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+ /*set internal pull up*/
+ PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
+ /*disable SD1 power*/
+ GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
+
+ /* enable SD1 PIN share */
+ PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare;
+
+ /* do not config GPIO_SD1_CD because ISR has already run,
+ * config card detect will issue ISR storm.
+ */
+ /* Config SD to GPIO */
+ GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
+
+ /* SD all pins output low */
+ GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
+ GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
+
+ /* Config SD to GPO */
+ GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
+ GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
+
+ /* stop SD output clock */
+ *ATSMB1_BUS_MODE &= ~ATSMB_CST;
+
+ /* Pull up/down resister of SD Bus */
+ /*Disable Clock & CMD Pull enable*/
+ PULL_EN_GP14_NAND_BYTE_VAL &= ~(GPIO_SD1_Clock | GPIO_SD1_Command);
+
+ /*Set CD ,WP ,DATA pin pull up*/
+ PULL_CTRL_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data;
+ PULL_CTRL_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD);
+
+ /*Enable CD ,WP ,DATA internal pull*/
+ PULL_EN_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data;
+ PULL_EN_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* enable SD1 power */
+ GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_POWER;
+
+ /* enable SD output clock */
+ *ATSMB1_BUS_MODE |= ATSMB_CST;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Config SD1 back to function */
+ GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD;
+
+ /* terminate emmc boot mode */
+ DBG("[%s] STRAP_STATUS_VAL = 0x%x\n", __func__, STRAP_STATUS_VAL);
+ strapping = STRAP_STATUS_VAL & 0xE;
+ if (strapping == 0x2) {
+ printk("[%s] strapping = 0x%x, terminate boot mode\n", __func__, strapping);
+ *ATSMB1_EXT_BUS_MODE &= ~BIT0;
+ *ATSMB1_BUS_MODE &= ~BIT4;
+ *ATSMB1_BUS_MODE |= BIT4;
+ }
+ }
+ }
+ } else {
+ /*nothing to do when powering on.*/
+ }
+
+ host->current_clock = atsmb1_set_clock(mmc,ios->clock);
+
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ *ATSMB1_EXT_CTL |= (0x04);
+ } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ *ATSMB1_BUS_MODE |= ATSMB_BUS_WIDTH_4;
+ *ATSMB1_EXT_CTL &= ~(0x04);
+ } else {
+ *ATSMB1_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
+ *ATSMB1_EXT_CTL &= ~(0x04);
+ }
+
+#if 1
+ if (ios->timing == MMC_TIMING_SD_HS)
+ *ATSMB1_EXT_CTL &= ~0x80; /*HIGH SPEED MODE hsot1 H_S must be off for wm3498*/
+ else if (ios->timing == MMC_TIMING_MMC_HS)
+ *ATSMB1_EXT_CTL &= ~0x80;
+ else if (ios->timing == MMC_TIMING_UHS_DDR50) {
+ /* enable emmc DDR mode */
+ *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
+ /* enable SD output clock */
+ *ATSMB1_BUS_MODE &= ~ATSMB_CST;
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&host->lock, flags);
+
+ *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
+ /* enable SD output clock */
+ *ATSMB0_BUS_MODE |= ATSMB_CST;
+ /*BIT4~7: PMOS driver strength, BIT8~11: NMOS driver strength */
+ DRV_SPI_NAND_4BYTE_VAL |= (BIT4 |BIT5 | BIT6 | BIT7 | BIT8 | BIT9 | BIT10 | BIT11);
+ }
+#endif
+#if 0 //zhf: marked by James Tian
+ if (ios->ins_en == MMC_INSERT_IRQ_EN)
+ *ATSMB1_INT_MASK_0 |= (0x80);/* or 40?*/
+ else
+ *ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/
+#endif
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+}
+
+
+static const struct mmc_host_ops atsmb1_ops = {
+ .request = atsmb1_request,
+ .set_ios = atsmb1_set_ios,
+ .get_ro = atsmb1_get_ro,
+ .get_slot_status = atsmb1_get_slot_status,
+ .dump_host_regs = atsmb1_dump_host_regs,
+ .enable_sdio_irq = atsmb1_enable_sdio_irq,
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+/**********************************************************************
+Name :atsmb1_probe
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int __init atsmb1_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = NULL;
+ struct atsmb_host *atsmb_host = NULL;
+ struct resource *resource = NULL;
+ int irq[2] = {0};
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+ if (!pdev) {
+ ret = -EINVAL; /* Invalid argument */
+ goto the_end;
+ }
+
+
+ /*Enable SD host clock*/
+ auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0);
+
+ if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
+ /* enable SD1 PIN share */
+ PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare;
+
+ /* Pull up/down resister of SD CD */
+ PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD;
+ PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD;
+
+ /* config CardDetect pin to SD function */
+ GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD;
+ }
+
+ /* support emmc fisrt boot don't setting GPIO*/
+ atsmb1_first_boot = 1; //1:first boot, 0: suspend/resume
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ ret = -ENXIO; /* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
+ goto the_end;
+ }
+#if 0
+ if (!request_mem_region(resource->start, SZ_1K, MMC1_DRIVER_NAME)) {
+ ret = -EBUSY;
+ printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
+ goto the_end ;
+ }
+#endif
+ irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
+ irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
+
+ if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
+ ret = -ENXIO;/* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
+ goto rls_region;
+ }
+
+ /*allocate a standard msp_host structure attached with a atsmb structure*/
+ mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
+ if (!mmc_host) {
+ ret = -ENOMEM;
+ printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
+ goto rls_region;
+ }
+ mmc_host->wmt_host_index = 1; /*to identify host number*/
+
+ dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
+ atsmb_host = mmc_priv(mmc_host);
+
+ mmc_host->ops = &atsmb1_ops;
+
+ mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+
+ mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
+ mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/
+
+ if (SDXC1_function == 1) {
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ
+ | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50;
+ } else if (SDXC1_function == 0) {
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ
+ | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA; /* */ //zhf: marked by James Tian
+ }
+
+ mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
+
+ /*1MB per each request */
+ /*we have a 16 bit block number register, and block length is 512 bytes.*/
+ mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
+ mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
+ mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
+ mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
+
+ /*set the specified host -- ATSMB*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ mmc_host->card_attath_status = card_attach_status_unchange;
+#endif
+ sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
+#if 0
+ atsmb_host->base = ioremap(resource->start, SZ_1K);
+ if (!atsmb_host->base) {
+ printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
+ ret = -ENOMEM;
+ goto fr_host;
+ }
+#endif
+ atsmb_host->base = (void *)resource->start;
+ atsmb_host->mmc = mmc_host;
+ spin_lock_init(&atsmb_host->lock);
+ atsmb_host->res = resource;/* for atsmb_remove*/
+
+ /*disable all interrupt and clear status by resetting controller.*/
+ //*ATSMB1_BUS_MODE |= ATSMB_SFTRST; //emmc card don't execute SW reset. because uboot is done.
+ *ATSMB1_BLK_LEN &= ~(0xa000);
+ *ATSMB1_SD_STS_0 |= 0xff;
+ *ATSMB1_SD_STS_1 |= 0xff;
+
+ /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
+ //if (MMC1_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
+ *ATSMB1_BUS_MODE |= ATSMB_CST;
+
+ atsmb_host->regular_irq = irq[0];
+ atsmb_host->dma_irq = irq[1];
+
+ ret = request_irq(atsmb_host->regular_irq,
+ atsmb1_regular_isr,
+ IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
+ MMC1_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
+ goto unmap;
+ }
+
+ ret = request_irq(atsmb_host->dma_irq,
+ atsmb1_dma_isr,
+ IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
+ MMC1_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
+ goto fr_regular_isr;
+ }
+
+
+
+ /*wait card detect status change*/
+ //msleep(10);
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB1_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
+ *ATSMB1_SD_STS_0 |= 0xff;
+ *ATSMB1_INT_MASK_0 |= 0x80; /*or 0x40?*/
+
+ /*allocation dma descriptor*/
+ ret = atsmb1_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
+ if (ret == -1) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
+ goto fr_dma_isr;
+ }
+ printk(KERN_INFO "WMT ATSMB1 (AHB To SD/MMC1 Bus) controller registered!\n");
+ mmc_add_host(mmc_host,true);
+
+ DBG("[%s] e1\n",__func__);
+ return 0;
+
+fr_dma_isr:
+ free_irq(atsmb_host->dma_irq, atsmb_host);
+fr_regular_isr:
+ free_irq(atsmb_host->regular_irq, atsmb_host);
+unmap:
+ //iounmap(atsmb_host->base);
+//fr_host:
+ dev_set_drvdata(dev, NULL);
+ mmc_free_host(mmc_host);
+rls_region:
+ //release_mem_region(resource->start, SZ_1K);
+the_end:
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB1 probe Failed!\n") ;
+ DBG("[%s] e2\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb1_remove
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb1_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
+ struct atsmb_host *atsmb_host;
+
+ DBG("[%s] s\n",__func__);
+ atsmb_host = mmc_priv(mmc_host);
+ if (!mmc_host || !atsmb_host) {
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB1 remove method failed!\n");
+ DBG("[%s] e1\n",__func__);
+ return -ENXIO;
+ }
+ mmc_remove_host(mmc_host);
+
+ /*disable interrupt by resetting controller -- for safey*/
+ *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB1_BLK_LEN &= ~(0xa000);
+ *ATSMB1_SD_STS_0 |= 0xff;
+ *ATSMB1_SD_STS_1 |= 0xff;
+
+ (void)free_irq(atsmb_host->regular_irq, atsmb_host);
+ (void)free_irq(atsmb_host->dma_irq, atsmb_host);
+ (void)iounmap(atsmb_host->base);
+ (void)release_mem_region(atsmb_host->res->start, SZ_1K);
+ dev_set_drvdata(dev, NULL);
+ /*free dma descriptor*/
+ dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
+ atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
+ (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb_shutdown
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb1_shutdown(struct platform_device *pdev)
+{
+ /*atsmb1_shutdown don't be used now.*/
+ /*struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
+
+ DBG("[%s] s\n",__func__);
+
+ /* turn off clock before emmc card shutdown. */
+ *ATSMB1_BUS_MODE &= ~(ATSMB_CST);
+
+ /*Disable card detect interrupt*/
+ *ATSMB1_INT_MASK_0 &= ~0x80;
+ DBG("[%s] e\n",__func__);
+
+}
+
+/**********************************************************************
+Name : atsmb_suspend
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+#ifdef CONFIG_PM
+static int atsmb1_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ /* after suspend/resume, it isn't first boot*/
+ atsmb1_first_boot = 0;
+
+ if (mmc) {
+ /*struct atsmb_host *host = mmc_priv(mmc);*/
+ ret = mmc_suspend_host(mmc);
+ if (ret == 0) {
+ /*disable all interrupt and clear status by resetting controller. */
+ *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB1_BLK_LEN &= ~(0xa000);
+ *ATSMB1_SD_STS_0 |= 0xff;
+ *ATSMB1_SD_STS_1 |= 0xff;
+
+ }
+ /*disable source clock*/
+ //TODO: SD1 clock en or dis
+ auto_pll_divisor(DEV_SDMMC1, CLK_DISABLE, 0, 0);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*clean SD card attatch status change*/
+ PMCWS_VAL |= BIT20;
+ mmc->card_attath_status = card_attach_status_unchange;
+#endif
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb_resume
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb1_resume(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ /*
+ * enable interrupt, DMA, etc.
+ * Supply power to slot.
+ */
+ if (mmc) {
+ /*enable source clock*/
+ auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0);
+
+ udelay(1);
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB1_BLK_LEN |= (0xa000);
+ *ATSMB1_INT_MASK_0 |= 0x80; /* or 40?*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*modify SD card attatch status change*/
+ if ((PMCWS_VAL & BIT20) && !mmc->bus_dead) {
+ /*card change when suspend mode*/
+ mmc->card_attath_status = card_attach_status_change;
+ /*clean SD card attatch status change*/
+ PMCWS_VAL |= BIT20;
+ }
+#endif
+ ret = mmc_resume_host(mmc);
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+#else
+#define atsmb1_suspend NULL
+#define atsmb1_resume NULL
+#endif
+
+static struct platform_driver atsmb1_driver = {
+ .driver.name = "sdmmc1",
+ //.probe = atsmb1_probe,
+ .remove = atsmb1_remove,
+ .shutdown = atsmb1_shutdown,
+ .suspend = atsmb1_suspend,
+ .resume = atsmb1_resume,
+};
+
+static struct platform_device wmt_sdmmc1_device = {
+ .name = "sdmmc1",
+ .id = 0,
+ .dev = {
+ .dma_mask = &wmt_sdmmc1_dma_mask,
+ .coherent_dma_mask = ~0,
+ .release = atsmb1_release,
+ },
+ .num_resources = ARRAY_SIZE(wmt_sdmmc1_resources),
+ .resource = wmt_sdmmc1_resources,
+};
+
+
+static int __init atsmb1_init(void)
+{
+ int ret;
+ int retval;
+ unsigned char buf[80];
+ int varlen = 80;
+ char *varname = "wmt.sd1.param";
+ int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/
+
+ DBG("[%s] s\n",__func__);
+
+#ifdef CONFIG_MTD_WMT_SF
+ /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%x:%d", &temp, &SD1_function);
+ printk(KERN_ALERT "wmt.sd1.param = %x:%d\n", temp, SD1_function);
+ sd_enable = temp & 0xf;
+ SDXC1_function = (temp >> 4) & 0xf;
+ printk(KERN_ALERT "SD1 ebable = %x, SDXC = %x, function = %x\n",
+ sd_enable, SDXC1_function, SD1_function);
+
+ if (SD1_function < 0 || SD1_function >= SD_MAX_FUN)
+ return -ENODEV;
+ } else {
+ printk(KERN_ALERT "Default wmt.sd1.param = %x:%d\n", temp, SD1_function);
+ }
+#endif
+ /*SD function disable*/
+ if (sd_enable != 1)
+ return -ENODEV;
+
+ get_driver_version1();
+
+ if (platform_device_register(&wmt_sdmmc1_device))//add by jay,for modules support
+ return -1;
+ //ret = platform_driver_register(&atsmb1_driver);
+ ret = platform_driver_probe(&atsmb1_driver, atsmb1_probe);
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+
+static void __exit atsmb1_exit(void)
+{
+ DBG("[%s] s\n",__func__);
+ (void)platform_driver_unregister(&atsmb1_driver);
+ (void)platform_device_unregister(&wmt_sdmmc1_device);//add by jay,for modules support
+ DBG("[%s] e\n",__func__);
+}
+
+module_init(atsmb1_init);
+module_exit(atsmb1_exit);
+module_param(fmax1, uint, 0444);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [AHB to SD/MMC1 Bridge] driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c
new file mode 100755
index 00000000..944e3cc4
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c
@@ -0,0 +1,2855 @@
+/*++
+linux/drivers/mmc/host/mmc_atsmb.c
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/memory.h>
+#include <mach/hardware.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include "mmc_atsmb.h"
+//#include <mach/multicard.h>
+#include <mach/irqs.h>
+#include <linux/mmc/sdio.h>
+#include <linux/gpio.h>
+#include <mach/wmt_iomux.h>
+
+int enable_wifi_irq = 1;
+
+#define MMC2_SDIO_EXT_IRQ (1) /* use sdio ext irq or not */
+
+#if MMC2_SDIO_EXT_IRQ
+static int is_mtk6620 = 0;
+static unsigned int mmc2_sdio_ext_irq = 0;
+static unsigned long mmc2_sdio_ext_irq_flags = 0;
+enum ext_irq_flag {
+ IN_SUSPEND = 0,
+ IRQ_IN_SUSPEND = 1,
+};
+int wmt_mtk6620_intr=0xf; //gpio 15
+#endif
+
+
+static int is_nmc1000 = 0x0;
+static int is_ap6330 = 0;
+int set_bus_dead = 1;
+#define mprintk
+
+#if 0
+#define DBG(host, fmt, args...) \
+ pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
+#endif
+#define ATSMB_TIMEOUT_TIME (HZ*2)
+
+//add by jay,for modules support
+static u64 wmt_sdmmc2_dma_mask = 0xffffffffUL;
+static struct resource wmt_sdmmc2_resources[] = {
+ [0] = {
+ .start = SD2_SDIO_MMC_BASE_ADDR,
+ .end = (SD2_SDIO_MMC_BASE_ADDR + 0x3FF),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SDC2,
+ .end = IRQ_SDC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_SDC2_DMA,
+ .end = IRQ_SDC2_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-s*/
+ [3] = {
+ .start = IRQ_PMC_WAKEUP,
+ .end = IRQ_PMC_WAKEUP,
+ .flags = IORESOURCE_IRQ,
+ },
+ /*2008/10/6 RichardHsu-e*/
+};
+
+struct kobject *atsmb2_kobj;
+struct mmc_host *mmc2_host_attr = NULL;
+//
+static void atsmb2_release(struct device * dev) {}
+
+/*#ifdef CONFIG_MMC_DEBUG*/
+#define MORE_INFO
+#if 0
+#define DBG(x...) printk(KERN_ALERT x)
+#define DBGR(x...) printk(KERN_ALERT x)
+#else
+#define DBG(x...) do { } while (0)
+#define DBGR(x...) do { } while (0)
+#endif
+
+/* when Read CRC error occur, and clear read CRC error by software reset.*/
+void atsmb2_copy_reg(int direct)
+{
+ static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ static u32 CMD_ARG, CURBLK_CNT;
+
+ /*direct 0: copy register to memory; 1: copy memory to register.*/
+ if (direct == 0) {
+ CTL = *ATSMB2_CTL;
+ CMD_IDX = *ATSMB2_CMD_IDX;
+ RSP_TYPE = *ATSMB2_RSP_TYPE;
+ CMD_ARG = *ATSMB2_CMD_ARG;
+ BUS_MODE = *ATSMB2_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE;
+ CTL2 = *ATSMB2_CTL2;
+ BLK_LEN = *ATSMB2_BLK_LEN;
+ BLK_CNT = *ATSMB2_BLK_CNT;
+ RSP_0 = *ATSMB2_RSP_0;
+ RSP_1 = *ATSMB2_RSP_1;
+ RSP_2 = *ATSMB2_RSP_2;
+ RSP_3 = *ATSMB2_RSP_3;
+ RSP_4 = *ATSMB2_RSP_4;
+ RSP_5 = *ATSMB2_RSP_5;
+ RSP_6 = *ATSMB2_RSP_6;
+ RSP_7 = *ATSMB2_RSP_7;
+ RSP_8 = *ATSMB2_RSP_8;
+ RSP_9 = *ATSMB2_RSP_9;
+ RSP_10 = *ATSMB2_RSP_10;
+ RSP_11 = *ATSMB2_RSP_11;
+ RSP_12 = *ATSMB2_RSP_12;
+ RSP_13 = *ATSMB2_RSP_13;
+ RSP_14 = *ATSMB2_RSP_14;
+ RSP_15 = *ATSMB2_RSP_15;
+ CURBLK_CNT = *ATSMB2_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB2_INT_MASK_0;
+ INT_MASK_1 = *ATSMB2_INT_MASK_1;
+ SD_STS_0 = *ATSMB2_SD_STS_0;
+ SD_STS_1 = *ATSMB2_SD_STS_1;
+ SD_STS_2 = *ATSMB2_SD_STS_2;
+ SD_STS_3 = *ATSMB2_SD_STS_3;
+ RSP_TOUT = *ATSMB2_RSP_TOUT;
+ CLK_SEL = *ATSMB2_CLK_SEL;
+ EXT_CTL = *ATSMB2_EXT_CTL;
+ EXT_CTL_1 = *ATSMB2_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB2_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB2_TIMER_VAL;
+ } else {
+ *ATSMB2_CTL = CTL;
+ *ATSMB2_CMD_IDX = CMD_IDX;
+ *ATSMB2_RSP_TYPE = RSP_TYPE;
+ *ATSMB2_CMD_ARG = CMD_ARG;
+ *ATSMB2_BUS_MODE = BUS_MODE;
+ *ATSMB2_EXT_BUS_MODE = EXT_BUS_MODE;
+ *ATSMB2_CTL2 = CTL2;
+ *ATSMB2_BLK_LEN = BLK_LEN;
+ *ATSMB2_BLK_CNT = BLK_CNT;
+ *ATSMB2_RSP_0 = RSP_0;
+ *ATSMB2_RSP_1 = RSP_1;
+ *ATSMB2_RSP_2 = RSP_2;
+ *ATSMB2_RSP_3 = RSP_3;
+ *ATSMB2_RSP_4 = RSP_4;
+ *ATSMB2_RSP_5 = RSP_5;
+ *ATSMB2_RSP_6 = RSP_6;
+ *ATSMB2_RSP_7 = RSP_7;
+ *ATSMB2_RSP_8 = RSP_8;
+ *ATSMB2_RSP_9 = RSP_9;
+ *ATSMB2_RSP_10 = RSP_10;
+ *ATSMB2_RSP_11 = RSP_11;
+ *ATSMB2_RSP_12 = RSP_12;
+ *ATSMB2_RSP_13 = RSP_13;
+ *ATSMB2_RSP_14 = RSP_14;
+ *ATSMB2_RSP_15 = RSP_15;
+ *ATSMB2_CURBLK_CNT = CURBLK_CNT;
+ *ATSMB2_INT_MASK_0 = INT_MASK_0;
+ *ATSMB2_INT_MASK_1 = INT_MASK_1;
+ *ATSMB2_SD_STS_0 = SD_STS_0;
+ *ATSMB2_SD_STS_1 = SD_STS_1;
+ *ATSMB2_SD_STS_2 = SD_STS_2;
+ *ATSMB2_SD_STS_3 = SD_STS_3;
+ *ATSMB2_RSP_TOUT = RSP_TOUT;
+ *ATSMB2_CLK_SEL = CLK_SEL;
+ *ATSMB2_EXT_CTL = EXT_CTL;
+ *ATSMB2_EXT_CTL_1 = EXT_CTL_1;
+ *ATSMB2_EXT_CTL_2 = EXT_CTL_2;
+ *ATSMB2_SHDW_BLKLEN = SHDW_BLKLEN;
+ *ATSMB2_MAN_TUNE_VAL = MAN_TUNE_VAL;
+ *ATSMB2_SD_WRI_TUNE = SD_WRI_TUNE;
+ *ATSMB2_TIMER_VAL = TIMER_VAL;
+ }
+}
+
+#if 0
+void atsmb2_dump_reg(struct atsmb_host *host)
+{
+ u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
+ u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
+ u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
+ u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
+ u8 RSP_TOUT, CLK_SEL, EXT_CTL;
+ u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
+ u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
+ u32 CURBLK_CNT;
+
+ CTL = *ATSMB2_CTL;
+ CMD_IDX = *ATSMB2_CMD_IDX;
+ RSP_TYPE = *ATSMB2_RSP_TYPE;
+ CMD_ARG = *ATSMB2_CMD_ARG;
+ BUS_MODE = *ATSMB2_BUS_MODE;
+ EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE;
+ CTL2 = *ATSMB2_CTL2;
+ BLK_LEN = *ATSMB2_BLK_LEN;
+ BLK_CNT = *ATSMB2_BLK_CNT;
+ RSP_0 = *ATSMB2_RSP_0;
+ RSP_1 = *ATSMB2_RSP_1;
+ RSP_2 = *ATSMB2_RSP_2;
+ RSP_3 = *ATSMB2_RSP_3;
+ RSP_4 = *ATSMB2_RSP_4;
+ RSP_5 = *ATSMB2_RSP_5;
+ RSP_6 = *ATSMB2_RSP_6;
+ RSP_7 = *ATSMB2_RSP_7;
+ RSP_8 = *ATSMB2_RSP_8;
+ RSP_9 = *ATSMB2_RSP_9;
+ RSP_10 = *ATSMB2_RSP_10;
+ RSP_11 = *ATSMB2_RSP_11;
+ RSP_12 = *ATSMB2_RSP_12;
+ RSP_13 = *ATSMB2_RSP_13;
+ RSP_14 = *ATSMB2_RSP_14;
+ RSP_15 = *ATSMB2_RSP_15;
+ CURBLK_CNT = *ATSMB2_CURBLK_CNT;
+ INT_MASK_0 = *ATSMB2_INT_MASK_0;
+ INT_MASK_1 = *ATSMB2_INT_MASK_1;
+ SD_STS_0 = *ATSMB2_SD_STS_0;
+ SD_STS_1 = *ATSMB2_SD_STS_1;
+ SD_STS_2 = *ATSMB2_SD_STS_2;
+ SD_STS_3 = *ATSMB2_SD_STS_3;
+ RSP_TOUT = *ATSMB2_RSP_TOUT;
+ CLK_SEL = *ATSMB2_CLK_SEL;
+ EXT_CTL = *ATSMB2_EXT_CTL;
+ EXT_CTL_1 = *ATSMB2_EXT_CTL_1;
+ EXT_CTL_2 = *ATSMB2_EXT_CTL_2;
+ SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN;
+ MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL;
+ SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE;
+ TIMER_VAL = *ATSMB2_TIMER_VAL;
+
+ PDMA_GCR = *ATSMB2_PDMA_GCR;
+ PDMA_IER = *ATSMB2_PDMA_IER;
+ PDMA_ISR = *ATSMB2_PDMA_ISR;
+ PDMA_DESPR = *ATSMB2_PDMA_DESPR;
+ PDMA_RBR = *ATSMB2_PDMA_RBR;
+ PDMA_DAR = *ATSMB2_PDMA_DAR;
+ PDMA_BAR = *ATSMB2_PDMA_BAR;
+ PDMA_CPR = *ATSMB2_PDMA_CPR;
+ PDMA_CCR = *ATSMB2_PDMA_CCR;
+
+ DBGR("\n+---------------------------Registers----------------------------+\n");
+
+ DBGR("%16s = 0x%8x |", "CTL", CTL);
+ DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
+
+ DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
+ DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
+
+ DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
+ DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
+
+ DBGR("%16s = 0x%8x |", "CTL2", CTL2);
+ DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
+
+ DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
+ DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
+
+ DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
+ DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
+
+ DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
+ DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
+
+ DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
+ DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
+
+ DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
+ DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
+
+ DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
+ DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
+
+ DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
+ DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
+
+ DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
+ DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
+
+ DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
+
+ DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
+ DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
+
+ DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
+ DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
+
+ DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
+ DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
+
+ DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
+
+ DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
+ DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
+
+ DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
+ DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
+
+ DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
+ DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
+
+ DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
+ DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
+
+ DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
+ DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
+ DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
+
+ DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
+ DBGR("\n+----------------------------------------------------------------+\n");
+}
+#else
+void atsmb2_dump_reg(struct atsmb_host *host) {}
+#endif
+
+unsigned int fmax2 = 515633;
+unsigned int MMC2_DRIVER_VERSION;
+int SD2_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/
+int SDXC2_function;
+
+int SCC2_ID(void){
+ unsigned short val;
+
+ val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
+ return val;
+}
+
+int get_chip_version2(void) /*2008/05/01 janshiue modify for A1 chip*/
+{
+ u32 tmp;
+
+ tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
+ tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
+ return tmp;
+}
+
+void get_driver_version2(void)
+{
+ if (SCC2_ID() == 0x3426) {
+ if (get_chip_version2() < 0xA1)
+ MMC2_DRIVER_VERSION = MMC_DRV_3426_A0;
+ else if (get_chip_version2() == 0xA1)
+ MMC2_DRIVER_VERSION = MMC_DRV_3426_A1;
+ else
+ MMC2_DRIVER_VERSION = MMC_DRV_3426_A2;
+ } else if (SCC2_ID() == 0x3437) {
+ if (get_chip_version2() < 0xA1)
+ MMC2_DRIVER_VERSION = MMC_DRV_3437_A0;
+ else
+ MMC2_DRIVER_VERSION = MMC_DRV_3437_A1;
+ } else if (SCC2_ID() == 0x3429) {
+ MMC2_DRIVER_VERSION = MMC_DRV_3429;
+ } else if (SCC2_ID() == 0x3451) {
+ if (get_chip_version2() < 0xA1)
+ MMC2_DRIVER_VERSION = MMC_DRV_3451_A0;
+ } else if (SCC2_ID() == 0x3465) {
+ MMC2_DRIVER_VERSION = MMC_DRV_3465;
+ } else if (SCC2_ID() == 0x3445) {
+ MMC2_DRIVER_VERSION = MMC_DRV_3445;
+ } else if (SCC2_ID() == 0x3481) {
+ MMC2_DRIVER_VERSION = MMC_DRV_3481;
+ } else if (SCC2_ID() == 0x3498) {
+ MMC2_DRIVER_VERSION = MMC_DRV_3498;
+ }
+}
+/*2008/10/6 RichardHsu-e*/
+
+/**********************************************************************
+Name : atsmb2_alloc_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline int atsmb2_alloc_desc(struct atsmb_host *host,
+ unsigned int bytes)
+{
+ void *DescPool = NULL;
+ DBG("[%s] s\n",__func__);
+
+ DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
+ if (!DescPool) {
+ DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ DBG("[%s] e1\n",__func__);
+ return -1;
+ }
+ DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
+ host->DescVirAddr = (unsigned long *)DescPool;
+ host->DescSize = bytes;
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb2_config_desc
+Function : To config PDMA descriptor setting.
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+static inline void atsmb2_config_desc(unsigned long *DescAddr,
+ unsigned long *BufferAddr,
+ unsigned long Blk_Cnt)
+{
+
+ int i = 0 ;
+ unsigned long *CurDes = DescAddr;
+ DBG("[%s] s\n",__func__);
+
+ /* the first Descriptor store for 1 Block data
+ * (512 bytes)
+ */
+ for (i = 0 ; i < 3 ; i++) {
+ atsmb2_init_short_desc(CurDes, 0x80, BufferAddr, 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
+ }
+ if (Blk_Cnt > 1) {
+ atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
+ BufferAddr += 0x20;
+ CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
+ /* the following Descriptor store the rest Blocks data
+ * (Blk_Cnt - 1) * 512 bytes
+ */
+ atsmb2_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
+ BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ } else {
+ atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb2_config_dma
+Function : To set des/src address, byte count to transfer, and DMA channel settings,
+ and DMA ctrl. register.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb2_config_dma(unsigned long config_dir,
+ unsigned long dma_mask,
+ struct atsmb_host *host)
+{
+
+ DBG("[%s] s\n",__func__);
+ /* Enable DMA */
+ *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
+ /*open interrupt*/
+ *ATSMB2_PDMA_IER = SD_PDMA_IER_INT_EN;
+ /*Make sure host could co-work with DMA*/
+ *ATSMB2_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
+
+ /*Set timer timeout value*/
+ /*If clock is 390KHz*/
+ if (host->current_clock < 400000)
+ *ATSMB2_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
+ else
+ *ATSMB2_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
+
+ /*clear all DMA INT status for safety*/
+ *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /* hook desc */
+ *ATSMB2_PDMA_DESPR = host->DescPhyAddr;
+ if (config_dir == DMA_CFG_WRITE)
+ *ATSMB2_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
+ else
+ *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
+
+ host->DmaIntMask = dma_mask; /*save success event*/
+
+ *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_RUN;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb2_prep_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb2_prep_cmd(struct atsmb_host *host,
+ u32 opcode,
+ u32 arg,
+ unsigned int flags,
+ u16 blk_len,
+ u16 blk_cnt,
+ unsigned char int_maks_0,
+ unsigned char int_mask_1,
+ unsigned char cmd_type,
+ unsigned char op)
+{
+ unsigned long spl_flags; /* add by th */
+ DBG("[%s] s\n",__func__);
+
+ /*set cmd operation code and arguments.*/
+ host->opcode = opcode;
+ *ATSMB2_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
+ *ATSMB2_CMD_ARG = arg;
+
+#if 0 /* Fixme to support SPI mode, James Tian*/
+ if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
+ else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1;
+ else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b;
+ else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2;
+ else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3;
+ else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
+ *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ else
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
+#endif
+
+#if 1
+ /*set cmd response type*/
+ switch (flags) {
+ case MMC_RSP_NONE | MMC_CMD_AC:
+ case MMC_RSP_NONE | MMC_CMD_BC:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ case MMC_RSP_R1 | MMC_CMD_ADTC:
+ case MMC_RSP_R1 | MMC_CMD_AC:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1;
+ break;
+ case MMC_RSP_R1B | MMC_CMD_AC:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b;
+ break;
+ case MMC_RSP_R2 | MMC_CMD_BCR:
+ case MMC_RSP_R2 | MMC_CMD_AC:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2;
+ break;
+ case MMC_RSP_R3 | MMC_CMD_BCR:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3;
+ break;
+ case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
+ *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
+ ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
+ break;
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
+ case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5;
+ break;
+ case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4;
+ break;
+ default:
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
+ break;
+ }
+#endif
+ /*SDIO cmd 52 , 53*/
+ if ((opcode == SD_IO_RW_DIRECT) ||
+ (opcode == SD_IO_RW_EXTENDED)) {
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5;
+ *ATSMB2_RSP_TYPE |= BIT6;
+ }
+ /*SDIO cmd 5*/
+ if ((opcode == SD_IO_SEND_OP_COND) &&
+ ((flags & (MMC_RSP_PRESENT|
+ MMC_RSP_136|
+ MMC_RSP_CRC|
+ MMC_RSP_BUSY|
+ MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
+ *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4;
+ *ATSMB2_RSP_TYPE |= BIT6;
+ }
+
+ /*reset Response FIFO*/
+ *ATSMB2_CTL |= 0x08;
+
+ /* SD Host enable Clock */
+ *ATSMB2_BUS_MODE |= ATSMB_CST;
+
+ /*Set Cmd-Rsp Timeout to be maximum value.*/
+ *ATSMB2_RSP_TOUT = 0xFE;
+
+ /*clear all status registers for safety*/
+ *ATSMB2_SD_STS_0 |= 0xff;
+ *ATSMB2_SD_STS_1 |= 0xff;
+ *ATSMB2_SD_STS_2 |= 0xff;
+ //*ATSMB2_SD_STS_2 |= 0x7f;
+ *ATSMB2_SD_STS_3 |= 0xff;
+
+ //set block length and block count for cmd requesting data
+ *ATSMB2_BLK_LEN &=~(0x07ff);
+ *ATSMB2_BLK_LEN |= blk_len;
+ //*ATSMB2_SHDW_BLKLEN = blk_len;
+ *ATSMB2_BLK_CNT = blk_cnt;
+
+
+ *ATSMB2_INT_MASK_0 |= int_maks_0;
+
+ /* spin_lock add by th for fix sdio irq*/
+ spin_lock_irqsave(&host->lock, spl_flags);
+ *ATSMB2_INT_MASK_1 |= int_mask_1;
+ spin_unlock_irqrestore(&host->lock, spl_flags);
+
+ //Set Auto stop for Multi-block access
+ if(cmd_type == 3 || cmd_type == 4)
+ {
+ //auto stop command set.
+ *ATSMB2_EXT_CTL |= 0x01;
+
+/*
+ * Enable transaction abort.
+ * When CRC error occurs, CMD 12 would be automatically issued.
+ * That is why we cannot enable R/W CRC error INTs.
+ * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
+ */
+ *ATSMB2_BLK_LEN |= 0x0800;
+ }
+
+ /*Set read or write*/
+ if (op == 1)
+ *ATSMB2_CTL &= ~(0x04);
+ else if (op == 2)
+ *ATSMB2_CTL |= 0x04;
+
+ /*for Non data access command, command type is 0.*/
+ *ATSMB2_CTL &= 0x0F;
+ *ATSMB2_CTL |= (cmd_type<<4);
+ DBG("[%s] e\n",__func__);
+}
+
+static inline void atsmb2_issue_cmd(void)
+{
+ *ATSMB2_CTL |= ATSMB_START;
+ wmb();
+}
+/**********************************************************************
+Name : atsmb2_request_end
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void
+atsmb2_request_end(struct atsmb_host *host, struct mmc_request *mrq)
+{
+ DBG("[%s] s\n",__func__);
+ /*
+ * Need to drop the host lock here; mmc_request_done may call
+ * back into the driver...
+ */
+ //kevin delete spin lock
+ //spin_unlock(&host->lock);
+ /*DBG("100");*/
+ mmc_request_done(host->mmc, mrq);
+ /*DBG("101\n");*/
+ //spin_lock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+Name : atsmb2_data_done
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb2_wait_done(void *data)
+{
+ struct atsmb_host *host = (struct atsmb_host *) data;
+ DBG("[%s] s\n",__func__);
+
+ WARN_ON(host->done_data == NULL);
+ complete(host->done_data);
+ host->done_data = NULL;
+ host->done = NULL;
+ DBG("[%s] e\n",__func__);
+}
+
+/**********************************************************************
+wait_data_busy
+waiting for previous data transfer done
+**********************************************************************/
+void wait_data_busy(struct mmc_command *cmd)
+{
+ int wait_count = 500000;
+
+ switch(cmd->opcode) {
+ case MMC_GO_IDLE_STATE:
+ case MMC_STOP_TRANSMISSION:
+ case MMC_SEND_STATUS:
+ case MMC_GO_INACTIVE_STATE:
+ break;
+ default:
+ do {
+ if (*ATSMB2_CURBLK_CNT & (0x01<<24))
+ break;
+
+ udelay(1);
+
+ } while (--wait_count);
+ }
+
+}
+/**********************************************************************
+Name : atsmb2_start_data
+Function : If we start data, there must be only four cases.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb2_start_data(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+ unsigned char cmd_type = 0;
+ unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
+ unsigned char mask_0 = 0;
+ unsigned char mask_1 = 0;
+ unsigned long dma_mask = 0;
+
+ struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+
+ unsigned int total_blks = 0; /*total block number to transfer*/
+ u32 card_addr = 0;
+ unsigned long dma_len = 0;
+ unsigned long total_dma_len = 0;
+ dma_addr_t dma_phy = 0; /* physical address used for DMA*/
+ unsigned int dma_times = 0; /*times dma need to transfer*/
+ unsigned int dma_loop = 0;
+ unsigned int sg_num = 0;
+ int loop_cnt = 10000;
+ unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
+
+ DBG("[%s] s\n",__func__);
+ data->bytes_xfered = 0;
+ cmd->error = 0;
+ data->error = 0;
+
+ /*for loop*/
+ sg = data->sg;
+ sg_len = data->sg_len;
+
+ dma_times = (sg_len / MAX_DESC_NUM);
+ if (sg_len % MAX_DESC_NUM)
+ dma_times++;
+ DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
+ card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
+ total_blks = data->blocks;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+
+ for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
+ DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
+ if (dma_loop < dma_times)
+ sg_transfer_len = MAX_DESC_NUM;
+ else
+ sg_transfer_len = sg_len;
+ DBG("sg_transfer_len = %d\n", sg_transfer_len);
+ /*
+ *Firstly, check and wait till card is in the transfer state.
+ *For our hardware, we can not consider
+ *the card has successfully tranfered its state from data/rcv to trans,
+ *when auto stop INT occurs.
+ */
+ loop_cnt = 10000;
+ do {
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED)
+ break;
+ loop_cnt--;
+ WARN_ON(loop_cnt == 0);
+ host->done_data = &complete;
+ host->done = &atsmb2_wait_done;
+ host->soft_timeout = 1;
+ atsmb2_prep_cmd(host,
+ MMC_SEND_STATUS,
+ (host->mmc->card->rca)<<16,
+ MMC_RSP_R1 | MMC_CMD_AC,
+ 0,
+ 0,
+ 0, /*mask_0*/
+ ATSMB_RSP_DONE_EN
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN,
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb2_issue_cmd();
+ DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB2_INT_MASK_1);
+ DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB2_SD_STS_1);
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ WARN_ON(host->soft_timeout == 1);
+ if (host->soft_timeout == 1) {
+ DBG("%s soft_timeout.\n", __func__);
+ atsmb2_dump_reg(host);
+ }
+ if (cmd->error != MMC_ERR_NONE) {
+ cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("Getting Status failed.\n");
+ goto end;
+ }
+ } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
+ /*SDIO read/write*/
+ if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ /*Single Block read/write*/
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (//ATSMB_SDIO_EN
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ } else {
+ /*Multiple Block read/write*/
+ /* read operation*/
+ if (data->flags & MMC_DATA_READ) {
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 6;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ } else {
+ /* write operation*/
+ host->opcode = SD_IO_RW_EXTENDED;
+ cmd_type = 5;
+ op = 2;
+ mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
+ ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
+ __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
+ }
+ }
+
+ } else {
+ if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
+ if (data->flags & MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_SINGLE_BLOCK;
+ cmd_type = 2;
+ op = 1;
+ mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
+ mask_1 = (ATSMB_READ_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = SD_PDMA_CCR_Evt_success;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_BLOCK;
+ cmd_type = 1;
+ op = 2;
+ /*====That is what we want===== DMA TC INT skipped*/
+ mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
+ mask_1 = (ATSMB_WRITE_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ } else { /*more than one*/
+ if (data->flags&MMC_DATA_READ) {/* read operation*/
+ host->opcode = MMC_READ_MULTIPLE_BLOCK;
+ cmd_type = 4;
+ op = 1;
+ mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ } else {/*write operation*/
+ host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ cmd_type = 3;
+ op = 2;
+ mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
+ mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
+ |ATSMB_DATA_TIMEOUT_EN
+ /*Data Timeout and CRC error */
+ |ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_RSP_TIMEOUT_EN);
+ /*Resp Timeout and CRC error */
+ dma_mask = 0;
+ }
+ }
+ }
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb2_wait_done;
+ /*sleep till ISR wakes us*/
+ host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
+
+ total_dma_len = 0;
+ DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
+ memset(host->DescVirAddr, 0, host->DescSize);
+ for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
+
+ /*
+ * Now, we can safely issue read/write command.
+ * We can not consider this request as multi-block acess or single one via opcode,
+ * as request is splitted into sgs.
+ * Some sgs may be single one, some sgs may be multi one.
+ */
+
+ dma_phy = sg_dma_address(sg);
+ dma_len = sg_dma_len(sg);
+ total_dma_len = total_dma_len + dma_len;
+ DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
+ sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
+ /*2009/01/15 janshiue add*/
+ if (sg_num < sg_transfer_len - 1) {
+ /* means the last descporitor */
+ atsmb2_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 0);
+ } else {
+ atsmb2_init_short_desc(
+ host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
+ dma_len, (unsigned long *)dma_phy, 1);
+ }
+ /*2009/01/15 janshiue add*/
+
+ }
+ /*operate our hardware*/
+ atsmb2_prep_cmd(host,
+ host->opcode,
+ /*arg, may be byte addressed, may be block addressed.*/
+ card_addr,
+ cmd->flags,
+ data->blksz - 1, /* in fact, it is useless.*/
+ /* for single one, it is useless. but for multi one, */
+ /* it would be used to tell auto stop function whether it is done.*/
+ total_dma_len/(data->blksz),
+ mask_0,
+ mask_1,
+ cmd_type,
+ op);
+
+ atsmb2_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
+ dma_mask,
+ host);
+
+ wait_data_busy(cmd);
+ //sync from tp,fix broadcom 6181 wifi dongle crash.
+ //udelay(10);
+ atsmb2_issue_cmd();
+ wait_for_completion_timeout(&complete,
+ ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
+
+ /* When the address of request plus length equal card bound,
+ * force this stop command response as pass. Eason 2012/4/20 */
+ if (cmd->resp[0] == 0x80000b00) {
+ /*This caes used for SD2.0 and after MMC4.1 version*/
+ if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
+ card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
+ printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
+ }
+
+ /* This caes used for SD1.0 and before MMC 4.1 */
+ if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
+ cmd->resp[0] = 0x00000b00;
+ /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
+ card_addr,data->blksz,(total_dma_len/data->blksz));*/
+ }
+ }
+
+ if (host->soft_timeout == 1) {
+ atsmb2_dump_reg(host);
+ //*ATSMB2_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
+ /*disable INT */
+ *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+ cmd->error = -ETIMEDOUT;
+ data->error = -ETIMEDOUT;
+ }
+
+ WARN_ON(host->soft_timeout == 1);
+
+ /*check everything goes okay or not*/
+ if (cmd->error != MMC_ERR_NONE
+ || data->error != MMC_ERR_NONE) {
+ DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
+ cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
+ goto end;
+ }
+// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
+ card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
+ data->bytes_xfered += total_dma_len;
+
+
+ }
+// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
+ host->opcode = 0;
+end:
+ dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
+ ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ //kevin delete spin lock
+ //spin_lock(&host->lock);
+ atsmb2_request_end(host, host->mrq);
+ //spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+
+
+/**********************************************************************
+Name : atsmb2_cmd_with_data_back
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb2_cmd_with_data_back(struct atsmb_host *host)
+{
+ DECLARE_COMPLETION(complete);
+
+ struct scatterlist *sg = NULL;
+ unsigned int sg_len = 0;
+ DBG("[%s] s\n",__func__);
+ /*for loop*/
+ sg = host->data->sg;
+ sg_len = host->data->sg_len;
+ /*To controller every sg done*/
+ host->done_data = &complete;
+ host->done = &atsmb2_wait_done;
+ dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
+
+ /*2009/01/15 janshiue add*/
+ memset(host->DescVirAddr, 0, host->DescSize);
+ atsmb2_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
+ /*2009/01/15 janshiue add*/
+ /*prepare for cmd*/
+ atsmb2_prep_cmd(host, /*host*/
+ host->cmd->opcode, /*opcode*/
+ host->cmd->arg, /*arg*/
+ host->cmd->flags, /*flags*/
+ sg_dma_len(sg)-1, /*block length*/
+ 0, /*block size: It looks like useless*/
+ 0, /*int_mask_0*/
+ (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
+ |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
+ 2, /*cmd_type*/
+ 1); /*op*/
+
+ atsmb2_config_dma(DMA_CFG_READ,
+ SD_PDMA_CCR_Evt_success,
+ host);
+ atsmb2_issue_cmd();
+ /*ISR would completes it.*/
+ wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
+
+ dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
+ ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ spin_lock(&host->lock);
+ atsmb2_request_end(host, host->mrq);
+ spin_unlock(&host->lock);
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb2_start_cmd
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb2_start_cmd(struct atsmb_host *host)
+{
+ unsigned char int_mask_0,int_mask_1;
+ int_mask_0 = 0;
+ int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
+
+ DBG("[%s] s\n",__func__);
+
+ atsmb2_prep_cmd(host,
+ host->cmd->opcode,
+ host->cmd->arg,
+ host->cmd->flags,
+ 0, /*useless*/
+ 0, /*useless*/
+ int_mask_0, /*mask_0*/
+ int_mask_1, /*mask_1*/
+ 0, /*cmd type*/
+ 0); /*read or write*/
+ atsmb2_issue_cmd();
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb2_fmt_check_rsp
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static inline void atsmb2_fmt_check_rsp(struct atsmb_host *host)
+{
+
+ u8 tmp_resp[4] = {0};
+ int i, j, k;
+ DBG("[%s] s\n",__func__);
+ if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
+ for (j = 0, k = 1; j < 4; j++, k++)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k));
+
+ host->cmd->resp[0] = (tmp_resp[0] << 24) |
+ (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
+ } else {
+ for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
+ for (j = 0; j < 4; j++) {
+ if (k < 16)
+ tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k));
+ else /* k =16*/
+ tmp_resp[j] = *(ATSMB2_RSP_0);
+ k++;
+ }
+ host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
+ (tmp_resp[2]<<8) | (tmp_resp[3]);
+ }
+ }
+
+ /*
+ * For the situation that we need response,
+ * but response registers give us all zeros, we consider this operation timeout.
+ */
+ if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
+ && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
+ if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
+ && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
+ host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
+ }
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb2_get_slot_status
+Function : Our host only supports one slot.
+Calls :
+Called by :
+Parameter :
+returns : 1: in slot; 0: not in slot.
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb2_get_slot_status(struct mmc_host *mmc)
+{
+// struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+// unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ status_0 = *ATSMB2_SD_STS_0;
+// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
+ /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
+ if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
+ DBG("[%s] e1\n",__func__);
+ return ret;
+ } else {
+ ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
+ DBG("[%s] e2\n",__func__);
+ return ret;
+ }
+ DBG("[%s] e3\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb2_init_short_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
+{
+ struct SD_PDMA_DESC_S *CurDes_S;
+ DBG("[%s] s\n",__func__);
+ CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
+ CurDes_S->ReqCount = ReqCount;
+ CurDes_S->i = 0;
+ CurDes_S->format = 0;
+ CurDes_S->DataBufferAddr = BufferAddr;
+ if (End) {
+ CurDes_S->end = 1;
+ CurDes_S->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb2_init_long_desc
+Function :
+Calls :
+Called by :
+Parameter :
+Author : Janshiue Wu
+History :
+***********************************************************************/
+int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
+ unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
+{
+ struct SD_PDMA_DESC_L *CurDes_L;
+ DBG("[%s] s\n",__func__);
+ CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
+ CurDes_L->ReqCount = ReqCount;
+ CurDes_L->i = 0;
+ CurDes_L->format = 1;
+ CurDes_L->DataBufferAddr = BufferAddr;
+ CurDes_L->BranchAddr = BranchAddr;
+ if (End) {
+ CurDes_L->end = 1;
+ CurDes_L->i = 1;
+ }
+ DBG("[%s] e\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb2_dma_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static irqreturn_t atsmb2_dma_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3;
+ u32 pdma_event_code = 0;
+ DBG("[%s] s\n",__func__);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+ /*Get INT status*/
+ status_0 = *ATSMB2_SD_STS_0;
+ status_1 = *ATSMB2_SD_STS_1;
+ status_2 = *ATSMB2_SD_STS_2;
+ status_3 = *ATSMB2_SD_STS_3;
+ /* after WM3426 A0 using PDMA */
+ if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) {
+
+ pdma_event_code = *ATSMB2_PDMA_CCR & SD_PDMA_CCR_EvtCode;
+
+ /* clear INT status to notify HW clear EventCode*/
+ *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*printk("dma_isr event code = %X\n", *ATSMB2_PDMA_CCR);*/
+ /*We expect cmd with data sending back or read single block cmd run here.*/
+ if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
+ /*means need to update the data->error and cmd->error*/
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
+ if (host->data != NULL) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ DBG("dma_isr2 hodt->data is NULL\n");
+ /*disable INT*/
+ *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ goto out;
+ }
+ }
+ /*else do nothing*/
+ DBG("dma_isr PDMA OK\n");
+ /*atsmb2_dump_reg(host);*/
+ }
+ /*But unluckily, we should also be prepare for all kinds of error situation.*/
+ else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB2_PDMA_CCR);
+ atsmb2_dump_reg(host);
+ }
+
+ if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
+ atsmb2_fmt_check_rsp(host);
+
+ /*disable INT*/
+ *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
+ }
+
+ /*wake up some one who is sleeping.*/
+ if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
+ if (host->done_data) {/* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb2_request_end(host, host->mrq); /*for cmd with data sending back.*/
+ }
+
+out:
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e\n",__func__);
+ return IRQ_HANDLED;
+}
+
+/* add by th for ack interrupt */
+void eagle_ack_interrupt(void)
+{
+ *ATSMB2_SD_STS_1 |= ATSMB_SDIO_INT;
+}
+EXPORT_SYMBOL(eagle_ack_interrupt);
+
+/**********************************************************************
+Name : atsmb2_regular_isr
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+//static irqreturn_t atsmb2_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t atsmb2_regular_isr(int irq, void *dev_id)
+{
+
+ struct atsmb_host *host = dev_id;
+ u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
+ u32 pdma_sts;
+
+ DBG("[%s] s\n",__func__);
+ WARN_ON(host == NULL);
+
+ disable_irq_nosync(irq);
+ spin_lock(&host->lock);
+
+ /*Get INT status*/
+ status_0 = *ATSMB2_SD_STS_0;
+ status_1 = *ATSMB2_SD_STS_1;
+ status_2 = *ATSMB2_SD_STS_2;
+ status_3 = *ATSMB2_SD_STS_3;
+
+ mask_0 = *ATSMB2_INT_MASK_0;
+ mask_1 = *ATSMB2_INT_MASK_1;
+ /*******************************************************
+ card insert interrupt
+ ********************************************************/
+ if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
+ /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
+ && (*ATSMB2_INT_MASK_0 & 0x80)) {
+
+ if (host->mmc->ops->get_slot_status(host->mmc)) {
+ host->mmc->scan_retry = 3;
+ host->mmc->card_scan_status = false;
+ } else {
+ host->mmc->scan_retry = 0;
+ host->mmc->card_scan_status = false;
+ }
+
+ mmc_detect_change(host->mmc, HZ/2);
+ /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
+ //*ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
+ /*Then we clear the INT status*/
+ //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
+ *ATSMB2_SD_STS_0 |= ATSMB_DEVICE_INSERT;
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e1\n",__func__);
+ return IRQ_HANDLED;
+ }
+
+ if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
+ spin_unlock(&host->lock);
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
+
+ enable_irq(irq);
+ DBG("[%s] e2\n",__func__);
+
+ return IRQ_HANDLED;
+ }
+ spin_lock(&host->lock);
+ }
+ pdma_sts = *ATSMB2_PDMA_CCR;
+
+ if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e3\n",__func__);
+ return IRQ_HANDLED;
+ }
+ /*******************************************************
+ command interrupt.
+ *******************************************************/
+ /*for write single block*/
+ if (host->opcode == MMC_WRITE_BLOCK) {
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err1\n",__func__);
+ atsmb2_dump_reg(host);
+ }
+ } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
+ if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
+ && (status_0 & ATSMB_MULTI_XFER_DONE)) {
+ /*If CRC error occurs, I think this INT would not occrs.*/
+ /*okay, that is what we want.*/
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err2\n",__func__);
+ atsmb2_dump_reg(host);
+
+ }
+ } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err3\n",__func__);
+ atsmb2_dump_reg(host);
+ } else if (host->opcode == SD_IO_RW_EXTENDED){
+ /*Write operation*/
+ if (*ATSMB2_CTL & BIT2) {
+ if ((*ATSMB2_CTL & 0xf0) == 0x10) { /*single block write*/
+ if ((status_0 & ATSMB_BLOCK_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+
+ } else if ((*ATSMB2_CTL & 0xf0) == 0x50) {
+ if ((status_0 & ATSMB_MULTI_XFER_DONE)
+ && (status_1 & ATSMB_RSP_DONE)) {
+ host->data->error = MMC_ERR_NONE;
+ host->cmd->error = MMC_ERR_NONE;
+ /* okay, what we want.*/
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ } else {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
+ }
+ }
+ else {
+ /*Read operation*/
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err5\n",__func__);
+ }
+
+
+ } else {
+/* command, not request data*/
+/* the command which need data sending back,*/
+/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
+/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
+ if (host->data && host->opcode != MMC_SEND_STATUS) {
+ host->data->error = -EIO; //MMC_ERR_FAILED;
+ host->cmd->error = -EIO; //MMC_ERR_FAILED;
+ DBG("[%s] err6\n",__func__);
+ atsmb2_dump_reg(host);
+ } else { /* Just command, no need data sending back.*/
+ if (status_1 & ATSMB_RSP_DONE) {
+ /*Firstly, check data-response is busy or not.*/
+ if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
+ int i = 10000;
+
+ while (status_2 & ATSMB_RSP_BUSY) {
+ status_2 = *ATSMB2_SD_STS_2;
+ if (--i == 0)
+ break;
+ DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
+ }
+ if (i == 0)
+ printk("[MMC driver] Error :SD data-response always busy!");
+ }
+#if 1
+/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
+/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
+/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
+ if (!atsmb2_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
+ host->cmd->retries = 0; /* No retry.*/
+// host->cmd->error = MMC_ERR_INVALID;
+ host->cmd->error = -EINVAL;
+ } else
+#endif
+ host->cmd->error = MMC_ERR_NONE;
+ } else {
+ if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
+// host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
+ DBG("[%s] err7\n",__func__);
+ } else {/*or RSP CRC error*/
+// host->cmd->error = MMC_ERR_BADCRC;
+ host->cmd->error = -EILSEQ;
+ DBG("[%s] err8\n",__func__);
+ }
+ atsmb2_dump_reg(host);
+ }
+ }
+ }
+ atsmb2_fmt_check_rsp(host);
+
+ /*disable INT */
+ *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
+ *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
+ |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
+
+
+ /*clear INT status. In fact, we will clear again before issuing new command.*/
+ *ATSMB2_SD_STS_0 |= status_0;
+ *ATSMB2_SD_STS_1 |= status_1;
+ //*ATSMB2_SD_STS_1 |= ((status_1 & mask_1) | (status_1 & (~ATSMB_SDIO_INT)));
+
+ /* when read CRC error occur, and the status can't write one to clear.
+ * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
+ if ((*ATSMB2_SD_STS_1 & BIT6) == 0x40) {
+ DBG("[%s] host2 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
+ /* Save SD card register */
+ atsmb2_copy_reg(0);
+ /* Software reset */
+ *ATSMB2_BUS_MODE |= BIT7;
+ /* restore SD card register */
+ atsmb2_copy_reg(1);
+ }
+
+ if (*ATSMB2_PDMA_ISR & SD_PDMA_IER_INT_STS)
+ *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
+
+ /*wake up some one who is sleeping.*/
+ if (host->done_data) { /* We only use done_data when requesting data.*/
+ host->soft_timeout = 0;
+ host->done(host);
+ } else
+ atsmb2_request_end(host, host->mrq); /*for cmd without data.*/
+
+ spin_unlock(&host->lock);
+ enable_irq(irq);
+ DBG("[%s] e4\n",__func__);
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(atsmb2_regular_isr);
+
+/**********************************************************************
+Name : atsmb2_get_ro
+Function :.
+Calls :
+Called by :
+Parameter :
+returns : 0 : write protection is disabled. 1: write protection is enabled.
+Author : Leo Lee
+History :
+***********************************************************************/
+int atsmb2_get_ro(struct mmc_host *mmc)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned char status_0 = 0;
+ unsigned long flags;
+ unsigned long ret = 0;
+ DBG("[%s] s\n",__func__);
+ spin_lock_irqsave(&host->lock, flags);
+ status_0 = *ATSMB2_SD_STS_0;
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
+ ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb2_dump_host_regs
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Leo Lee
+History :
+***********************************************************************/
+void atsmb2_dump_host_regs(struct mmc_host *mmc)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ DBG("[%s] s\n",__func__);
+ atsmb2_dump_reg(host);
+ DBG("[%s] e\n",__func__);
+}
+EXPORT_SYMBOL(atsmb2_dump_host_regs);
+
+
+
+
+#if MMC2_SDIO_EXT_IRQ
+static irqreturn_t mtk6620_sdio_ext_irq (int irq, void *dev_id)
+{
+ struct mmc_host *mmc = dev_id;
+
+ if(!is_gpio_irqenable(wmt_mtk6620_intr) || !gpio_irqstatus(wmt_mtk6620_intr))
+ return IRQ_NONE;
+
+ smp_rmb();
+ if (unlikely(test_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
+ //disable_irq_nosync(mmc2_sdio_ext_irq);
+ wmt_gpio_mask_irq(wmt_mtk6620_intr);
+
+ set_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
+ smp_wmb();
+
+ printk( "%s: irq in suspend, defer & disable_irq(%d)\n",
+ mmc_hostname(mmc), mmc2_sdio_ext_irq);
+ wmt_gpio_ack_irq(wmt_mtk6620_intr);
+ return IRQ_HANDLED;
+ }
+ //printk( "%s: irq happen, call mmc_signal_sdio_irq\n", mmc_hostname(mmc));
+ mmc_signal_sdio_irq(mmc);
+ wmt_gpio_ack_irq(wmt_mtk6620_intr);
+ return IRQ_HANDLED;
+}
+
+static void mtk6620_setup_sdio_ext_irq (struct mmc_host *mmc)
+{
+ int ret;
+ printk(KERN_WARNING "setup sdio ext irq but mmc2_sdio_ext_irq(%d) != 0!\n", mmc2_sdio_ext_irq);
+
+ if (0 != mmc2_sdio_ext_irq) {
+ return;
+ }
+
+ wmt_gpio_setpull(wmt_mtk6620_intr,WMT_GPIO_PULL_UP);
+
+// s3c_gpio_setpull(MMC2_SDIO_EINT_PIN, S3C_GPIO_PULL_NONE);
+// s3c_gpio_cfgpin(MMC2_SDIO_EINT_PIN, S3C_GPIO_SFN(0xF));
+
+ mmc2_sdio_ext_irq = 1;//gpio_to_irq(MMC2_SDIO_EINT_PIN);
+
+ wmt_gpio_mask_irq(wmt_mtk6620_intr);
+ //clear_gpio26_irq_state();
+ wmt_gpio_ack_irq(wmt_mtk6620_intr);
+
+
+ ret = request_irq(IRQ_GPIO, mtk6620_sdio_ext_irq, IRQF_SHARED,"mmc2_sdio_ext_irq", mmc);
+ if (ret) {
+ printk( "request_irq(%d, 0x%p, IRQF_TRIGGER_LOW) fail(%d)!!\n",
+ mmc2_sdio_ext_irq, mtk6620_sdio_ext_irq, ret);
+ mmc2_sdio_ext_irq = 0;
+ return;
+ }
+
+ /*clear int status register before enable this int pin*/
+ wmt_gpio_ack_irq(wmt_mtk6620_intr);
+ /*enable this int pin*/
+ wmt_gpio_unmask_irq(wmt_mtk6620_intr);
+
+// enable_irq_wake(mmc2_sdio_ext_irq);
+ printk("%s: using sdio_ext_irq and enable_irq_wake(%d) gpio(%d) IRQ_EINT(%d)\n",
+ mmc_hostname(mmc), mmc2_sdio_ext_irq, wmt_mtk6620_intr,
+ (IRQ_GPIO));
+ return;
+}
+#endif /* MMC2_SDIO_EXT_IRQ */
+
+
+
+
+/**********************************************************************
+Name : atsmb2_enable_sdio_irq
+Function :
+Calls :
+Called by :
+Parameter :
+returns :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb2_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ DBG("[%s] s enable = %d *ATSMB2_INT_MASK_1 = %x\n",__func__,enable,*ATSMB2_INT_MASK_1);
+ spin_lock_irqsave(&host->lock, flags);
+
+
+#if MMC2_SDIO_EXT_IRQ
+ if (is_mtk6620) {
+ if (enable&&enable_wifi_irq) {
+ if (likely(0 != mmc2_sdio_ext_irq)) {
+ //enable_irq(mmc2_sdio_ext_irq);
+ wmt_gpio_unmask_irq(wmt_mtk6620_intr);
+ }
+ else {
+ mtk6620_setup_sdio_ext_irq(mmc);
+ }
+ }
+ else {
+ smp_rmb();
+ if (unlikely(test_and_clear_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
+ smp_wmb();
+ printk("%s: irq already disabled when being deferred(%d)\n",
+ mmc_hostname(host->mmc), mmc2_sdio_ext_irq);
+ /* do nothing */
+ }
+ else {
+ //disable_irq_nosync(mmc2_sdio_ext_irq);
+ wmt_gpio_mask_irq(wmt_mtk6620_intr);
+ }
+ }
+ goto out;
+ }
+#endif /* MMC2_SDIO_EXT_IRQ */
+
+
+
+ if (enable) {
+ *ATSMB2_INT_MASK_1 |= ATSMB_SDIO_EN;
+ } else {
+ *ATSMB2_INT_MASK_1 &= ~ATSMB_SDIO_EN;
+ }
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+
+}
+void wmt_detect_sdio2(void){
+
+ if(mmc2_host_attr!=NULL){
+
+ struct atsmb_host *host = mmc_priv(mmc2_host_attr);
+
+ mmc_detect_change(host->mmc, HZ/2);
+ }
+}
+
+
+void force_remove_sdio2(void)
+{
+ if(mmc2_host_attr!=NULL)
+ mmc_force_remove_card(mmc2_host_attr);
+}
+
+void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ enable_wifi_irq = (unsigned int )enable;
+ atsmb2_enable_sdio_irq(mmc, enable);
+}
+
+EXPORT_SYMBOL(rda_mci_enable_sdio_irq);
+
+EXPORT_SYMBOL(wmt_detect_sdio2);
+EXPORT_SYMBOL(force_remove_sdio2);
+/**********************************************************************
+Name : atsmb2_request
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb2_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ DBG("[%s] s\n",__func__);
+
+ /* May retry process comes here.*/
+ host->mrq = mrq;
+ host->data = mrq->data;
+ host->cmd = mrq->cmd;
+ host->done_data = NULL;
+ host->done = NULL;
+
+ /*for data request*/
+ if (host->data) {
+ if (host->cmd->opcode == MMC_WRITE_BLOCK
+ || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
+ || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
+ || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
+ || host->cmd->opcode == SD_IO_RW_EXTENDED) {
+ atsmb2_start_data(host);
+ } else {
+ atsmb2_cmd_with_data_back(host);
+ }
+ } else {
+ atsmb2_start_cmd(host);
+ }
+ DBG("[%s] e\n",__func__);
+}
+/**********************************************************************
+Name : atsmb2_set_clock
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Eason Chien
+History :2012/7/19
+***********************************************************************/
+static int atsmb2_set_clock(struct mmc_host *mmc, unsigned int clock)
+{
+ if (clock == mmc->f_min) {
+ DBG("[%s]ATSMB2 Host 400KHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390);
+ } else if (clock >= 50000000) {
+ DBG("[%s]ATSMB2 Host 50MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 45);
+ } else if ((clock >= 25000000) && (clock < 50000000)) {
+ DBG("[%s]ATSMB2 Host 25MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 24);
+ } else if ((clock >= 20000000) && (clock < 25000000)) {
+ DBG("[%s]ATSMB2 Host 20MHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 20);
+ } else {
+ DBG("[%s]ATSMB2 Host 390KHz\n", __func__);
+ return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390);
+ }
+}
+
+/**********************************************************************
+Name : atsmb2_set_ios
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static void atsmb2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+
+ struct atsmb_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ DBG("[%s] s\n",__func__);
+ spin_lock_irqsave(&host->lock, flags);
+#if MMC2_SDIO_EXT_IRQ
+ if(is_mtk6620){
+ if ((ios->power_mode == MMC_POWER_OFF)) {
+ if (0 != mmc2_sdio_ext_irq) {
+ printk("%s: set mmc2 MMC_POWER_OFF disable_irq_wake & free_irq(%d)!\n", __func__, mmc2_sdio_ext_irq);
+ //disable_irq_wake(mmc2_sdio_ext_irq);
+ wmt_gpio_mask_irq(wmt_mtk6620_intr);
+ free_irq(IRQ_GPIO, host->mmc);
+ mmc2_sdio_ext_irq = 0;
+ }
+ }
+ }
+#endif /* MMC2_SDIO_EXT_IRQ */
+
+
+ if (ios->power_mode == MMC_POWER_OFF) {
+ if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
+ /* stop SD output clock */
+ *ATSMB2_BUS_MODE &= ~(ATSMB_CST);
+
+ /* disable SD Card power */
+ /*set SD2 power pin as GPO pin*/
+ if (SD2_function == SDIO_WIFI)
+ ;//GPIO_OC_GP0_BYTE_VAL |= BIT6;
+ else {
+ GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ GPIO_OC_GP19_SD2_BYTE_VAL|= GPIO_SD2_POWER;
+ }
+
+ /*set internal pull up*/
+ PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ /*disable SD2 power*/
+ if (SD2_function == SDIO_WIFI)
+ GPIO_OD_GP0_BYTE_VAL &= ~BIT6;
+ else
+ GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+
+ /* Disable Pull up/down resister of SD Bus */
+ PULL_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
+
+ /* Config SD2 to GPIO */
+ GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN;
+
+ /* SD2 all pins output low */
+ GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
+
+ /* Config SD2 to GPIO */
+ GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN;
+ }
+ } else if (ios->power_mode == MMC_POWER_UP) {
+ if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
+ /* disable SD Card power */
+ /*set SD2 power pin as GPO pin*/
+ if (SD2_function == SDIO_WIFI)
+ ;//GPIO_OC_GP0_BYTE_VAL |= BIT6;
+ else {
+ GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ GPIO_OC_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ }
+
+ /*set internal pull up*/
+ PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ /*set internal pull enable*/
+ PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+ /*disable SD2 power*/
+ if (SD2_function == SDIO_WIFI)
+ GPIO_OD_GP0_BYTE_VAL &= ~BIT6;
+ else
+ GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
+
+ /* Config SD PIN share */
+ //kevin delete for dvfs
+ //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare;
+
+ /* do not config GPIO_SD2_CD because ISR has already run,
+ * config card detect will issue ISR storm.
+ */
+ /* Config SD to GPIO */
+ GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN;
+
+ /* SD all pins output low */
+ GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
+
+ /* Config SD to GPO */
+ GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN;
+
+ /* Pull up/down resister of SD Bus */
+ /*Disable Clock & CMD Pull enable*/
+ PULL_EN_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Clock );
+
+ /*Set CD ,WP ,DATA pin pull up*/
+ if (SD2_function == SDIO_WIFI) {
+ PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down card always in slot*/
+ PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
+ } else {
+ PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
+ PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
+ }
+
+ /*Enable CD ,WP ,DATA internal pull*/
+ PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
+ PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(100);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* enable SD Card Power */
+ if (SD2_function == SDIO_WIFI)
+ GPIO_OD_GP0_BYTE_VAL |= BIT6;
+ else
+ GPIO_OD_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_POWER;
+
+ /* enable SD output clock */
+ *ATSMB2_BUS_MODE |= ATSMB_CST;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Config SD0 back to function */
+ GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD;
+ GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
+ }
+ } else {
+ /*nothing to do when powering on.*/
+ }
+
+ host->current_clock = atsmb2_set_clock(mmc,ios->clock);
+
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ *ATSMB2_EXT_CTL |= (0x04);
+ } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ *ATSMB2_BUS_MODE |= ATSMB_BUS_WIDTH_4;
+ *ATSMB2_EXT_CTL &= ~(0x04);
+ } else {
+ *ATSMB2_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
+ *ATSMB2_EXT_CTL &= ~(0x04);
+ }
+#if 1
+ if (ios->timing == MMC_TIMING_SD_HS)
+ *ATSMB2_EXT_CTL |= 0x80; /*HIGH SPEED MODE*/
+ else
+ *ATSMB2_EXT_CTL &= ~(0x80);
+#endif
+#if 0 //zhf: marked by James Tian
+ if (ios->ins_en == MMC_INSERT_IRQ_EN)
+ *ATSMB2_INT_MASK_0 |= (0x80);/* or 40?*/
+ else
+ *ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/
+#endif
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ DBG("[%s] e\n",__func__);
+}
+
+
+static const struct mmc_host_ops atsmb2_ops = {
+ .request = atsmb2_request,
+ .set_ios = atsmb2_set_ios,
+ .get_ro = atsmb2_get_ro,
+ .get_slot_status = atsmb2_get_slot_status,
+ .dump_host_regs = atsmb2_dump_host_regs,
+ .enable_sdio_irq = atsmb2_enable_sdio_irq,
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+/**********************************************************************
+Name :atsmb2_probe
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int __init atsmb2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = NULL;
+ struct atsmb_host *atsmb_host = NULL;
+ struct resource *resource = NULL;
+ int irq[2] = {0};
+ int ret = 0;
+
+ DBG("[%s] s\n",__func__);
+ if (!pdev) {
+ ret = -EINVAL; /* Invalid argument */
+ goto the_end;
+ }
+
+ /*Enable SD host clock*/
+ auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0);
+
+ if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
+ /* enable SD1 PIN share */
+ //kevin delete for dvfs
+ //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare;
+
+ /* Pull up/down resister of SD CD */
+ if (SD2_function == SDIO_WIFI) {
+ PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/
+ } else {
+ PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; /*pull up CD*/
+ }
+ PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
+
+ /* config CardDetect pin to SD function */
+ GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD;
+ }
+
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ ret = -ENXIO; /* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
+ goto the_end;
+ }
+#if 0
+ if (!request_mem_region(resource->start, SZ_1K, MMC2_DRIVER_NAME)) {
+ ret = -EBUSY;
+ printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
+ goto the_end ;
+ }
+#endif
+ irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
+ irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
+
+ if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
+ ret = -ENXIO;/* No such device or address */
+ printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
+ goto rls_region;
+ }
+
+ /*allocate a standard msp_host structure attached with a atsmb structure*/
+ mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
+ if (!mmc_host) {
+ ret = -ENOMEM;
+ printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
+ goto rls_region;
+ }
+ mmc_host->wmt_host_index = 2; /*to identify host number*/
+
+ dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
+ atsmb_host = mmc_priv(mmc_host);
+
+ mmc_host->ops = &atsmb2_ops;
+
+ mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+
+ mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
+ mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/
+
+ if(!is_nmc1000){
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE;
+ }else{
+ mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE;
+ }
+ /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
+ mmc_host->pm_caps |= MMC_PM_KEEP_POWER;
+ mmc_host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;//add by kevinguan for mtk6620
+
+ mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
+
+ /*1MB per each request */
+ /*we have a 16 bit block number register, and block length is 512 bytes.*/
+ mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
+ mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
+ mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
+ mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
+
+ /*set the specified host -- ATSMB*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ mmc_host->card_attath_status = card_attach_status_unchange;
+#endif
+ sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
+#if 0
+ atsmb_host->base = ioremap(resource->start, SZ_1K);
+ if (!atsmb_host->base) {
+ printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
+ ret = -ENOMEM;
+ goto fr_host;
+ }
+#endif
+ atsmb_host->base = (void *)resource->start;
+ atsmb_host->mmc = mmc_host;
+ spin_lock_init(&atsmb_host->lock);
+ atsmb_host->res = resource;/* for atsmb2_remove*/
+
+ /*disable all interrupt and clear status by resetting controller.*/
+ *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB2_BLK_LEN &= ~(0xa000);
+ *ATSMB2_SD_STS_0 |= 0xff;
+ *ATSMB2_SD_STS_1 |= 0xff;
+
+ /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
+ //if (MMC2_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
+ *ATSMB2_BUS_MODE |= ATSMB_CST;
+
+ atsmb_host->regular_irq = irq[0];
+ atsmb_host->dma_irq = irq[1];
+
+ ret = request_irq(atsmb_host->regular_irq,
+ atsmb2_regular_isr,
+ IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
+ MMC2_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
+ goto unmap;
+ }
+
+ ret = request_irq(atsmb_host->dma_irq,
+ atsmb2_dma_isr,
+ IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
+ MMC2_DRIVER_NAME,
+ (void *)atsmb_host);
+ if (ret) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
+ goto fr_regular_isr;
+ }
+
+
+ /*wait card detect status change*/
+ //msleep(10);
+
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB2_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
+ *ATSMB2_SD_STS_0 |= 0xff;
+ *ATSMB2_INT_MASK_0 |= 0x80; /*or 0x40?*/
+
+ /*allocation dma descriptor*/
+ ret = atsmb2_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
+ if (ret == -1) {
+ printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
+ goto fr_dma_isr;
+ }
+ printk(KERN_INFO "WMT ATSMB2 (AHB To SD/MMC2 Bus) controller registered!\n");
+
+ if (SD2_function == SDIO_WIFI){
+ if(set_bus_dead){
+ mmc_host->bus_dead = 1; //fix this problem: mmc1: error -110 during resume (card was removed?)
+ }else
+ printk("dont set bus dead in probe function\n");
+ mmc_add_host(mmc_host,false);
+ }else
+ mmc_add_host(mmc_host,true);
+
+ mmc2_host_attr = mmc_host;
+ DBG("[%s] e1\n",__func__);
+ return 0;
+
+fr_dma_isr:
+ free_irq(atsmb_host->dma_irq, atsmb_host);
+fr_regular_isr:
+ free_irq(atsmb_host->regular_irq, atsmb_host);
+unmap:
+ //iounmap(atsmb_host->base);
+//fr_host:
+ dev_set_drvdata(dev, NULL);
+ mmc_free_host(mmc_host);
+rls_region:
+ //release_mem_region(resource->start, SZ_1K);
+the_end:
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB2 probe Failed!\n") ;
+ DBG("[%s] e2\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb2_remove
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb2_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
+ struct atsmb_host *atsmb_host;
+
+ DBG("[%s] s\n",__func__);
+ atsmb_host = mmc_priv(mmc_host);
+ if (!mmc_host || !atsmb_host) {
+ printk(KERN_ALERT "[MMC/SD driver] ATSMB2 remove method failed!\n");
+ DBG("[%s] e1\n",__func__);
+ return -ENXIO;
+ }
+ mmc_remove_host(mmc_host);
+
+ /*disable interrupt by resetting controller -- for safey*/
+ *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB2_BLK_LEN &= ~(0xa000);
+ *ATSMB2_SD_STS_0 |= 0xff;
+ *ATSMB2_SD_STS_1 |= 0xff;
+
+ (void)free_irq(atsmb_host->regular_irq, atsmb_host);
+ (void)free_irq(atsmb_host->dma_irq, atsmb_host);
+ (void)iounmap(atsmb_host->base);
+ (void)release_mem_region(atsmb_host->res->start, SZ_1K);
+ dev_set_drvdata(dev, NULL);
+ /*free dma descriptor*/
+ dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
+ atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
+ (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
+ DBG("[%s] e2\n",__func__);
+ return 0;
+}
+
+/**********************************************************************
+Name : atsmb2_shutdown
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Tommy Huang
+History :
+***********************************************************************/
+static void atsmb2_shutdown(struct platform_device *pdev)
+{
+ /*atsmb2_shutdown don't be used now.*/
+ /*struct device *dev = &pdev->dev;
+ struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
+
+ DBG("[%s] s\n",__func__);
+ if (SD2_function != SDIO_WIFI) {
+ /*Disable card detect interrupt*/
+ *ATSMB2_INT_MASK_0 &= ~0x80;
+ }
+ DBG("[%s] e\n",__func__);
+
+}
+
+/**********************************************************************
+Name : atsmb2_suspend
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+int SD2_card_state = 0; /*0: card remove >=1: card enable*/
+
+#ifdef CONFIG_PM
+static int atsmb2_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ if (mmc) {
+
+ if (SD2_function == SDIO_WIFI) {
+ if (SD2_card_state > 0)
+ mmc_force_remove_card(mmc2_host_attr);
+ }
+#if MMC2_SDIO_EXT_IRQ
+ if (is_mtk6620) {
+ if (0 != mmc2_sdio_ext_irq) {
+ //if (mmc_try_claim_host(host->mmc)) {
+ if(true){
+ set_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
+ printk(KERN_INFO "%s:in_suspend++\n", mmc_hostname(mmc));
+ }
+ else {
+ printk(KERN_INFO "%s:claim host fail in suspend, return -EBUSY\n", mmc_hostname(mmc));
+ return -EBUSY;
+ }
+ }
+ }
+#endif /* MMC2_SDIO_EXT_IRQ */
+
+ /*struct atsmb_host *host = mmc_priv(mmc);*/
+ ret = mmc_suspend_host(mmc);
+
+#if MMC2_SDIO_EXT_IRQ
+ if (is_mtk6620) {
+ if (ret) {
+ printk("\n\n\n\n\n\n%s:mmc_suspend_host fail(%d)\n\n\n\n\n\n",
+ mmc_hostname(mmc), ret);
+ if (0 != mmc2_sdio_ext_irq) {
+ clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
+ //mmc_release_host(host->mmc);
+
+ }
+ return ret;
+ }
+
+ }
+#endif
+
+
+ if (ret == 0) {
+ /*disable all interrupt and clear status by resetting controller. */
+ *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB2_BLK_LEN &= ~(0xa000);
+ *ATSMB2_SD_STS_0 |= 0xff;
+ *ATSMB2_SD_STS_1 |= 0xff;
+
+ }
+ /*disable source clock*/
+ auto_pll_divisor(DEV_SDMMC2, CLK_DISABLE, 0, 0);
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*clean SD card attatch status change*/
+ //PMCWS_VAL |= BIT19;
+ mmc->card_attath_status = card_attach_status_unchange;
+#endif
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+/**********************************************************************
+Name : atsmb2_resume
+Function :.
+Calls :
+Called by :
+Parameter :
+Author : Leo Lee
+History :
+***********************************************************************/
+static int atsmb2_resume(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
+ int ret = 0;
+ DBG("[%s] s\n",__func__);
+
+ /*
+ * enable interrupt, DMA, etc.
+ * Supply power to slot.
+ */
+ if (mmc) {
+ /*enable source clock*/
+ auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0);
+
+ udelay(1);
+ /*enable card insertion interrupt and enable DMA and its Global INT*/
+ *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
+ *ATSMB2_BLK_LEN |= (0xa000);
+ *ATSMB2_INT_MASK_0 |= 0x80; /* or 40?*/
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+ /*modify SD card attatch status change*/
+ //if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) {
+ /*card change when suspend mode*/
+ mmc->card_attath_status = card_attach_status_change;
+ /*clean SD card attatch status change*/
+ // PMCWS_VAL |= BIT19;
+ //}
+#endif
+ if (SD2_function == SDIO_WIFI) {
+ PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/
+ PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
+
+ //kevin add for suspend&resume
+ PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_Data | GPIO_SD2_Command;
+ PULL_CTRL_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_WriteProtect;
+ PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
+ PULL_EN_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_Clock;
+ GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Data | GPIO_SD2_WriteProtect | GPIO_SD2_Command | GPIO_SD2_Clock);
+ *ATSMB2_BUS_MODE |= ATSMB_CST;
+ msleep(20);
+
+
+ if (SD2_card_state > 0) {
+ printk("[%s] mmc_resume_host s\n",__func__);
+ mmc_detect_change(mmc2_host_attr, 1*HZ/2);
+ printk("[%s] mmc_resume_host e\n",__func__);
+ }
+
+
+#if MMC2_SDIO_EXT_IRQ
+ if (is_mtk6620) {
+ if (0 != mmc2_sdio_ext_irq) {
+ /* sdhc goes back to normal working mode, after mtk6620_init() */
+ clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
+ //mmc_release_host(host->mmc);
+ printk(KERN_INFO "%s:in_suspend--\n", mmc_hostname(mmc));
+ }
+ }
+#endif /* MMC2_SDIO_EXT_IRQ */
+
+
+
+ //kevin add for suspend&resume
+ ret = mmc_resume_host(mmc);
+
+
+#if MMC2_SDIO_EXT_IRQ
+ /* after mmc_resume_host(), sdio_func is also resumed */
+ if (is_mtk6620) {
+ if (0 != mmc2_sdio_ext_irq) {
+ /* signal deferred irq if any */
+ smp_rmb();
+ if (unlikely(test_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
+ printk(KERN_INFO "%s: signal deferred irq(%d)\n",
+ mmc_hostname(mmc), mmc2_sdio_ext_irq);
+ /* signal the deferred irq */
+ mmc_signal_sdio_irq(mmc);
+ }
+ }
+ }
+#endif
+
+ } else {
+ ret = mmc_resume_host(mmc);
+ }
+ }
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+#else
+#define atsmb2_suspend NULL
+#define atsmb2_resume NULL
+#endif
+
+static struct platform_driver atsmb2_driver = {
+ .driver.name = "sdmmc2",
+ //.probe = atsmb2_probe,
+ .remove = atsmb2_remove,
+ .shutdown = atsmb2_shutdown,
+ .suspend = atsmb2_suspend,
+ .resume = atsmb2_resume,
+};
+
+static struct platform_device wmt_sdmmc2_device = {
+ .name = "sdmmc2",
+ .id = 0,
+ .dev = {
+ .dma_mask = &wmt_sdmmc2_dma_mask,
+ .coherent_dma_mask = ~0,
+ .release = atsmb2_release,
+ },
+ .num_resources = ARRAY_SIZE(wmt_sdmmc2_resources),
+ .resource = wmt_sdmmc2_resources,
+};
+
+static DEFINE_MUTEX(SD2_state_lock);
+
+static ssize_t atsmb2_state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+
+ DBG("[%s] s\n",__func__);
+
+ ret = sprintf(buf, "%d\n", SD2_card_state);
+ DBG("[%s]SD2_card_state = %d\n",__func__,SD2_card_state);
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+
+static ssize_t atsmb2_state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int val;
+ DBG("[%s] s\n",__func__);
+
+ mutex_lock(&SD2_state_lock);
+ if (sscanf(buf, "%d", &val) == 1) {
+ DBG("[%s] val = %d\n",__func__,val);
+ if (val == 1) {
+ SD2_card_state++;
+ DBG("[%s] add state SD2_card_state = %d\n",__func__,SD2_card_state);
+ if ((SD2_card_state == 1) && (mmc2_host_attr->card == NULL)) {
+ DBG("[%s]add card\n",__func__);
+ mmc_detect_change(mmc2_host_attr, 0);
+ msleep(1000);
+ } else {
+ msleep(1000); /*to prevent the card not init ready*/
+ }
+ } else if (val == 0) {
+ SD2_card_state--;
+ printk("[%s] sub state SD2_card_state = %d\n",__func__,SD2_card_state);
+ if (SD2_card_state < 0) {
+ SD2_card_state = 0;
+ printk("[%s] set 0 SD2_card_state = %d\n",__func__,SD2_card_state);
+ }
+
+ if ((SD2_card_state == 0) && (mmc2_host_attr->card != NULL)) {
+ DBG("[%s]remove card\n",__func__);
+ mmc_force_remove_card(mmc2_host_attr);
+ }
+ }
+
+ DBG("[%s] e1\n",__func__);
+ mutex_unlock(&SD2_state_lock);
+ return n;
+ }
+
+ mutex_unlock(&SD2_state_lock);
+ DBG("[%s] e2\n",__func__);
+ return -EINVAL;
+}
+
+static struct kobj_attribute atsmb2_state_attr = { \
+ .attr = { \
+ .name = __stringify(state), \
+ .mode = 0755, \
+ }, \
+ .show = atsmb2_state_show, \
+ .store = atsmb2_state_store, \
+};
+
+#if MMC2_SDIO_EXT_IRQ
+
+static ssize_t atsmb2_intr_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+
+
+ ret = sprintf(buf, "%d\n", is_mtk6620);
+ printk("[%s]is_mtk6620 = %d\n",__func__,is_mtk6620);
+ return ret;
+}
+
+static ssize_t atsmb2_intr_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int val;
+ if (sscanf(buf, "%d", &val) == 1) {
+ printk("[%s] val = %d\n",__func__,val);
+ if (val == 1) {
+ if (gpio_request(wmt_mtk6620_intr, "mtk6620_wifi_intr") < 0) {
+ printk("gpio(%d) mtk6620_wifi_intr gpio request fail\n", wmt_mtk6620_intr);
+ is_mtk6620 = 0;
+ return -1;
+ }
+ } else if (val == 0) {
+
+ gpio_free(wmt_mtk6620_intr);
+
+ }
+ is_mtk6620 = val;
+
+ return n;
+ }
+ return -EINVAL;
+}
+
+static struct kobj_attribute atsmb2_intr_attr = { \
+ .attr = { \
+ .name = __stringify(intr), \
+ .mode = 0755, \
+ }, \
+ .show = atsmb2_intr_show, \
+ .store = atsmb2_intr_store, \
+};
+#endif
+
+
+static struct attribute * g2[] = {
+ &atsmb2_state_attr.attr,
+#if MMC2_SDIO_EXT_IRQ
+ &atsmb2_intr_attr.attr,
+#endif
+ NULL,
+};
+
+static struct attribute_group attr2_group = {
+ .attrs = g2,
+};
+
+static int __init atsmb2_init(void)
+{
+ int ret;
+
+ int retval;
+ unsigned char buf[80];
+ unsigned char buf1[80];
+ int varlen = 80;
+ char *varname = "wmt.sd2.param";
+ int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/
+
+ DBG("[%s] s\n",__func__);
+
+#ifdef CONFIG_MTD_WMT_SF
+ /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%x:%d", &temp, &SD2_function);
+ printk(KERN_ALERT "wmt.sd2.param = %x:%d\n", temp, SD2_function);
+ sd_enable = temp & 0xf;
+ SDXC2_function = (temp >> 4) & 0xf;
+ printk(KERN_ALERT "SD2 ebable = %x, SDXC = %x, function = %x\n",
+ sd_enable, SDXC2_function, SD2_function);
+
+ if (SD2_function < 0 || SD2_function >= SD_MAX_FUN)
+ return -ENODEV;
+ } else {
+ //default is enable sdio wifi
+ temp = sd_enable = 1;
+ SD2_function = 1;
+ printk(KERN_ALERT "Default wmt.sd2.param = %x:%d\n", temp, SD2_function);
+
+ }
+ memset(buf,0,sizeof(buf));
+ varlen = 80;
+ retval = wmt_getsyspara("wmt.init.rc", buf, &varlen);
+ if (retval == 0) {
+ printk(KERN_ALERT"wmt.init.rc:%s\n",buf);
+ if(!strcmp(buf,"init_nmc1000.rc")){
+ is_nmc1000 = 0x01;
+ printk("is_nmc1000:%d",is_nmc1000);
+ }
+ if (!strcmp(buf, "init.bcm6330.rc"))
+ {
+ is_ap6330 = 1;
+ printk("is_ap6330:%d\n", is_ap6330);
+ }
+ if (!strcmp(buf, "init.rda5991.rc"))
+ {
+ printk("is rda5991\n");
+ set_bus_dead = 0;
+ }
+ if (!strcmp(buf, "init.mtk6620.rc"))
+ {
+ printk("is mtk6620\n");
+ set_bus_dead = 0;
+ }
+ } else {
+ printk(KERN_ALERT "wmt.init.rc do not exit\n");
+ }
+#endif
+ /*SD function disable*/
+ if (sd_enable != 1)
+ return -ENODEV;
+
+ get_driver_version2();
+
+ if (platform_device_register(&wmt_sdmmc2_device))//add by jay,for modules support
+ return -1;
+ //ret = platform_driver_register(&atsmb2_driver);
+ ret = platform_driver_probe(&atsmb2_driver, atsmb2_probe);
+
+ atsmb2_kobj = kobject_create_and_add("mmc2", NULL);
+ if (!atsmb2_kobj)
+ return -ENOMEM;
+ return sysfs_create_group(atsmb2_kobj, &attr2_group);
+
+ DBG("[%s] e\n",__func__);
+ return ret;
+}
+
+static void __exit atsmb2_exit(void)
+{
+ DBG("[%s] s\n",__func__);
+ (void)platform_driver_unregister(&atsmb2_driver);
+ (void)platform_device_unregister(&wmt_sdmmc2_device);//add by jay,for modules support
+ DBG("[%s] e\n",__func__);
+}
+
+module_init(atsmb2_init);
+module_exit(atsmb2_exit);
+module_param(fmax2, uint, 0444);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [AHB to SD/MMC2 Bridge] driver");
+MODULE_LICENSE("GPL");