#define xbwprintk(n, arg...)
#endif
-#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
+#if defined(CONFIG_ARCH_RK29)
+#define SDMMC_USE_INT_UNBUSY 0
+#else
+#define SDMMC_USE_INT_UNBUSY 1
+#endif
-#if defined(CONFIG_ARCH_RK29)
-#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
-#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
-#elif defined(CONFIG_ARCH_RK30)
+#if SDMMC_USE_INT_UNBUSY
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+#else
+#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
+#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#endif
#define RK29_SDMMC_SEND_START_TIMEOUT 3000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
#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.03 The last modify date is 2012-03-23,modifyed by XBW."
+#define RK29_SDMMC_VERSION "Ver.3.04 The last modify date is 2012-03-29,modifyed by XBW."
#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC
#endif
#define SDMMC_CLOCK_TEST 0
+
#define RK29_SDMMC_NOTIFY_REMOVE_INSERTION /* use sysfs to notify the removal or insertion of sd-card*/
//#define RK29_SDMMC_LIST_QUEUE /* use list-queue for multi-card*/
enum {
EVENT_CMD_COMPLETE = 0,
EVENT_DATA_COMPLETE,
+ EVENT_DATA_UNBUSY,
EVENT_DATA_ERROR,
EVENT_XFER_ERROR
};
STATE_IDLE = 0,
STATE_SENDING_CMD,
STATE_DATA_BUSY,
+ STATE_DATA_UNBUSY,
+ STATE_DATA_END,
STATE_SENDING_STOP,
};
struct rk29_sdmmc {
spinlock_t lock;
+ spinlock_t irqlock;
void __iomem *regs;
struct clk *clk;
u32 *pbuf;
SDC_INT_INFO_T intInfo;
struct rk29_sdmmc_dma_info dma_info;
-
+ int irq;
int error_times;
u32 old_cmd;
test_and_clear_bit(event, &host->pending_events)
#define rk29_sdmmc_test_pending(host, event) \
test_bit(event, &host->pending_events)
+#define rk29_sdmmc_test_completed(host, event) \
+ test_bit(event, &host->completed_events)
#define rk29_sdmmc_set_completed(host, event) \
set_bit(event, &host->completed_events)
-
#define rk29_sdmmc_set_pending(host, event) \
set_bit(event, &host->pending_events)
}
spin_lock(&host->lock);
-
if(strncmp(buf,oldbuf , strlen(buf)))
{
printk(".%d.. MMC0 receive the message %s from VOLD.====xbw[%s]====\n", __LINE__, buf, host->dma_name);
/* Make sure we get a consistent snapshot */
spin_lock(&host->lock);
+
mrq = host->mrq;
if (mrq) {
}
#endif
-
static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd)
{
u32 cmdr = cmd->opcode;
rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register
- xbwprintk(5, "\n%s..%d..************.start cmd=%d, arg=0x%x ********=====xbw[%s]=======\n", \
+ xbwprintk(1,"\n%s..%d..************.start cmd=%d, arg=0x%x ********=====xbw[%s]=======\n", \
__FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->dma_name);
host->mmc->doneflag = 1;
static int rk29_sdmmc_wait_unbusy(struct rk29_sdmmc *host)
{
- int time_out = 500000;//250000; //max is 250ms; //adapt the value to the sick card. modify at 2011-10-08
+ int time_out = 500000;//250000; //max is 250ms; //adapt the value to the sick card. modify at 2011-10-08
+#if SDMMC_USE_INT_UNBUSY
+ if((24==host->cmd->opcode)||(25==host->cmd->opcode))
+ return SDM_SUCCESS;
+#endif
while (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))
{
udelay(1);
rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks);
rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz);
- xbwprintk(6, "%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d ==xbw=[%s]==\n", \
+ xbwprintk(1, "%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d ==xbw=[%s]==\n", \
__FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg,data->blksz, data->blocks, host->dma_name);
if (data->flags & MMC_DATA_WRITE)
rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
tasklet_schedule(&host->tasklet);
break;
+#if SDMMC_USE_INT_UNBUSY
+ case STATE_DATA_UNBUSY:
+ host->data_status |= (SDMMC_INT_DCRC|SDMMC_INT_EBE);
+ host->cmd->data->error = -EILSEQ;
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY); // clear interrupt
+ rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY);
+ tasklet_schedule(&host->tasklet);
+ break;
+#endif
case STATE_SENDING_STOP:
host->cmd_status |= SDMMC_INT_RTO;
host->cmd->error = -ETIME;
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
unsigned long iflags;
- spin_lock_irqsave(&host->lock, iflags);
+ spin_lock(&host->lock);
if(STATE_SENDING_CMD == host->state)
{
rk29_sdmmc_dealwith_timeout(host);
}
- spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);
}
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
unsigned long iflags;
- spin_lock_irqsave(&host->lock, iflags);
-
+ spin_lock(&host->lock);
if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state))
{
rk29_sdmmc_dealwith_timeout(host);
}
- spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);
}
u32 cmdr, ret;
unsigned long iflags;
+ //spin_lock(&host->lock);//
spin_lock_irqsave(&host->lock, iflags);
mrq = host->new_mrq;
mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+500));
}
-
+
ret = rk29_sdmmc_start_command(host, cmd, host->cmdr);
if(SDM_SUCCESS != ret)
{
__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;
start_request_Err:
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);
+
}
return ret;
}
host->state = STATE_IDLE;
spin_unlock_irqrestore(&host->lock, iflags);
+
mmc_request_done(mmc, mrq);
return;
}
host->state = STATE_IDLE;
mrq->cmd->error = -ENOMEDIUM;
spin_unlock_irqrestore(&host->lock, iflags);
+
mmc_request_done(mmc, mrq);
return;
}
host->new_mrq = mrq;
spin_unlock_irqrestore(&host->lock, iflags);
-
+
rk29_sdmmc_start_request(mmc);
#else
unsigned long iflags;
struct rk29_sdmmc *host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, iflags);
+ spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags);
if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDMMC_ID == host->pdev->id))
{
}
out:
- spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags);
+
}
static int rk29_sdmmc_get_ro(struct mmc_host *mmc)
unsigned long flags;
struct rk29_sdmmc *host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
+
intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK);
if(enable)
rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO);
else
rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO);
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
+
}
static void rk29_sdmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
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)
{
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;
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
+ state = STATE_DATA_UNBUSY;
+ #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;
+ }
+ // printk("%d: ******************222222222*******************\n", __LINE__);
+ rk29_sdmmc_set_completed(host, EVENT_DATA_UNBUSY);
+ state = STATE_DATA_END;
+ #endif
rk29_sdmmc_request_end(host, host->cmd);
if (data && !data->stop)
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)
{
if(0==host->complete_done)
{
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;
- host->state = STATE_IDLE;
+ host->state = STATE_IDLE;
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);
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);
+
}
}
u32 status, pending;
bool present;
bool present_old;
- unsigned long iflags;
+ int sdio_irq=0;
+ //unsigned long iflags;
- spin_lock_irqsave(&host->lock, iflags);
+ spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags);
status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS);
pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg
if(pending & SDMMC_INT_CD)
{
+ //disable_irq_nosync(host->irq);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, SDMMC_INT_CD); // clear sd detect int
present = rk29_sdmmc_get_cd(host->mmc);
present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
goto Exit_INT;
- }
-
+ }
+
+ xbwprintk(1,"\n*******test***********\n%s:INT_CD=0x%x,INT-En=%d,hostState=%d, cmd=%d,present Old=%d ==> New=%d ==xbw[%s]==\n",\
+ __FUNCTION__, pending, host->mmc->re_initialized_flags, host->state, host->cmd->opcode,present_old, present, host->dma_name);
if (pending & SDMMC_INT_CMD_DONE) {
xbwprintk(6, "%s..%d.. CMD%d INT_CMD_DONE INT=0x%x ====xbw[%s]====\n", \
__FUNCTION__, __LINE__, host->cmd->opcode,pending, host->dma_name);
-
- rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); // clear interrupt
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); // clear interrupt
rk29_sdmmc_cmd_interrupt(host, status);
goto Exit_INT;
__FUNCTION__, __LINE__, pending, host->dma_name);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO);
- mmc_signal_sdio_irq(host->mmc);
+ sdio_irq = 1;
goto Exit_INT;
}
rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
if(!(pending & SDMMC_INT_CMD_DONE))
+ {
+ //disable_irq_nosync(host->irq);
tasklet_schedule(&host->tasklet);
+ }
goto Exit_INT;
}
if(pending & SDMMC_INT_DTO)
{
- xbwprintk(7, "%s..%d.. CMD%d INT_DTO INT=0x%x ==xbw[%s]==\n", \
- __FUNCTION__, __LINE__,host->cmd->opcode,pending, host->dma_name);
-
+ 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_DTO);
del_timer(&host->DTO_timer); //delete the timer for INT_DTO
goto Exit_INT;
}
-#if defined(CONFIG_ARCH_RK30)
+#if SDMMC_USE_INT_UNBUSY
if(pending & SDMMC_INT_UNBUSY)
{
- // printk("%d..%s: ==test=== xbw======\n", __LINE__, __FUNCTION__);
- // rk29_sdmmc_regs_printk(host);
+ 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
Exit_INT:
- spin_unlock_irqrestore(&host->lock, iflags);
+ spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags);
+
+ if(1 == sdio_irq)
+ {
+ mmc_signal_sdio_irq(host->mmc);
+ }
+
return IRQ_HANDLED;
}
struct rk29_sdmmc *host;
struct resource *regs;
struct rk29_sdmmc_platform_data *pdata;
- int irq;
+ //int irq;
int ret = 0;
/* must have platform data */
pdata->io_init();
spin_lock_init(&host->lock);
+ spin_lock_init(&host->irqlock);
#ifdef RK29_SDMMC_LIST_QUEUE
INIT_LIST_HEAD(&host->queue);
setup_timer(&host->request_timer,rk29_sdmmc_INT_CMD_DONE_timeout,(unsigned long)host);
setup_timer(&host->DTO_timer,rk29_sdmmc_INT_DTO_timeout,(unsigned long)host);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0)
{
host->errorstep = 0x8B;
ret = -EINVAL;
rk29_sdmmc_hw_init(host);
- ret = request_irq(irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host);
+ ret = request_irq(host->irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host);
if (ret)
{