diff options
author | Kevin | 2014-11-15 10:00:36 +0800 |
---|---|---|
committer | Kevin | 2014-11-15 10:00:36 +0800 |
commit | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch) | |
tree | de942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/mmc | |
parent | 392e8802486cb573b916e746010e141a75f507e6 (diff) | |
download | FOSSEE-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.c | 288 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/bus.c | 118 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/core.c | 701 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/core.h | 2 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/host.c | 82 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/mmc.c | 16 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c | 22 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/sd.c | 16 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/core/sd_ops.c | 21 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/host/Kconfig | 25 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mmc/host/Makefile | 4 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c | 2837 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h | 691 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c | 2405 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c | 2855 |
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"); |