#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
#include <mach/board.h>
#include <mach/rk2818_iomap.h>
struct mmc_host *wifi_mmc_host = NULL;
+int sdmmc0_disable_Irq_ForRemoval;
+int hotplug_global_ctl;
+struct rk2818_sdmmc_host *mmc0_host;
+
+
#define RK2818_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE)
#define RK2818_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE)
#define RK2818_MCI_ERROR_FLAGS (RK2818_MCI_DATA_ERROR_FLAGS | RK2818_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
#define RK2818_MMC_CARD_NEED_INIT 1
#define RK2818_MMC_SHUTDOWN 2
int irq;
+ unsigned int cmd_tmo;
+ struct mmc_command stop_mannual;
struct timer_list detect_timer;
};
+#define MMC_DEBUG 0
+#if MMC_DEBUG
+#define xjhprintk(msg...) xjhprintk(msg)
+#else
+#define xjhprintk(msg...)
+#endif
+
#define rk2818_sdmmc_test_and_clear_pending(host, event) \
test_and_clear_bit(event, &host->pending_events)
#define rk2818_sdmmc_set_completed(host, event) \
dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n");
}
#endif
+static void rk2818_show_regs(struct rk2818_sdmmc_host *host)
+{
+ unsigned long cpsr_tmp;
+
+ xjhprintk("--------[xjh] SD/MMC/SDIO Registers-----------------\n");
+ xjhprintk("SDMMC_CTRL:\t0x%x\n",readl(host->regs + SDMMC_CTRL));
+ xjhprintk("SDMMC_PWREN:\t0x%x\n",readl(host->regs + SDMMC_PWREN));
+ xjhprintk("SDMMC_CLKDIV:\t0x%x\n",readl(host->regs + SDMMC_CLKDIV));
+ xjhprintk("SDMMC_CLKSRC:\t0x%x\n",readl(host->regs + SDMMC_CLKSRC));
+ xjhprintk("SDMMC_CLKENA:\t0x%x\n",readl(host->regs + SDMMC_CLKENA));
+ xjhprintk("SDMMC_TMOUT:\t0x%x\n",readl(host->regs + SDMMC_TMOUT));
+ xjhprintk("SDMMC_CTYPE:\t0x%x\n",readl(host->regs + SDMMC_CTYPE));
+ xjhprintk("SDMMC_BLKSIZ:\t0x%x\n",readl(host->regs + SDMMC_BLKSIZ));
+ xjhprintk("SDMMC_BYTCNT:\t0x%x\n",readl(host->regs + SDMMC_BYTCNT));
+ xjhprintk("SDMMC_INTMASK:\t0x%x\n",readl(host->regs + SDMMC_INTMASK));
+ xjhprintk("SDMMC_CMDARG:\t0x%x\n",readl(host->regs + SDMMC_CMDARG));
+ xjhprintk("SDMMC_CMD:\t0x%x\n",readl(host->regs + SDMMC_CMD));
+ xjhprintk("SDMMC_RESP0:\t0x%x\n",readl(host->regs + SDMMC_RESP0));
+ xjhprintk("SDMMC_RESP1:\t0x%x\n",readl(host->regs + SDMMC_RESP1));
+ xjhprintk("SDMMC_RESP2:\t0x%x\n",readl(host->regs + SDMMC_RESP2));
+ xjhprintk("SDMMC_RESP3:\t0x%x\n",readl(host->regs + SDMMC_RESP3));
+ xjhprintk("SDMMC_MINTSTS:\t0x%x\n",readl(host->regs + SDMMC_MINTSTS));
+ xjhprintk("SDMMC_RINTSTS:\t0x%x\n",readl(host->regs + SDMMC_RINTSTS));
+ xjhprintk("SDMMC_STATUS:\t0x%x\n",readl(host->regs + SDMMC_STATUS));
+ xjhprintk("SDMMC_FIFOTH:\t0x%x\n",readl(host->regs + SDMMC_FIFOTH));
+ xjhprintk("SDMMC_CDETECT:\t0x%x\n",readl(host->regs + SDMMC_CDETECT));
+ xjhprintk("SDMMC_WRTPRT:\t0x%x\n",readl(host->regs + SDMMC_WRTPRT));
+ xjhprintk("SDMMC_TCBCNT:\t0x%x\n",readl(host->regs + SDMMC_TCBCNT));
+ xjhprintk("SDMMC_TBBCNT:\t0x%x\n",readl(host->regs + SDMMC_TBBCNT));
+ xjhprintk("SDMMC_DEBNCE:\t0x%x\n",readl(host->regs + SDMMC_DEBNCE));
+ xjhprintk("-------- Host states-----------------\n");
+ xjhprintk("host->state:\t0x%x\n",host->state);
+ xjhprintk("host->pending_events:\t0x%x\n",host->pending_events);
+ xjhprintk("host->cmd_status:\t0x%x\n",host->cmd_status);
+ xjhprintk("host->data_status:\t0x%x\n",host->data_status);
+ xjhprintk("host->stop_cmdr:\t0x%x\n",host->stop_cmdr);
+ xjhprintk("host->dir_status:\t0x%x\n",host->dir_status);
+ xjhprintk("host->completed_events:\t0x%x\n",host->completed_events);
+ xjhprintk("host->dma_chn:\t0x%x\n",host->dma_chn);
+ xjhprintk("host->use_dma:\t0x%x\n",host->use_dma);
+ xjhprintk("host->no_detect:\t0x%x\n",host->no_detect);
+ xjhprintk("host->bus_hz:\t0x%x\n",host->bus_hz);
+ xjhprintk("host->current_speed:\t0x%x\n",host->current_speed);
+ xjhprintk("host->ctype:\t0x%x\n",host->ctype);
+ xjhprintk("host->clock:\t0x%x\n",host->clock);
+ xjhprintk("host->flags:\t0x%x\n",host->flags);
+ xjhprintk("host->irq:\t0x%x\n",host->irq);
+ xjhprintk("-------- rk2818 CPU register-----------------\n");
+ __asm__ volatile ("mrs %0, cpsr @ local_irq_save\n":"=r" (cpsr_tmp)::"memory", "cc" );
+ xjhprintk("cpsr:\t0x%x\n",cpsr_tmp);
+
+
+
+}
+
static void rk2818_sdmmc_set_power(struct rk2818_sdmmc_host *host, u32 ocr_avail)
{
if(ocr_avail == 0)
if(cmdr == 12)
cmdr |= SDMMC_CMD_STOP;
+ else if(cmdr == 13)
+ cmdr &= ~SDMMC_CMD_PRV_DAT_WAIT;
else
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
static void rk2818_sdmmc_start_command(struct rk2818_sdmmc_host *host,
struct mmc_command *cmd, u32 cmd_flags)
{
- int tmo = 50;
+ int tmo = 5000;
+ unsigned long flags;
+ int retry = 4;
host->cmd = cmd;
dev_dbg(host->dev, "start cmd:%d ARGR=0x%08x CMDR=0x%08x\n",
cmd->opcode, cmd->arg, cmd_flags);
+ local_irq_save(flags);
writel(cmd->arg, host->regs + SDMMC_CMDARG); // write to CMDARG register
writel(cmd_flags | SDMMC_CMD_START, host->regs + SDMMC_CMD); // write to CMD register
+ local_irq_restore(flags);
/* wait until CIU accepts the command */
while (--tmo && (readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START))
cpu_relax();
+ if(!tmo) {
+ tmo = 5000;
+ xjhprintk("%s start cmd %d error. retry again!!!\n",__FUNCTION__ ,cmd->opcode);
+ rk2818_show_regs(host);
+ rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+ host->cmd_status |= SDMMC_INT_RE;
+ tasklet_schedule(&host->tasklet);
+ retry --;
+ // if(retry)
+ // goto START_CMD;
+ }
+ #if 0
+ tmo = 60;
+ host->cmd_tmo = 0;
+ while(--tmo && !host->cmd_tmo)
+ {
+ mdelay(5);
+ //cpu_relax();
+
+ }
+ if(!tmo)
+ {
+ xjhprintk("cmd %d response time out(not receive INT)\n",cmd->opcode);
+ rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+ host->cmd_status |= SDMMC_INT_RE;
+ tasklet_schedule(&host->tasklet);
+ }
+ #endif
}
static void send_stop_cmd(struct rk2818_sdmmc_host *host, struct mmc_data *data)
{
+ unsigned long flags;
+ unsigned long fifo_left;
+ /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+ int time_out =60;
+ while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+ mdelay(5);
+ time_out --;
+
+ if(!time_out){
+ time_out =60;
+ xjhprintk("card busy now,can not issuse req! \nreset DMA and FIFO\n");
+ local_irq_save(flags);
+
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ) & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ }
+ //cpu_relax();
+ }
+
+ #if 1
+
+ fifo_left = readl(host->regs + SDMMC_STATUS);
+
+ if((fifo_left & SDMMC_STAUTS_FIFO_FULL) && (fifo_left & SDMMC_STAUTS_FIFO_RX_WATERMARK))
+ {
+ xjhprintk("%s read operation reach water mark\n",__FUNCTION__);
+ rk2818_show_regs(host);
+ while(SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS))>>2)
+ readl(host->regs + SDMMC_DATA); //discard the no use data
+
+ rk2818_show_regs(host);
+
+ }
+ #endif
+ /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+ if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+ xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+ rk2818_show_regs(host);
+ local_irq_save(flags);
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ //cpu_relax();
+ }
+
rk2818_sdmmc_start_command(host, data->stop, host->stop_cmdr);
}
-
static void rk2818_sdmmc_dma_cleanup(struct rk2818_sdmmc_host *host)
{
struct mmc_data *data = host->data;
static void rk2818_sdmmc_stop_dma(struct rk2818_sdmmc_host *host)
{
if (host->dma_chn >= 0) {
+ xjhprintk("[xjh] %s enter host->state %d\n", __FUNCTION__, host->state);
writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_DMA_ENABLE,
host->regs +SDMMC_CTRL);
//disable_dma(host->dma_chn);
free_dma(host->dma_chn);
host->dma_chn = -1;
rk2818_sdmmc_dma_cleanup(host);
+ rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);//[xjh] Èç¹ûÊý¾Ý¶Áд¹ý³Ì±»°Îµô£¬ÐèÒªÉèÖÃÕâ¸ö״̬
+ xjhprintk("[xjh] %s exit\n", __FUNCTION__);
} else {
/* Data transfer was stopped by the interrupt handler */
rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
dev_dbg(host->dev, "DMA complete\n");
spin_lock(&host->lock);
+ //disable dma
+ writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_DMA_ENABLE,
+ host->regs +SDMMC_CTRL);
rk2818_sdmmc_dma_cleanup(host);
//disable_dma(host->dma_chn);
free_dma(host->dma_chn);
host->dma_chn = -1;
if (data) {
+
rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
tasklet_schedule(&host->tasklet);
}
host->regs +SDMMC_CTRL);
}
}
-
+#if 0
#define mci_send_cmd(host,cmd,arg) { \
writel(arg, host->regs + SDMMC_CMDARG); \
writel(SDMMC_CMD_START | cmd, host->regs + SDMMC_CMD); \
while (readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); \
}
+#else
+static void mci_send_cmd(struct rk2818_sdmmc_host *host,unsigned int cmd,int arg)
+{
+ int tmo = 5000;
+ int retry = 4;
+
+ writel(arg, host->regs + SDMMC_CMDARG);
+ writel(SDMMC_CMD_START | cmd, host->regs + SDMMC_CMD);
+ while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START);
+ if(!tmo) {
+ tmo = 5000;
+ xjhprintk("%s set register error. retry again!!!\n",__FUNCTION__);
+ retry --;
+ // if(retry)
+ // goto START_CMD;
+ }
+}
+
+#endif
+#if 1
+void inline rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
+{
+ ;
+}
+#else
void rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
{
u32 div;
dev_dbg(host->dev, "Bus speed = %dHz div:%d (actual %dHz)\n",
host->clock, div, (host->bus_hz / div) >> 1);
+ xjhprintk("Bus speed = %dHz div:%d (actual %dHz)\n",
+ host->clock, div, (host->bus_hz / div) >> 1);
/* store the actual clock for calculations */
host->clock = (host->bus_hz / div) >> 1;
/* Set the current host bus width */
writel(host->ctype, host->regs + SDMMC_CTYPE);
}
+#endif
+
static void rk2818_sdmmc_start_request(struct rk2818_sdmmc_host *host)
{
struct mmc_command *cmd;
struct mmc_data *data;
u32 cmdflags;
+ unsigned long flags;
+
+ int time_out =60;
mrq = host->mrq;
- rk2818_sdmmc_setup_bus(host);
+ //rk2818_sdmmc_setup_bus(host);
+
+ /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+ while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+ mdelay(5);
+ time_out --;
+
+ if(!time_out){
+ time_out =60;
+ xjhprintk("card busy now,can not issuse req! \nreset DMA and FIFO\n");
+ local_irq_save(flags);
+
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ) & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ }
+ //cpu_relax();
+ }
+ /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+ if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+ xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+ rk2818_show_regs(host);
+ local_irq_save(flags);
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ //cpu_relax();
+ }
host->mrq = mrq;
host->stop_cmdr = rk2818_sdmmc_prepare_command(host->mmc, mrq->stop);
dev_dbg(host->dev, "mrq stop: stop_cmdr = %d", host->stop_cmdr);
}
+
}
struct rk2818_sdmmc_host *host = mmc_priv(mmc);
WARN_ON(host->mrq);
-
+ #if 0
if (!test_bit(RK2818_MMC_CARD_PRESENT, &host->flags)) {
mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq);
return;
}
+ #endif
rk2818_sdmmc_queue_request(host, mrq);
}
static void rk2818_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct rk2818_sdmmc_host *host = mmc_priv(mmc);
+ u32 div;
+ unsigned long flags;
+
+ xjhprintk("%s bus_width %x ios->clock %x host->clock %x ocr %x\n",
+ __FUNCTION__,ios->bus_width, ios->clock, host->clock, host->mmc->ocr_avail);
host->ctype = 0; // set default 1 bit mode
switch (ios->bus_width) {
host->ctype = SDMMC_CTYPE_4BIT;
break;
}
+
+ spin_lock_irqsave(host->lock,flags);
+ /* Set the current host bus width */
+ writel(host->ctype, host->regs + SDMMC_CTYPE);
+
if(ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
writel(readl(host->regs + SDMMC_CTRL) | SDMMC_CTRL_OD_PULLUP, host->regs + SDMMC_CTRL);
else
writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_OD_PULLUP, host->regs + SDMMC_CTRL);
+ spin_unlock_irqrestore(host->lock,flags);
- if (ios->clock) {
- spin_lock(&host->lock);
+ if (ios->clock && (host->current_speed != ios->clock)) {
/*
* Use mirror of ios->clock to prevent race with mmc
* core ios update when finding the minimum.
*/
- host->clock = ios->clock;
+ div = (((host->bus_hz + (host->bus_hz / 5)) / ios->clock)) >> 1;
+ xjhprintk("Bus speed = %dHz div:%d (actual %dHz)\n",
+ host->clock, div, (host->bus_hz / div) >> 1);
+
+ /* store the actual clock for calculations */
+ host->clock = (host->bus_hz / div) >> 1;
+ /*µÈ´ý¿¨Æ¬´«ÊäÍê³É*/
+ while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY | SDMMC_STAUTS_DATA_BUSY)){
+ udelay(10);
+ xjhprintk("SD/MMC busy now(status 0x%x),can not change clock\n",readl(host->regs + SDMMC_STATUS));
+ //cpu_relax();
+ }
+ spin_lock_irqsave(host->lock,flags);
+ /* disable clock */
+ writel(0, host->regs + SDMMC_CLKENA);
+ writel(0, host->regs + SDMMC_CLKSRC);
+ /* inform CIU */
+ mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+ /* set clock to desired speed */
+ writel(div, host->regs + SDMMC_CLKDIV);
+ /* inform CIU */
+ mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+ /* enable clock */
+ if(host->pdev->id == 0) //sdmmc0 endable low power mode
+ writel(SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE, host->regs + SDMMC_CLKENA);
+ else
+ writel(SDMMC_CLKEN_ENABLE, host->regs + SDMMC_CLKENA);
+ /* inform CIU */
+ mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
- spin_unlock(&host->lock);
- } else {
+ host->current_speed= ios->clock;
+
+ spin_unlock_irqrestore(host->lock,flags);
+
+ }
+ #if 0
+ else {
spin_lock(&host->lock);
host->clock = 0;
spin_unlock(&host->lock);
}
+ #endif
+ spin_lock_irqsave(host->lock,flags);
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(RK2818_MMC_CARD_NEED_INIT, &host->flags);
+ rk2818_sdmmc_set_power(host, host->mmc->ocr_avail);
break;
default:
+ //rk2818_sdmmc_set_power(host, 0);
break;
}
+ spin_unlock_irqrestore(host->lock,flags);
+
}
__acquires(&host->lock)
{
struct mmc_host *prev_mmc = host->mmc;
-
+ unsigned long flags;
+ int time_out =60;
+ unsigned long fifo_left;
+
WARN_ON(host->cmd || host->data);
host->mrq = NULL;
+
+ /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+ while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+ mdelay(5);
+ time_out --;
+
+ if(!time_out){
+ time_out =60;
+ xjhprintk("req done:card busy for a long time!!!reset DMA and FIFO\n");
+ local_irq_save(flags);
+
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ) & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ }
+ //cpu_relax();
+ }
+
+ #if 1
+ fifo_left = readl(host->regs + SDMMC_STATUS);
+
+ if((fifo_left & SDMMC_STAUTS_FIFO_FULL) && (fifo_left & SDMMC_STAUTS_FIFO_RX_WATERMARK))
+ {
+ xjhprintk("%s read operation reach water mark\n",__FUNCTION__);
+ rk2818_show_regs(host);
+ while(SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS))>>2)
+ readl(host->regs + SDMMC_DATA); //discard the no use data
+ rk2818_show_regs(host);
+
+ }
+ #endif
+ /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+ if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+ xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+ rk2818_show_regs(host);
+ local_irq_save(flags);
+ // writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ // while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+
+ writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+ /* wait till resets clear */
+ while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+ local_irq_restore(flags);
+ //cpu_relax();
+ }
+
if (!list_empty(&host->queue)) {
host = list_entry(host->queue.next,
struct rk2818_sdmmc_host, queue_node);
cmd->error = -EILSEQ;
else if (status & SDMMC_INT_RE)
cmd->error = -EIO;
+ else if(status & SDMMC_INT_HLE)
+ cmd->error = -EIO;
else
cmd->error = 0;
"cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n",
status, cmd->resp[0],
cmd->opcode, cmd->arg, cmd->flags, cmd->error);
+
if (cmd->data) {
host->data = NULL;
struct rk2818_sdmmc_host *host = (struct rk2818_sdmmc_host *)priv;
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = host->data;
- struct mmc_command *cmd = host->cmd;
enum rk2818_sdmmc_state state = host->state;
enum rk2818_sdmmc_state prev_state;
u32 status;
+ int timeout=5000;
spin_lock(&host->lock);
state = host->state;
do {
prev_state = state;
+ timeout --;
+ if(!timeout)
+ {
+ timeout = 5000;
+ xjhprintk("%s\n",__FUNCTION__);
+ }
switch (state) {
case STATE_IDLE:
host->cmd = NULL;
rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
rk2818_sdmmc_command_complete(host, mrq->cmd);
- if (!mrq->data || cmd->error) {
+ //if (!mrq->data || cmd->error) {
+ if (!mrq->data || mrq->cmd->error) {
rk2818_sdmmc_request_end(host, host->mrq);
goto unlock;
}
case STATE_SENDING_DATA:
if (rk2818_sdmmc_test_and_clear_pending(host,
EVENT_DATA_ERROR)) {
+ xjhprintk("[xjh] %s data->stop %p\n", __FUNCTION__,data->stop);
rk2818_sdmmc_stop_dma(host);
+ #if 0
if (data->stop)
send_stop_cmd(host, data);
+ #else
+ if (data->stop)
+ send_stop_cmd(host, data);
+ else //cmd17 or cmd24
+ {
+ xjhprintk("%s>> send stop command mannualy\n",__FUNCTION__);
+ host->stop_mannual.opcode = MMC_STOP_TRANSMISSION;
+ host->stop_mannual.arg = 0;
+ host->stop_mannual.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ host->stop_cmdr = 0x414c;
+
+ host->mrq->stop = &host->stop_mannual;
+ data->stop = &host->stop_mannual;
+ send_stop_cmd(host, data);
+ }
+ #endif
state = STATE_DATA_ERROR;
+ xjhprintk("[xjh] %s sendging data error\n", __FUNCTION__);
break;
}
status = host->data_status;
if (unlikely(status & RK2818_MCI_DATA_ERROR_FLAGS)) {
+ xjhprintk("[xjh] %s data error\n", __FUNCTION__);
if (status & SDMMC_INT_DRTO) {
dev_err(host->dev,
"data timeout error\n");
if (!rk2818_sdmmc_test_and_clear_pending(host,
EVENT_CMD_COMPLETE))
break;
-
+
+ //xjhprintk("[xjh] %s sending stop cmd end\n", __FUNCTION__);
host->cmd = NULL;
rk2818_sdmmc_command_complete(host, mrq->stop);
rk2818_sdmmc_request_end(host, host->mrq);
if (!rk2818_sdmmc_test_and_clear_pending(host,
EVENT_XFER_COMPLETE))
break;
-
+ #if 0
+ //[xjh] cmd17ûÓвúÉúDTOÖжϣ¬EVENT_DATA_COMPLETEûÓб»ÉèÖã¬ÐèÒªÊÖ¹¤ÉèÖÃ
+ //ΪºÎcmd17³ö´íºó²»ÄܲúÉúDTOÖжϣ¬ÐèÒª½øÒ»²½²éÃ÷???????
+ if((host->mrq->cmd->opcode == 17)) {
+ xjhprintk("%s cmd%d was interrupt(host->pending_events %x)\n",
+ __FUNCTION__,host->mrq->cmd->opcode,host->pending_events);
+ // rk2818_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
+ }
+ #endif
+
state = STATE_DATA_BUSY;
break;
}
struct mmc_data *data = host->data;
u32 status;
unsigned int nbytes = 0,len,old_len,count =0;
+ xjhprintk("[xjh] %s enter,sg->length 0x%x\n", __FUNCTION__, sg->length);
do {
len = SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS)) << 2;
len = SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS));
host->pio_offset = offset;
data->bytes_xfered += nbytes;
+ xjhprintk("[xjh] %s exit-1\n", __FUNCTION__);
return;
done:
data->bytes_xfered += nbytes;
smp_wmb();
rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+ xjhprintk("[xjh] %s exit-2\n", __FUNCTION__);
}
static void rk2818_sdmmc_write_data_pio(struct rk2818_sdmmc_host *host)
struct rk2818_sdmmc_host *host = data;
u32 status, pending;
unsigned int pass_count = 0;
+ bool present;
+ bool present_old;
spin_lock(&host->lock);
do {
if (!pending)
break;
if(pending & SDMMC_INT_CD) {
- disable_irq_nosync(irq);
writel(SDMMC_INT_CD, host->regs + SDMMC_RINTSTS); // clear interrupt
- mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+
+ present = rk2818_sdmmc_get_cd(host->mmc);
+ present_old = test_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+ if(present != present_old) {
+
+ if (present != 0) {
+ set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+ } else {
+ clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+ }
+
+ if(host->pdev->id ==0) { //sdmmc0
+ xjhprintk("[xjh] %s >> %s >> %d sd/mmc insert/remove occur: Removal %d present %d present_old %d\n",
+ __FILE__, __FUNCTION__,__LINE__,sdmmc0_disable_Irq_ForRemoval,present,present_old);
+ if(0 == sdmmc0_disable_Irq_ForRemoval) {
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+ if(!test_bit(RK2818_MMC_CARD_PRESENT, &host->flags))
+ sdmmc0_disable_Irq_ForRemoval = 1;
+ }
+ else
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK28_SDMMC0_SWITCH_POLL_DELAY));
+ } else { //sdio
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+ }
+ }
}
+
if(pending & RK2818_MCI_CMD_ERROR_FLAGS) {
writel(RK2818_MCI_CMD_ERROR_FLAGS, host->regs + SDMMC_RINTSTS); // clear interrupt
+ if(status & SDMMC_INT_HLE)
+ {
+ xjhprintk("[xjh] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n",
+ __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
+
+ }
host->cmd_status = status;
smp_wmb();
rk2818_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
tasklet_schedule(&host->tasklet);
+ host->cmd_tmo = 1;
+ xjhprintk("[xjh] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n",
+ __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
}
if (pending & RK2818_MCI_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR
smp_wmb();
rk2818_sdmmc_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
+ xjhprintk("[xjh] %s :data transfer error(int status 0x%x host->state %d pending_events %d)\n",
+ __FUNCTION__,status,host->state,host->pending_events);
}
if (pending & SDMMC_INT_CMD_DONE) {
writel(SDMMC_INT_CMD_DONE, host->regs + SDMMC_RINTSTS); // clear interrupt
rk2818_sdmmc_cmd_interrupt(host, status);
+ host->cmd_tmo = 1;
+
}
if(pending & SDMMC_INT_SDIO) {
writel(SDMMC_INT_SDIO, host->regs + SDMMC_RINTSTS);
} while (pass_count++ < 5);
spin_unlock(&host->lock);
+
//return IRQ_HANDLED;
return pass_count ? IRQ_HANDLED : IRQ_NONE;
static void rk2818_sdmmc_detect_change(unsigned long host_data)
{
struct rk2818_sdmmc_host *host = (struct rk2818_sdmmc_host *) host_data;
- struct mmc_request *mrq;
- bool present;
- bool present_old;
+ //bool present;
+ //bool present_old;
+ //unsigned long flags;
+ #if 0
+ mrq = host->mrq;
+ if (mrq) {
- enable_irq(host->irq);
- present = rk2818_sdmmc_get_cd(host->mmc);
- present_old = test_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
- dev_dbg(host->dev, "detect change: %d (was %d)\n",
- present, present_old);
+ host->data = NULL;
+ host->cmd = NULL;
+ xjhprintk("[xjh] %s >> %s >> %d stage 2\n", __FILE__, __FUNCTION__,__LINE__);
- if (present != present_old) {
+ switch (host->state) {
+ case STATE_IDLE:
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+ if (!mrq->data)
+ break;
+ /* fall through */
+ case STATE_SENDING_DATA:
+ mrq->data->error = -ENOMEDIUM;
+ xjhprintk("[xjh] %s host %p\n", __FUNCTION__,host);
+ rk2818_sdmmc_stop_dma(host);
+ break;
+ case STATE_DATA_BUSY:
+ case STATE_DATA_ERROR:
+ if (mrq->data->error == -EINPROGRESS)
+ mrq->data->error = -ENOMEDIUM;
+ if (!mrq->stop)
+ break;
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
+ }
- dev_dbg(host->dev, "card %s\n", present ? "inserted" : "removed");
+ rk2818_sdmmc_request_end(host, mrq);
+ }
+ #endif
+
+ // spin_lock( &sdmmc0_spinlock);
+// xjhprintk("%s....%s....%d **** timer open, then enable IRQ_OF_removal/insertion*****xbw****\n",__FUNCTION__,__FILE__,__LINE__);
+// sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжÏ
+// spin_unlock( &sdmmc0_spinlock);
+
+ mmc_detect_change(host->mmc, 0);
+
+}
- spin_lock(&host->lock);
- /* Power up host */
- if (present != 0) {
- rk2818_sdmmc_set_power(host, host->mmc->ocr_avail);
+/*--------------------add communication interface with applications ---------------------------------*/
+int resetTimes = 0;//ͳ¼ÆÁ¬ÐøresetµÄ´ÎÊý¡£
+ssize_t sdmmc_reset_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ //»òÕß´Ókobj×·Ëݵ½rk2818_sdmmc_host£¬½ÓÏÂÀ´³¢ÊÔ
+ struct rk2818_sdmmc_host *host = mmc0_host;
+ struct mmc_host *mmc = host->mmc;
+ int currentTimes=0;
+ unsigned long flags;
+
+ if( !strncmp(buf,"RemoveDone" , strlen("RemoveDone")) )
+ {
+ xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+
+ local_irq_save(flags);
+ del_timer(&host->detect_timer);
+ sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжÏ
+ local_irq_restore(flags);
+
+ //Ö÷¶¯Ö´ÐÐÒ»´Î¼ì²â, ÈôÓп¨´æÔÚ
+ if(rk2818_sdmmc_get_cd(host->mmc)) {
+ // mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
- } else {
- rk2818_sdmmc_set_power(host, 0);
- clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
- }
+ mmc_detect_change(mmc, 0);
+ }
+ }
+ else if( !strncmp(buf,"Removing" , strlen("Removing")) )
+ {
+ xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+ //vold is removing, so modify the timer.
+ mod_timer(&host->detect_timer, jiffies +msecs_to_jiffies(RK28_SDMMC0_SWITCH_POLL_DELAY));
+ }
+ else if( !strncmp(buf,"to_reset!" , strlen("to_reset!")) )
+ {
+ xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+
+ //ÉèÖÃresetµÄÔÊÐí´ÎÊý
+ ++resetTimes;
+ currentTimes = resetTimes;
+
+ //Á¬Ðøµ÷ÓÃreset³¬¹ý´ÎÊý£¬²»Ö´ÐС£
+ if(currentTimes <= 3)
+ {
+ xjhprintk("%s....%s....%d **** Begin to call rk28_sdmmc_reset() Times=%d *****xbw****\n",__FUNCTION__,__FILE__,__LINE__, resetTimes);
+ // rk28_sdmmc_reset();
+ }
+ }
+ else if(!strncmp(buf,"mounted!" , strlen("mounted!")))
+ {
+ xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+ resetTimes = 0;
+ }
+ else if(!strncmp(buf,"dump_reg" , strlen("dump_reg")))
+ {
+ unsigned long cpsr_tmp;
+ xjhprintk("-------- SD/MMC/SDIO dump Registers-----------------\n");
+ xjhprintk("SDMMC_CTRL:\t0x%x\n",readl(host->regs + SDMMC_CTRL));
+ xjhprintk("SDMMC_PWREN:\t0x%x\n",readl(host->regs + SDMMC_PWREN));
+ xjhprintk("SDMMC_CLKDIV:\t0x%x\n",readl(host->regs + SDMMC_CLKDIV));
+ xjhprintk("SDMMC_CLKSRC:\t0x%x\n",readl(host->regs + SDMMC_CLKSRC));
+ xjhprintk("SDMMC_CLKENA:\t0x%x\n",readl(host->regs + SDMMC_CLKENA));
+ xjhprintk("SDMMC_TMOUT:\t0x%x\n",readl(host->regs + SDMMC_TMOUT));
+ xjhprintk("SDMMC_CTYPE:\t0x%x\n",readl(host->regs + SDMMC_CTYPE));
+ xjhprintk("SDMMC_BLKSIZ:\t0x%x\n",readl(host->regs + SDMMC_BLKSIZ));
+ xjhprintk("SDMMC_BYTCNT:\t0x%x\n",readl(host->regs + SDMMC_BYTCNT));
+ xjhprintk("SDMMC_INTMASK:\t0x%x\n",readl(host->regs + SDMMC_INTMASK));
+ xjhprintk("SDMMC_CMDARG:\t0x%x\n",readl(host->regs + SDMMC_CMDARG));
+ xjhprintk("SDMMC_CMD:\t0x%x\n",readl(host->regs + SDMMC_CMD));
+ xjhprintk("SDMMC_RESP0:\t0x%x\n",readl(host->regs + SDMMC_RESP0));
+ xjhprintk("SDMMC_RESP1:\t0x%x\n",readl(host->regs + SDMMC_RESP1));
+ xjhprintk("SDMMC_RESP2:\t0x%x\n",readl(host->regs + SDMMC_RESP2));
+ xjhprintk("SDMMC_RESP3:\t0x%x\n",readl(host->regs + SDMMC_RESP3));
+ xjhprintk("SDMMC_MINTSTS:\t0x%x\n",readl(host->regs + SDMMC_MINTSTS));
+ xjhprintk("SDMMC_RINTSTS:\t0x%x\n",readl(host->regs + SDMMC_RINTSTS));
+ xjhprintk("SDMMC_STATUS:\t0x%x\n",readl(host->regs + SDMMC_STATUS));
+ xjhprintk("SDMMC_FIFOTH:\t0x%x\n",readl(host->regs + SDMMC_FIFOTH));
+ xjhprintk("SDMMC_CDETECT:\t0x%x\n",readl(host->regs + SDMMC_CDETECT));
+ xjhprintk("SDMMC_WRTPRT:\t0x%x\n",readl(host->regs + SDMMC_WRTPRT));
+ xjhprintk("SDMMC_TCBCNT:\t0x%x\n",readl(host->regs + SDMMC_TCBCNT));
+ xjhprintk("SDMMC_TBBCNT:\t0x%x\n",readl(host->regs + SDMMC_TBBCNT));
+ xjhprintk("SDMMC_DEBNCE:\t0x%x\n",readl(host->regs + SDMMC_DEBNCE));
+ xjhprintk("-------- Host states-----------------\n");
+ xjhprintk("host->state:\t0x%x\n",host->state);
+ xjhprintk("host->pending_events:\t0x%x\n",host->pending_events);
+ xjhprintk("host->cmd_status:\t0x%x\n",host->cmd_status);
+ xjhprintk("host->data_status:\t0x%x\n",host->data_status);
+ xjhprintk("host->stop_cmdr:\t0x%x\n",host->stop_cmdr);
+ xjhprintk("host->dir_status:\t0x%x\n",host->dir_status);
+ xjhprintk("host->completed_events:\t0x%x\n",host->completed_events);
+ xjhprintk("host->dma_chn:\t0x%x\n",host->dma_chn);
+ xjhprintk("host->use_dma:\t0x%x\n",host->use_dma);
+ xjhprintk("host->no_detect:\t0x%x\n",host->no_detect);
+ xjhprintk("host->bus_hz:\t0x%x\n",host->bus_hz);
+ xjhprintk("host->current_speed:\t0x%x\n",host->current_speed);
+ xjhprintk("host->ctype:\t0x%x\n",host->ctype);
+ xjhprintk("host->clock:\t0x%x\n",host->clock);
+ xjhprintk("host->flags:\t0x%x\n",host->flags);
+ xjhprintk("host->irq:\t0x%x\n",host->irq);
+ xjhprintk("-------- rk2818 CPU register-----------------\n");
+ __asm__ volatile ("mrs %0, cpsr @ local_irq_save\n":"=r" (cpsr_tmp)::"memory", "cc" );
+ xjhprintk("cpsr:\t0x%x\n",cpsr_tmp);
+
- mrq = host->mrq;
- if (mrq) {
- writel((SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET|
- SDMMC_CTRL_INT_ENABLE), host->regs + SDMMC_CTRL);
- /* wait till resets clear */
- while (readl(host->regs + SDMMC_CTRL) &
- (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+ }
- host->data = NULL;
- host->cmd = NULL;
+ return count;
+}
- switch (host->state) {
- case STATE_IDLE:
- break;
- case STATE_SENDING_CMD:
- mrq->cmd->error = -ENOMEDIUM;
- if (!mrq->data)
- break;
- /* fall through */
- case STATE_SENDING_DATA:
- mrq->data->error = -ENOMEDIUM;
- rk2818_sdmmc_stop_dma(host);
- break;
- case STATE_DATA_BUSY:
- case STATE_DATA_ERROR:
- if (mrq->data->error == -EINPROGRESS)
- mrq->data->error = -ENOMEDIUM;
- if (!mrq->stop)
- break;
- case STATE_SENDING_STOP:
- mrq->stop->error = -ENOMEDIUM;
- break;
- }
- rk2818_sdmmc_request_end(host, mrq);
- }
- spin_unlock(&host->lock);
- mmc_detect_change(host->mmc, 0);
- }
+struct kobj_attribute mmc_reset_attrs =
+{
+ .attr = {
+ .name = "rescan",
+ .mode = 0777},
+ .show = NULL,
+ .store = sdmmc_reset_store,
+};
+struct attribute *mmc_attrs[] =
+{
+ &mmc_reset_attrs.attr,
+ NULL
+};
+
+static struct kobj_type mmc_kset_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_attrs = &mmc_attrs[0],
+};
+static int rk28_sdmmc0_add_attr( struct platform_device *pdev )
+{
+ int result;
+ struct kobject *parentkobject;
+ struct kobject * me = kmalloc(sizeof(struct kobject) , GFP_KERNEL );
+ if( !me )
+ return -ENOMEM;
+ memset(me ,0,sizeof(struct kobject));
+ kobject_init( me , &mmc_kset_ktype );
+ //result = kobject_add( me , &pdev->dev.kobj , "%s", "RESET" );
+ parentkobject = &pdev->dev.kobj ;
+ result = kobject_add( me , parentkobject->parent->parent, "%s", "resetSdCard" );
+ return result;
}
+/*-------------------end of add communication interface with applications ---------------------------------*/
static int rk2818_sdmmc_probe(struct platform_device *pdev)
{
mmc->max_seg_size = 4095 * 4;
rk2818_sdmmc_set_power(host, 0);
+
+ /* Create card detect handler thread for the host */
+ setup_timer(&host->detect_timer, rk2818_sdmmc_detect_change,
+ (unsigned long)host);
+
+ writel(0xFFFFFFFF, host->regs + SDMMC_RINTSTS);
+ writel(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK2818_MCI_ERROR_FLAGS | SDMMC_INT_CD,
+ host->regs + SDMMC_INTMASK);
+
/* Assume card is present initially */
- if(host->no_detect == 1 || rk2818_sdmmc_get_cd(host->mmc) != 0)
+ if(rk2818_sdmmc_get_cd(host->mmc) == 0 &&strncmp(host->dma_name, "sdio", strlen("sdio")) == 0)
+ {
+ dev_err(&pdev->dev, "failed to detect sdio.\n");
+ return 0;
+ }
+ else if(rk2818_sdmmc_get_cd(host->mmc) != 0)
set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
else
clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+
ret = mmc_add_host(mmc);
if(ret)
{
dev_err(&pdev->dev, "failed to add mmc host.\n");
goto err_free_irq;
}
+ if (strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 0) {
+ xjhprintk("[xjh] sdmmc0 add interface with application\n");
+ sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжÏ
+ mmc0_host = host;
+ rk28_sdmmc0_add_attr(pdev);
+ }
+
#if defined (CONFIG_DEBUG_FS)
rk2818_sdmmc_init_debugfs(host);
#endif
- /* Create card detect handler thread for the host */
- setup_timer(&host->detect_timer, rk2818_sdmmc_detect_change,
- (unsigned long)host);
-
- writel(0xFFFFFFFF, host->regs + SDMMC_RINTSTS);
- writel(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_TXDR |
- SDMMC_INT_RXDR | RK2818_MCI_ERROR_FLAGS | SDMMC_INT_CD,
- host->regs + SDMMC_INTMASK);
writel(SDMMC_CTRL_INT_ENABLE, host->regs + SDMMC_CTRL); // enable mci interrupt
-
dev_info(&pdev->dev, "RK2818 MMC controller used as %s, at irq %d\n",
host->dma_name, host->irq);
- if (strncmp(host->dma_name, "sdio", 4) == 0)
+ if (strncmp(host->dma_name, "sdio", strlen("sdio")) == 0)
wifi_mmc_host = mmc;
return 0;
-
err_free_irq:
free_irq(host->irq, host);
err_free_clk: