#define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT
#define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react.
-#define RK29_SDMMC_VERSION "Ver.3.04 The last modify date is 2012-03-29,modifyed by XBW."
+#define RK29_SDMMC_VERSION "Ver.3.05 The last modify date is 2012-03-31,modifyed by XBW."
#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC
struct rk29_sdmmc {
spinlock_t lock;
- spinlock_t irqlock;
void __iomem *regs;
struct clk *clk;
static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_data *data)
{
- //uint32 value;
int output;
u32 i = 0;
u32 dataLen;
switch(host->state)
{
case STATE_IDLE:
- {
- #if 1
- break;
- #else
- if(!host->cmd)
- break;
-
- host->cmd->error = -EIO;
-
- if(host->cmd->data)
- {
- host->cmd->data->error = -EILSEQ;
- }
- host->state = STATE_SENDING_CMD;
- /* fall through */
- #endif
- }
-
+ break;
case STATE_SENDING_CMD:
host->cmd_status |= SDMMC_INT_RTO;
host->cmd->error = -ETIME;
rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
tasklet_schedule(&host->tasklet);
break;
+ case STATE_DATA_END:
+ break;
+ default:
+ break;
}
}
static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data)
{
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
- unsigned long iflags;
spin_lock(&host->lock);
static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data)
{
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
- unsigned long iflags;
spin_lock(&host->lock);
- if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state))
+#if SDMMC_USE_INT_UNBUSY
+ if( (host->cmdr & SDMMC_CMD_DAT_EXP) &&((STATE_DATA_BUSY == host->state)||(STATE_DATA_UNBUSY == host->state) ))
+#else
+ if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state))
+#endif
{
if(0==host->cmd->retries)
{
u32 cmdr, ret;
unsigned long iflags;
- //spin_lock(&host->lock);//
spin_lock_irqsave(&host->lock, iflags);
mrq = host->new_mrq;
__FUNCTION__, __LINE__, host->cmd->opcode,ret, \
host->state,host->cmd_status, host->pending_events,host->completed_events,host->dma_name);
- //spin_unlock(&host->lock);//
spin_unlock_irqrestore(&host->lock, iflags);
return SDM_SUCCESS;
if(host->mrq && host->mmc->doneflag)
{
host->mmc->doneflag = 0;
- //spin_unlock(&host->lock);//
spin_unlock_irqrestore(&host->lock, iflags);
mmc_request_done(host->mmc, host->mrq);
}
else
{
- //spin_unlock(&host->lock);//
- spin_unlock_irqrestore(&host->lock, iflags);
-
+ spin_unlock_irqrestore(&host->lock, iflags);
}
return ret;
{
int timeout = 250;
unsigned int value;
- unsigned long iflags;
struct rk29_sdmmc *host = mmc_priv(mmc);
- spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags);
+ spin_lock(&host->lock);
if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDMMC_ID == host->pdev->id))
{
}
out:
- spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);
}
rk29_sdmmc_command_complete(host, host->mrq->cmd);
rk29_sdmmc_request_end(host, host->mrq->cmd);
-
-}
-static void rk29_sdmmc_enable_irq(struct rk29_sdmmc *host, bool enable)
-{
- unsigned long iflags;
- spin_lock_irqsave(&host->irqlock, iflags);
- if(enable)
- {
- enable_irq(host->irq);
- }
- else
- {
- disable_irq(host->irq);
- }
- spin_unlock_irqrestore(&host->irqlock, iflags);
}
-
static void rk29_sdmmc_tasklet_func(unsigned long priv)
{
struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv;
enum rk29_sdmmc_state state = host->state;
int pending_flag, stopflag;
unsigned long iflags;
-
- //rk29_sdmmc_enable_irq(host, 0);
- //disable_irq(host->irq);
- //spin_lock(&host->lock);//
+
spin_lock_irqsave(&host->lock, iflags);
state = host->state;
break;
host->errorstep = 0xf8;
rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE);
- del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
- #if SDMMC_USE_INT_UNBUSY
+ #if SDMMC_USE_INT_UNBUSY
+ if((24==host->cmd->opcode)||(25==host->cmd->opcode))
+ {
+ /*
+ ** use DTO_timer for waiting for INT_UNBUSY.
+ ** max 250ms in specification, but adapt 500 for the compatibility of all kinds of sick sdcard.
+ */
+ mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(250));
+ }
+ else
+ {
+ del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+ }
+
state = STATE_DATA_UNBUSY;
- #endif
+
+ #else
+ del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+ #endif
}
case STATE_DATA_UNBUSY:
{
#if SDMMC_USE_INT_UNBUSY
if((24==host->cmd->opcode)||(25==host->cmd->opcode))
- { // printk("%d: ******************1111111111, hoststate=%x*******************\n", __LINE__, state);
+ {
if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_UNBUSY))
- break;
+ break;
+
+ del_timer_sync(&host->DTO_timer);
}
- // printk("%d: ******************222222222*******************\n", __LINE__);
rk29_sdmmc_set_completed(host, EVENT_DATA_UNBUSY);
state = STATE_DATA_END;
#endif
host->complete_done = 3;
break;
}
-
+
+ case STATE_DATA_END:
+ break;
+ default:
+ break;
}
pending_flag = (host->complete_done > 0) && (host->retryfunc<50) \
&& (rk29_sdmmc_test_pending(host, EVENT_CMD_COMPLETE)|| rk29_sdmmc_test_pending(host, EVENT_DATA_COMPLETE) );
-// pending_flag=0;
+
if(pending_flag)
{
xbwprintk(7, "%s..%d... cmd=%d(arg=0x%x),completedone=%d, retrycount=%d, doneflag=%d, \n \
}
} while(pending_flag && ++host->retryfunc); //while(0);
- // printk("%d: ******************333333333*******************\n", __LINE__);
if(0!=stopflag)
{
{
host->errorstep = 0xf2;
- // printk("%d: ******************44444444444, hoststat=%x*******************\n", __LINE__, host->state);
spin_unlock_irqrestore(&host->lock, iflags);
-
-
- //enable_irq(host->irq);
return;
}
host->errorstep = 0xf3;
if(host->mrq && host->mmc->doneflag)
{
host->mmc->doneflag = 0;
-
- //rk29_sdmmc_enable_irq(host, 1);
- //enable_irq(host->irq);
- //spin_unlock(&host->lock);//
- spin_unlock_irqrestore(&host->lock, iflags);
-
+ spin_unlock_irqrestore(&host->lock, iflags);
mmc_request_done(host->mmc, host->mrq);
}
else
{
-
- //rk29_sdmmc_enable_irq(host, 1);
- //enable_irq(host->irq);
- //spin_unlock(&host->lock);
- spin_unlock_irqrestore(&host->lock, iflags);
-
+ spin_unlock_irqrestore(&host->lock, iflags);
}
}
bool present;
bool present_old;
int sdio_irq=0;
- //unsigned long iflags;
- spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags);
+ spin_lock(&host->lock);
status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS);
pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg
if(!(pending & SDMMC_INT_CMD_DONE))
{
- //disable_irq_nosync(host->irq);
tasklet_schedule(&host->tasklet);
- }
+ }
goto Exit_INT;
}
goto Exit_INT;
}
-#if SDMMC_USE_INT_UNBUSY
- if(pending & SDMMC_INT_UNBUSY)
- {
- xbwprintk(1, "%d..%s: INT=0x%x ,RINTSTS=0x%x, CMD%d(arg=0x%x, retries=%d),host->state=0x%x ==xbw[%s]==\n *********\n", \
- __LINE__,__FUNCTION__, pending,status, host->cmd->opcode, host->cmd->arg, host->cmd->retries, host->state,host->dma_name);
-
- rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY);
-
- if(!((pending & SDMMC_INT_TXDR)||(pending & SDMMC_INT_RXDR)) )
- {
- host->data_status = status;
- smp_wmb();
- // printk("%d: ******************000000000000*******************\n", __LINE__);
- rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY);
- tasklet_schedule(&host->tasklet);
- }
-
- goto Exit_INT;
- }
-#endif
-
if (pending & SDMMC_INT_RXDR)
{
xbwprintk(6, "%s..%d.. SDMMC_INT_RXDR INT=0x%x ====xbw[%s]====\n", \
{
xbwprintk(6, "%s..%d.. SDMMC_INT_TXDR INT=0x%x ====xbw[%s]====\n", \
__FUNCTION__, __LINE__, pending, host->dma_name);
-
- rk29_sdmmc_do_pio_write(host);
-
+
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear interrupt
+ rk29_sdmmc_do_pio_write(host);
}
+#if SDMMC_USE_INT_UNBUSY
+ if(pending & SDMMC_INT_UNBUSY)
+ {
+ xbwprintk(1, "%d..%s: INT=0x%x ,RINTSTS=0x%x, CMD%d(arg=0x%x, retries=%d),host->state=0x%x ==xbw[%s]==\n", \
+ __LINE__,__FUNCTION__, pending,status, host->cmd->opcode, host->cmd->arg, host->cmd->retries, \
+ host->state,host->dma_name);
+
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY);
+
+ host->data_status = status;
+ smp_wmb();
+ rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY);
+ tasklet_schedule(&host->tasklet);
+
+ goto Exit_INT;
+ }
+#endif
+
Exit_INT:
- spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);
if(1 == sdio_irq)
{
pdata->io_init();
spin_lock_init(&host->lock);
- spin_lock_init(&host->irqlock);
#ifdef RK29_SDMMC_LIST_QUEUE
INIT_LIST_HEAD(&host->queue);