aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorDorian Snyder <dastin1015@gmail.com>2013-06-12 02:24:45 -0700
committerDorian Snyder <dastin1015@gmail.com>2013-06-20 00:06:04 -0700
commit4b2308ce699b9c599dd6e6acf57ac11f483381d9 (patch)
tree4c31179b06d094887b1c8ca70264cf8f184a5981 /drivers/mmc
parent855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (diff)
downloadkernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.zip
kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.gz
kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.bz2
d710: initial support for the Epic 4G Touch (SPH-D710)
Change-Id: Iafbd9fb45253b02d539ac0ba114f57b3bf9eeed4
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c122
-rw-r--r--drivers/mmc/core/core.c14
-rw-r--r--drivers/mmc/core/host.c36
-rw-r--r--drivers/mmc/core/host.h20
-rw-r--r--drivers/mmc/core/mmc.c61
-rw-r--r--drivers/mmc/core/mmc_ops.c4
-rw-r--r--drivers/mmc/core/sdio.c116
-rw-r--r--drivers/mmc/core/sdio_ops.c24
-rw-r--r--drivers/mmc/core/sdio_ops.h1
-rw-r--r--drivers/mmc/host/mshci-s3c.c9
-rw-r--r--drivers/mmc/host/sdhci-s3c.c28
11 files changed, 415 insertions, 20 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index f49e92c..1c63296 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1166,12 +1166,14 @@ static int mmc_blk_err_check(struct mmc_card *card,
if ((!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) ||
(mq_mrq->packed_cmd == MMC_PACKED_WR_HDR)) {
u32 status;
+#ifndef CONFIG_WIMAX_CMC
/* timeout value set 0x30000 : It works just SDcard case.
* It means send CMD sequencially about 7.8sec.
* If SDcard's data line stays low, timeout is about 4sec.
* max timeout is up to 300ms
*/
u32 timeout = 0x30000;
+#endif
do {
int err = get_card_status(card, &status, 5);
if (err) {
@@ -1184,6 +1186,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
* so make sure to check both the busy
* indication and the card state.
*/
+#ifdef CONFIG_WIMAX_CMC
+ } while (!(status & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+#else
/* Just SDcard case, decrease timeout */
if (mmc_card_sd(card))
timeout--;
@@ -1198,6 +1204,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
req->rq_disk->disk_name);
return MMC_BLK_DATA_ERR;
}
+#endif
}
if (brq->data.error) {
@@ -1534,6 +1541,88 @@ no_packed:
return 0;
}
+#ifdef CONFIG_WIMAX_CMC
+static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ struct mmc_queue *mq,
+ u8 reqs)
+{
+ struct mmc_blk_request *brq = &mqrq->brq;
+ struct request *req = mqrq->req;
+ struct request *prq;
+ struct mmc_blk_data *md = mq->data;
+ bool do_rel_wr;
+ u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
+ u8 i = 1;
+
+ mqrq->packed_cmd = (rq_data_dir(req) == READ) ?
+ MMC_PACKED_WR_HDR : MMC_PACKED_WRITE;
+ mqrq->packed_blocks = 0;
+ mqrq->packed_fail_idx = -1;
+
+ memset(packed_cmd_hdr, 0, sizeof(mqrq->packed_cmd_hdr));
+ packed_cmd_hdr[0] = (reqs << 16) |
+ (((rq_data_dir(req) == READ) ?
+ PACKED_CMD_RD : PACKED_CMD_WR) << 8) |
+ PACKED_CMD_VER;
+
+
+ /*
+ * Argument for each entry of packed group
+ */
+ list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
+ do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
+ /* Argument of CMD23*/
+ packed_cmd_hdr[(i * 2)] = (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
+ blk_rq_sectors(prq);
+ /* Argument of CMD18 or CMD25 */
+ packed_cmd_hdr[((i * 2)) + 1] = mmc_card_blockaddr(card) ?
+ blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+ mqrq->packed_blocks += blk_rq_sectors(prq);
+ i++;
+ }
+
+ memset(brq, 0, sizeof(struct mmc_blk_request));
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.data = &brq->data;
+ brq->mrq.sbc = &brq->sbc;
+ brq->mrq.stop = &brq->stop;
+
+ brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+ brq->sbc.arg = MMC_CMD23_ARG_PACKED |
+ ((rq_data_dir(req) == READ) ? 1 : mqrq->packed_blocks + 1);
+ brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ 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->data.blksz = 512;
+ /*
+ * Write separately the packd command header only for packed read.
+ * In case of packed write, header is sent with blocks of data.
+ */
+ brq->data.blocks = (rq_data_dir(req) == READ) ?
+ 1 : mqrq->packed_blocks + 1;
+ brq->data.flags |= MMC_DATA_WRITE;
+
+ brq->stop.opcode = MMC_STOP_TRANSMISSION;
+ brq->stop.arg = 0;
+ brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+ mmc_set_data_timeout(&brq->data, card);
+
+ brq->data.sg = mqrq->sg;
+ brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
+
+ mqrq->mmc_active.mrq = &brq->mrq;
+ mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+
+ mmc_queue_bounce_pre(mqrq);
+}
+#else
static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
struct mmc_queue *mq)
@@ -1612,7 +1701,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
mmc_queue_bounce_pre(mqrq);
}
-
+#endif
static void mmc_blk_packed_rrq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
struct mmc_queue *mq)
@@ -1722,7 +1811,11 @@ static int mmc_blk_issue_packed_rd(struct mmc_queue *mq,
ret = mmc_blk_chk_hdr_err(mq, status);
if (ret)
break;
+#ifdef CONFIG_WIMAX_CMC
+ mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq, mq_rq->packed_num);
+#else
mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
+#endif
mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
} else {
mmc_blk_packed_rrq_prep(mq_rq, card, mq);
@@ -1762,9 +1855,14 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
struct mmc_command cmd;
#endif
if (rqc) {
+#ifdef CONFIG_WIMAX_CMC
+ if (reqs >= 2)
+ mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur, card, mq, reqs);
+#else
if (reqs >= packed_num) {
mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur, card, mq);
}
+#endif
else
mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
areq = &mq->mqrq_cur->mmc_active;
@@ -1920,22 +2018,36 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
if (idx == i) {
/* retry from error index */
mq_rq->packed_num -= idx;
+#ifdef CONFIG_WIMAX_CMC
+ if (mq_rq->packed_num == 1) {
+ printk(KERN_ERR "SBRISSEN - I AM HERE\n");
+ mq_rq->packed_cmd = MMC_PACKED_NONE;
+ mq_rq->packed_num = 0;
+ }
+#endif
mq_rq->req = prq;
ret = 1;
break;
}
+#ifndef CONFIG_WIMAX_CMC
list_del_init(&prq->queuelist);
+#endif
spin_lock_irq(&md->lock);
__blk_end_request(prq, 0, blk_rq_bytes(prq));
spin_unlock_irq(&md->lock);
i++;
}
+#ifdef CONFIG_WIMAX_CMC
+ if (idx == -1)
+ mq_rq->packed_num = 0;
+#else
if (mq_rq->packed_num == MMC_PACKED_N_SINGLE) {
prq = list_entry_rq(mq_rq->packed_list.next);
list_del_init(&prq->queuelist);
mq_rq->packed_cmd = MMC_PACKED_NONE;
mq_rq->packed_num = MMC_PACKED_N_ZERO;
}
+#endif
break;
} else {
spin_lock_irq(&md->lock);
@@ -2015,7 +2127,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
} else {
+#ifdef CONFIG_WIMAX_CMC
+ mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq, mq_rq->packed_num);
+#else
mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
+#endif
mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
if (mq_rq->packed_cmd == MMC_PACKED_WR_HDR) {
if (mmc_blk_issue_packed_rd(mq, mq_rq))
@@ -2478,6 +2594,10 @@ static int mmc_blk_probe(struct mmc_card *card)
printk(KERN_INFO "%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
+#ifdef CONFIG_WIMAX_CMC
+ if (mmc_blk_alloc_parts(card, md))
+ goto out;
+#endif
mmc_set_drvdata(card, md);
mmc_fixup_device(card, blk_fixups);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ddd6d50..8252d44 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -275,12 +275,22 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
/* if card is mmc type and nonremovable, and there are erros after
issuing r/w command, then init eMMC and mshc */
+#ifdef CONFIG_WIMAX_CMC
+ if (((host->card) && mmc_card_mmc(host->card) && \
+ (host->caps & MMC_CAP_NONREMOVABLE)) && \
+ (mrq->cmd->error == -ENOTRECOVERABLE || \
+ ((mrq->cmd->opcode == 17 || mrq->cmd->opcode == 18 || \
+ mrq->cmd->opcode == 24 || mrq->cmd->opcode == 25) && \
+ ((mrq->data->error) || mrq->cmd->error || \
+ (mrq->sbc && mrq->sbc->error))))) {
+#else
if (((host->card) && mmc_card_mmc(host->card) && \
(host->caps & MMC_CAP_NONREMOVABLE)) && \
(mrq->cmd->error == -ENOTRECOVERABLE || \
((mrq->cmd->opcode == 17 || mrq->cmd->opcode == 18) && \
((mrq->data->error) || mrq->cmd->error || \
(mrq->sbc && mrq->sbc->error))))) {
+#endif
int rt_err = -1,count = 3;
printk(KERN_ERR "%s: it occurs a critical error on eMMC "
@@ -2440,6 +2450,7 @@ int mmc_suspend_host(struct mmc_host *host)
wake_unlock(&host->detect_wake_lock);
mmc_flush_scheduled_work();
if (mmc_try_claim_host(host)) {
+#ifndef CONFIG_WIMAX_CMC
u32 status;
u32 count=300000; /* up to 300ms */
@@ -2453,7 +2464,9 @@ int mmc_suspend_host(struct mmc_host *host)
"flushing emmc's cache\n",
mmc_hostname(host),ret);
}
+#endif
err = mmc_cache_ctrl(host, 0);
+#ifndef CONFIG_WIMAX_CMC
/* to make sure that emmc is not working. should check
emmc's state */
@@ -2469,6 +2482,7 @@ int mmc_suspend_host(struct mmc_host *host)
count--;
} while (count && R1_CURRENT_STATE(status) == 7);
}
+#endif
mmc_do_release_host(host);
} else {
err = -EBUSY;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 3664c49..7966957 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -53,6 +53,7 @@ static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
#ifdef CONFIG_MMC_CLKGATE
+#ifndef CONFIG_WIMAX_CMC
static ssize_t clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -74,6 +75,7 @@ static ssize_t clkgate_delay_store(struct device *dev,
spin_unlock_irqrestore(&host->clk_lock, flags);
return count;
}
+#endif
/*
* Enabling clock gating will make the core call out to the host
* once up and once down when it performs a request or card operation
@@ -108,10 +110,14 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
if (!host->clk_requests) {
spin_unlock_irqrestore(&host->clk_lock, flags);
/* wait only when clk_gate_delay is 0 */
+#ifdef CONFIG_WIMAX_CMC
if (!host->clkgate_delay) {
+#endif
tick_ns = DIV_ROUND_UP(1000000000, freq);
ndelay(host->clk_delay * tick_ns);
+#ifdef CONFIG_WIMAX_CMC
}
+#endif
} else {
/* New users appeared while waiting for this work */
spin_unlock_irqrestore(&host->clk_lock, flags);
@@ -135,9 +141,13 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
*/
static void mmc_host_clk_gate_work(struct work_struct *work)
{
+#ifdef CONFIG_WIMAX_CMC
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_gate_work);
+#else
struct mmc_host *host = container_of(work, struct mmc_host,
clk_gate_work.work);
-
+#endif
mmc_host_clk_gate_delayed(host);
}
@@ -152,9 +162,10 @@ static void mmc_host_clk_gate_work(struct work_struct *work)
void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
-
+#ifndef CONFIG_WIMAX_CMC
/* cancel any clock gating work scheduled by mmc_host_clk_release() */
cancel_delayed_work_sync(&host->clk_gate_work);
+#endif
mutex_lock(&host->clk_gate_mutex);
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated) {
@@ -204,9 +215,12 @@ void mmc_host_clk_release(struct mmc_host *host)
host->clk_requests--;
if (mmc_host_may_gate_card(host->card) &&
!host->clk_requests)
+#ifdef CONFIG_WIMAX_CMC
+ queue_work(system_nrt_wq, &host->clk_gate_work);
+#else
queue_delayed_work(system_nrt_wq, &host->clk_gate_work,
msecs_to_jiffies(host->clkgate_delay));
-
+#endif
spin_unlock_irqrestore(&host->clk_lock, flags);
}
@@ -239,13 +253,19 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
host->clk_requests = 0;
/* Hold MCI clock for 8 cycles by default */
host->clk_delay = 8;
+#ifndef CONFIG_WIMAX_CMC
/*
* Default clock gating delay is 0ms to avoid wasting power.
* This value can be tuned by writing into sysfs entry.
*/
host->clkgate_delay = 3;
+#endif
host->clk_gated = false;
+#ifdef CONFIG_WIMAX_CMC
+ INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+#else
INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+#endif
spin_lock_init(&host->clk_lock);
mutex_init(&host->clk_gate_mutex);
}
@@ -260,14 +280,18 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
* Wait for any outstanding gate and then make sure we're
* ungated before exiting.
*/
+#ifdef CONFIG_WIMAX_CMC
+ if (cancel_work_sync(&host->clk_gate_work))
+#else
if (cancel_delayed_work_sync(&host->clk_gate_work))
+#endif
mmc_host_clk_gate_delayed(host);
if (host->clk_gated)
mmc_host_clk_hold(host);
/* There should be only one user now */
WARN_ON(host->clk_requests > 1);
}
-
+#ifndef CONFIG_WIMAX_CMC
static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
{
host->clkgate_delay_attr.show = clkgate_delay_show;
@@ -279,7 +303,7 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
mmc_hostname(host));
}
-
+#endif
#else
static inline void mmc_host_clk_init(struct mmc_host *host)
@@ -384,7 +408,9 @@ int mmc_add_host(struct mmc_host *host)
mmc_add_host_debugfs(host);
#endif
+#ifndef CONFIG_WIMAX_CMC
mmc_host_clk_sysfs_init(host);
+#endif
mmc_start_host(host);
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 08a7852..df7d2cd 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -12,6 +12,26 @@
#define _MMC_CORE_HOST_H
#include <linux/mmc/host.h>
+#if defined(CONFIG_MMC_CLKGATE)
+void mmc_host_clk_hold(struct mmc_host *host);
+void mmc_host_clk_release(struct mmc_host *host);
+unsigned int mmc_host_clk_rate(struct mmc_host *host);
+
+#else
+static inline void mmc_host_clk_hold(struct mmc_host *host)
+{
+}
+
+static inline void mmc_host_clk_release(struct mmc_host *host)
+{
+}
+
+static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
+{
+ return host->ios.clock;
+}
+#endif
+
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
void mmc_host_deeper_disable(struct work_struct *work);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 506a4e3..1622bbb 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -30,10 +30,12 @@
#else
/* For debugging about ext_csd register value */
#if 0
+#ifndef CONFIG_WIMAX_CMC
#define MMC_CHECK_EXT_CSD
#endif
#endif
#endif
+#endif
/*
* If moviNAND VHX 4.41 device
@@ -216,7 +218,7 @@ static int mmc_decode_csd(struct mmc_card *card)
return 0;
}
-#if defined(MMC_CHECK_EXT_CSD)
+#if defined(MMC_CHECK_EXT_CSD) && !defined(CONFIG_WIMAX_CMC)
/* For debugging about ext_csd register value */
static u8 *ext_csd_backup;
static void mmc_error_ext_csd(struct mmc_card *card, u8 *ext_csd,
@@ -340,7 +342,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
} else
*new_ext_csd = ext_csd;
-#if defined(MMC_CHECK_EXT_CSD)
+#if defined(MMC_CHECK_EXT_CSD) && !defined(CONFIG_WIMAX_CMC)
/* For debugging about ext_csd register value */
mmc_error_ext_csd(card, ext_csd, 1, 0);
#endif
@@ -369,7 +371,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
"version %d\n", mmc_hostname(card->host),
card->ext_csd.raw_ext_csd_structure);
err = -EINVAL;
-#if defined(MMC_CHECK_EXT_CSD)
+#if defined(MMC_CHECK_EXT_CSD) && !defined(CONFIG_WIMAX_CMC)
/* For debugging about ext_csd register value */
mmc_error_ext_csd(card, ext_csd, 0, EXT_CSD_STRUCTURE);
#endif
@@ -386,7 +388,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
-#if defined(MMC_CHECK_EXT_CSD)
+#if defined(MMC_CHECK_EXT_CSD) && !defined(CONFIG_WIMAX_CMC)
/* For debugging about ext_csd register value */
mmc_error_ext_csd(card, ext_csd, 0, EXT_CSD_REV);
#endif
@@ -409,6 +411,35 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
mmc_card_set_blockaddr(card);
}
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
+#ifdef CONFIG_WIMAX_CMC
+ switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+ case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+ break;
+ case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+ EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+ break;
+ case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ break;
+ case EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 26000000;
+ break;
+ default:
+ /* MMC v4 spec says this cannot happen */
+ printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
+ "support any high-speed modes.\n",
+ mmc_hostname(card->host));
+#else
if (card->host->caps2 & MMC_CAP2_HS200) {
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
case EXT_CSD_CARD_TYPE_SDR_ALL:
@@ -507,6 +538,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
goto out;
#endif
}
+#endif
}
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
@@ -608,12 +640,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->host->card = card;
movi_ver_check = mmc_start_movi_smart(card);
}
-
+#ifndef CONFIG_WIMAX_CMC
/* enable discard feature if emmc is 4.41+ moviNand */
if ((ext_csd[EXT_CSD_VENDOR_SPECIFIC_FIELD + 0] & 0x1) &&
(card->cid.manfid == 0x15))
card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
-
+#endif
/* enable PON feature if moviNAND VHX/VMX devices */
if (CHECK_MOVI_PON_SUPPORT) {
if ((movi_ver_check & MMC_MOVI_VER_VHX0) &&
@@ -890,6 +922,7 @@ static int mmc_select_powerclass(struct mmc_card *card,
return err;
}
+#ifndef CONFIG_WIMAX_CMC
/*
* Selects the desired buswidth and switch to the HS200 mode
* if bus width set without error
@@ -962,7 +995,7 @@ static int mmc_select_hs200(struct mmc_card *card)
err:
return err;
}
-
+#endif
/*
* Handle the detection and initialisation of a card.
*
@@ -1076,7 +1109,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
/*
* Fetch and process extended CSD.
*/
-#if defined(MMC_RETRY_READ_EXT_CSD)
+#if defined(MMC_RETRY_READ_EXT_CSD) && !defined(CONFIG_WIMAX_CMC)
{
int i = 0;
for (i = 0 ; i < 3 ; i++) {
@@ -1180,6 +1213,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG)
goto free_card;
+#ifdef CONFIG_WIMAX_CMC
+ if (!err)
+#else
+ if (!err && (host->caps2 & MMC_CAP2_POWEROFF_NOTIFY))
+#endif
/*
* The err can be -EBADMSG or 0,
* so check for success and update the flag
@@ -1192,13 +1230,20 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Activate high speed (if supported)
*/
if (card->ext_csd.hs_max_dtr != 0) {
+#ifndef CONFIG_WIMAX_CMC
err = 0;
if (card->ext_csd.hs_max_dtr > 52000000 &&
host->caps2 & MMC_CAP2_HS200)
err = mmc_select_hs200(card);
else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
+#else
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 1, card->ext_csd.generic_cmd6_time);
+#endif
+#ifndef CONFIG_WIMAX_CMC
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1, 0);
+#endif
if (err && err != -EBADMSG)
goto free_card;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 3cec450..e0c3c88 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -788,7 +788,11 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
opcode = card->ext_csd.hpi_cmd;
if (opcode == MMC_STOP_TRANSMISSION)
+#ifdef CONFIG_WIMAX_CMC
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+#else
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+#endif
else if (opcode == MMC_SEND_STATUS)
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index fa2a8b4..1e9c109 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -147,10 +147,14 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
}
if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
+#ifdef CONFIG_WIMAX_CMC
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+#else
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+#endif
if (ret)
goto out;
-
+#ifndef CONFIG_WIMAX_CMC
card->scr.sda_spec3 = 0;
card->sw_caps.sd3_bus_mode = 0;
card->sw_caps.sd3_drv_type = 0;
@@ -201,6 +205,10 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
card->sw_caps.hs_max_dtr = 25000000;
}
}
+#else
+ if (data & SDIO_SPEED_SHS)
+ card->cccr.high_speed = 1;
+#endif
}
out:
@@ -382,6 +390,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
return max_dtr;
}
+#ifndef CONFIG_WIMAX_CMC
static unsigned char host_drive_to_sdio_drive(int host_strength)
{
switch (host_strength) {
@@ -569,7 +578,7 @@ out:
return err;
}
-
+#endif
/*
* Handle the detection and initialisation of a card.
*
@@ -636,6 +645,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
if (host->ops->init_card)
host->ops->init_card(host, card);
+#ifndef CONFIG_WIMAX_CMC
/*
* If the host and card support UHS-I mode request the card
* to switch to 1.8V signaling level. No 1.8v signalling if
@@ -659,7 +669,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
ocr &= ~R4_18V_PRESENT;
host->ocr &= ~R4_18V_PRESENT;
}
-
+#endif
/*
* For native busses: set card RCA and quit open drain mode.
*/
@@ -776,7 +786,30 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
err = sdio_disable_cd(card);
if (err)
goto remove;
+#ifdef CONFIG_WIMAX_CMC
+ /*
+ * Switch to high-speed (if supported).
+ */
+ err = sdio_enable_hs(card);
+ if (err > 0)
+ mmc_sd_go_highspeed(card);
+ else if (err)
+ goto remove;
+
+ /*
+ * Change to the card's maximum speed.
+ */
+ mmc_set_clock(host, mmc_sdio_get_max_clock(card));
+ /*
+ * Switch to wider bus (if supported).
+ */
+ err = sdio_enable_4bit_bus(card);
+ if (err > 0)
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ else if (err)
+ goto remove;
+#else
/* Initialization sequence for UHS-I cards */
/* Only if card supports 1.8v and UHS signaling */
if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
@@ -810,6 +843,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
else if (err)
goto remove;
}
+#endif
finish:
if (!oldcard)
host->card = card;
@@ -911,6 +945,11 @@ out:
static int mmc_sdio_suspend(struct mmc_host *host)
{
int i, err = 0;
+
+#ifdef CONFIG_WIMAX_CMC
+ if (host->pm_flags & MMC_PM_IGNORE_SUSPEND_RESUME)
+ return err;
+#endif
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
@@ -933,8 +972,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
}
}
-#ifdef CONFIG_MACH_PX
-#else
+#ifndef CONFIG_MACH_PX
if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
mmc_claim_host(host);
sdio_disable_wide(host->card);
@@ -948,6 +986,11 @@ static int mmc_sdio_suspend(struct mmc_host *host)
static int mmc_sdio_resume(struct mmc_host *host)
{
int i, err = 0;
+
+#ifdef CONFIG_WIMAX_CMC
+ if (host->pm_flags & MMC_PM_IGNORE_SUSPEND_RESUME)
+ return err;
+#endif
BUG_ON(!host);
BUG_ON(!host->card);
@@ -1299,3 +1342,66 @@ err:
return err;
}
EXPORT_SYMBOL(sdio_reset_comm);
+
+#ifdef CONFIG_WIMAX_CMC
+int cmc732_sdio_reset_comm(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u32 ocr;
+ int err;
+ printk("%s():\n",__func__);
+ cmc732_sdio_reset(host);
+ err = mmc_send_io_op_cond(host, 0, &ocr);
+ if (err)
+ goto err;
+#if 1//refer to mmc_attach_sdio()
+ if (!host->index)
+ ocr |= 0x00000080; //correct cmc ocr to show support for 1.8v operation
+ host->ocr = mmc_select_voltage(host, ocr);
+ if (!host->index)
+ host->ocr = 0x8000;//lie to cmc card that 2.8v operation selected
+#else
+ host->ocr = mmc_select_voltage(host, ocr);
+#endif
+ if (!host->ocr) {
+ err = -EINVAL;
+ goto err;
+ }
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto err;
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto err;
+ }
+ err = sdio_enable_hs(card);
+ if (err)
+ goto err;
+ if (mmc_card_highspeed(card)) {
+ mmc_set_clock(host, 50000000);
+ } else {
+ mmc_set_clock(host, card->cis.max_dtr);
+ }
+ err = sdio_enable_wide(card);
+ if (err)
+ goto err;
+ return 0;
+err:
+ printk("%s: Error resetting SDIO communications (%d)\n",
+ mmc_hostname(host), err);
+ return err;
+}
+EXPORT_SYMBOL(cmc732_sdio_reset_comm);
+#endif
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index f087d87..42f7810 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -198,3 +198,27 @@ int sdio_reset(struct mmc_host *host)
return ret;
}
+#ifdef CONFIG_WIMAX_CMC
+int cmc732_sdio_reset(struct mmc_host *host)
+{
+ int ret;
+ u8 abort;
+ ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+ if (ret)
+ abort = 0x01;
+ else
+ abort |= 0x01;
+ ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+ ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+ abort &= 0xFE;
+ ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+ ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+ if (ret)
+ abort = 0x08;
+ else
+ abort |= 0x08;
+ ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+ return ret;
+}
+#endif
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index 12a4d3a..ba07370 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -18,6 +18,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
int sdio_reset(struct mmc_host *host);
+int cmc732_sdio_reset(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/host/mshci-s3c.c b/drivers/mmc/host/mshci-s3c.c
index 58670ca..2c890c9 100644
--- a/drivers/mmc/host/mshci-s3c.c
+++ b/drivers/mmc/host/mshci-s3c.c
@@ -488,6 +488,7 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
if (pdata->cd_type == S3C_MSHCI_CD_PERMANENT) {
host->quirks |= MSHCI_QUIRK_BROKEN_PRESENT_BIT;
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+#ifndef CONFIG_WIMAX_CMC
if (pdata->int_power_gpio) {
gpio_set_value(pdata->int_power_gpio, 1);
s3c_gpio_cfgpin(pdata->int_power_gpio,
@@ -495,6 +496,7 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
s3c_gpio_setpull(pdata->int_power_gpio,
S3C_GPIO_PULL_NONE);
}
+#endif
}
/* IF SD controller's WP pin donsn't connected with SD card and there
@@ -511,12 +513,15 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
if (pdata->cd_type == S3C_MSHCI_CD_GPIO &&
gpio_is_valid(pdata->ext_cd_gpio)) {
+#ifdef CONFIG_WIMAX_CMC
+ gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD");
+#else
ret = gpio_request(pdata->ext_cd_gpio, "MSHCI EXT CD");
if (ret) {
dev_err(&pdev->dev, "cannot request gpio for card detect\n");
goto err_add_host;
}
-
+#endif
sc->ext_cd_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
@@ -537,7 +542,9 @@ static int __devinit mshci_s3c_probe(struct platform_device *pdev)
goto err_add_host;
}
+#ifndef CONFIG_WIMAX_CMC
device_enable_async_suspend(dev);
+#endif
return 0;
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 712c8c6..eba9825 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -608,6 +608,11 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
* transfers, not sure if this is a problem with this specific
* SDHCI block, or a missing configuration that needs to be set. */
host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
+
+#ifdef CONFIG_WIMAX_CMC
+ /* This host supports the Auto CMD12 */
+ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+#endif
if (pdata->cd_type == S3C_SDHCI_CD_NONE)
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
@@ -706,6 +711,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
pdata->ext_pdev(pdev);
#endif
}
+#ifdef CONFIG_MACH_U1_NA_SPR
+ if (pdata->cd_type == S3C_SDHCI_CD_GPIO && pdata->ext_cd_init)
+ pdata->ext_cd_init(&sdhci_s3c_notify_change);
+#endif
if (pdata->cd_type == S3C_SDHCI_CD_GPIO &&
gpio_is_valid(pdata->ext_cd_gpio))
sdhci_s3c_setup_card_detect_gpio(sc);
@@ -742,6 +751,10 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
+#ifdef CONFIG_MACH_U1_NA_SPR
+ if (pdata->cd_type == S3C_SDHCI_CD_GPIO && pdata->ext_cd_cleanup)
+ pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
+#endif
if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc);
@@ -792,9 +805,24 @@ static void sdhci_s3c_shutdown(struct platform_device *dev)
static int sdhci_s3c_resume(struct platform_device *dev)
{
struct sdhci_host *host = platform_get_drvdata(dev);
+#if defined(CONFIG_WIMAX_CMC)/* && defined(CONFIG_TARGET_LOCALE_NA)*/
+ struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
+ u32 ier;
+#endif
int ret = 0;
ret = sdhci_resume_host(host);
+
+#if defined(CONFIG_WIMAX_CMC)/* && defined(CONFIG_TARGET_LOCALE_NA)*/
+
+
+ if (pdata->enable_intr_on_resume) {
+ ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+ ier |= SDHCI_INT_CARD_INT;
+ sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+ }
+#endif
return ret;
}