* mount -t debugfs debugfs /data/debugfs;cat /data/debugfs/mmc0/status
* echo 't' >/proc/sysrq-trigger
* echo 19 >/sys/module/wakelock/parameters/debug_mask
+ * vdc volume uevent on
*/
#include <linux/blkdev.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/card.h>
+#include <linux/earlysuspend.h>
#include <mach/board.h>
#include <mach/rk29_iomap.h>
MRQ_REQUEST_START = 0,
MRQ_INT_CMD_DONE, //1
MRQ_INT_CMD_ERR, //2
- MRQ_INT_DATE_DONE, //3
+ MRQ_INT_DATA_DONE, //3
MRQ_INT_DATA_ERR, //4
MRQ_INT_CD, //5
MRQ_INT_SDIO, //6
void __iomem *regs;
struct mmc_host *mmc;
- struct work_struct work;
+ struct delayed_work work;
struct rk29_sdmmc_dma_info dma_info;
struct tasklet_struct tasklet;
struct mmc_request *mrq;
dma_addr_t dma_addr;
int (*get_wifi_cd)(struct device *);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
};
static void rk29_sdmmc_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val)
if(tmo > 0) {
rk29_sdmmc_set_mrq_status(host, MRQ_RESET_CTRL_DONE);
+ host->is_init = 1;
return 0;
}
else {
static void rk29_sdmmc_request_done(struct rk29_sdmmc *host,struct mmc_request *mrq)
{
+ int tmo = RK29_SDMMC_TMO_COUNT;
+
+ spin_unlock(&host->lock);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO);
rk29_sdmmc_write(host->regs, SDMMC_INTMASK,
rk29_sdmmc_read(host->regs, SDMMC_INTMASK) &
~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS));
- if(mrq->stop)
+ if(mrq->stop && !rk29_sdmmc_test_mrq_status(host, MRQ_STOP_START_DONE))
send_stop_cmd(host);
- //clk_disable(host->clk);
+ if(mrq->cmd->opcode == 17 && (host->data_intsts & SDMMC_INT_SBE)){
+ rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_STOP | SDMMC_CMD_START);
+ while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START);
+ }
if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_FULL ){
rk29_sdmmc_read(host->regs, SDMMC_DATA);
rk29_sdmmc_read(host->regs, SDMMC_DATA);
}
if(mrq->data && mrq->data->error)
rk29_sdmmc_reset_fifo(host);
-
- rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0);
host->mrq = NULL;
host->state = STATE_IDLE;
rk29_sdmmc_set_mrq_status(host, MRQ_REQUEST_DONE);
mmc_request_done(host->mmc, mrq);
+
+
+ spin_lock(&host->lock);
}
static int sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg)
if(!host->ios_clock)
return 0;
div = (((host->bus_hz + (host->bus_hz / 5)) / host->ios_clock)) >> 1;
+ if(div == 0)
+ div = 1;
if(host->div == div)
return 0;
}
dev_dbg(host->dev,"start cmd:%d ARGR=0x%08x CMDR=0x%08x\n",
cmd->opcode, cmd->arg, cmdflags);
+
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO);
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,
+ rk29_sdmmc_read(host->regs, SDMMC_INTMASK) |
+ (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS));
ret = rk29_sdmmc_start_command(host, cmd, cmdflags);
if(ret < 0) {
rk29_sdmmc_set_mrq_status(host, MRQ_CMD_START_TMO);
static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
+ int timeout;
struct rk29_sdmmc *host = mmc_priv(mmc);
if(host->mrq)
rk29_sdmmc_show_info(host);
- BUG_ON(host->mrq);
+ WARN_ON(host->mrq);
host->old_mrq_status = host->mrq_status;
host->mrq_status = 0;
host->pending_events = 0;
host->cmd_intsts = 0;
host->data_intsts = 0;
host->mrq = mrq;
- mod_timer(&host->monitor_timer, jiffies + msecs_to_jiffies(5000));
- //clk_enable(host->clk);
- rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 1);
-
- rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO);
- rk29_sdmmc_write(host->regs, SDMMC_INTMASK,
- rk29_sdmmc_read(host->regs, SDMMC_INTMASK) |
- (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS));
+ if(!mrq->data)
+ timeout = 500;
+ else
+ timeout = 500 + mrq->data->timeout_ns/1000000;
+ mod_timer(&host->monitor_timer, jiffies + msecs_to_jiffies(timeout));
if (!rk29_sdmmc_get_cd(mmc)) {
mrq->cmd->error = -ENOMEDIUM;
__releases(&host->lock)
__acquires(&host->lock)
{
- spin_unlock(&host->lock);
if(host->mrq)
rk29_sdmmc_request_done(host, host->mrq);
-
- spin_lock(&host->lock);
}
static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host)
{
rk29_sdmmc_dma_cleanup(host);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH);
- //rk29_sdmmc_write(host->regs, SDMMC_CTRL,
- //(rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE));
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL,
+ (rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE));
}
static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host,
}
if(intsts & SDMMC_INT_DTO) {
- rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATE_DONE);
+ rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATA_DONE);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO);
if (!host->data_intsts)
host->data_intsts = intsts;
}
rk29_sdmmc_request_end(host);
}
- rk29_sdmmc_reset_fifo(host);
+ //rk29_sdmmc_reset_ctrl(host);
spin_unlock(&host->lock);
mmc_detect_change(host->mmc, 0);
}
static void rk29_sdmmc_detect_change_work(struct work_struct *work)
{
int ret;
- struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work);
-
- if(host->enable_sd_warkup && rk29_sdmmc_get_cd(host->mmc) && !host->mmc->card)
+ struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work.work);
+
+ dev_info(host->dev, "sd detect change, card is %s\n",
+ rk29_sdmmc_get_cd(host->mmc)?"inserted":"removed");
+ if(host->enable_sd_warkup && rk29_sdmmc_get_cd(host->mmc))
rk28_send_wakeup_key();
rk29_sdmmc_detect_change(host);
struct rk29_sdmmc *host = dev_id;
disable_irq_nosync(host->gpio_irq);
- dev_info(host->dev, "sd detect change, card is %s\n",
- rk29_sdmmc_get_cd(host->mmc)?"inserted":"removed");
- schedule_work(&host->work);
+ if(rk29_sdmmc_get_cd(host->mmc))
+ schedule_delayed_work(&host->work, msecs_to_jiffies(500));
+ else
+ schedule_delayed_work(&host->work, 0);
return IRQ_HANDLED;
}
struct rk29_sdmmc *host = (struct rk29_sdmmc *)data;
if(!rk29_sdmmc_test_mrq_status(host, MRQ_REQUEST_DONE)){
+ dev_info(host->dev, "no dto interrupt\n");
rk29_sdmmc_show_info(host);
- host->mrq->cmd->error = -ENOMEDIUM;
+ host->mrq->cmd->error = -ETIMEDOUT;
if(host->mrq->data)
- host->mrq->data->error = -ENOMEDIUM;
+ host->mrq->data->error = -ETIMEDOUT;
rk29_sdmmc_request_end(host);
+ //rk29_sdmmc_reset_ctrl(host);
}
}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void rk29_sdmmc_early_suspend(struct early_suspend *h)
+{
+ struct rk29_sdmmc *host = container_of(h,
+ struct rk29_sdmmc,
+ early_suspend);
+
+ dev_dbg(host->dev, "Enter rk29_sdmmc_early_suspend\n");
+}
+
+static void rk29_sdmmc_early_resume(struct early_suspend *h)
+{
+ struct rk29_sdmmc *host = container_of(h,
+ struct rk29_sdmmc,
+ early_suspend);
+
+ dev_dbg(host->dev, "Exit rk29_sdmmc_early_resume\n");
+}
+#endif
+
+
static int rk29_sdmmc_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
host->gpio_det = pdata->detect_irq;
if(!host->is_sdio && host->gpio_det != INVALID_GPIO) {
- INIT_WORK(&host->work, rk29_sdmmc_detect_change_work);
+ INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work);
ret = gpio_request(host->gpio_det, "sd_detect");
if(ret < 0) {
dev_err(&pdev->dev, "gpio_request error\n");
rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS);
rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE);
rk29_sdmmc_write(host->regs, SDMMC_CLKENA,1);
-
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ host->early_suspend.suspend = rk29_sdmmc_early_suspend;
+ host->early_suspend.resume = rk29_sdmmc_early_resume;
+ host->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ register_early_suspend(&host->early_suspend);
+#endif
dev_info(host->dev, "RK29 SDMMC controller at irq %d\n", host->irq);
return 0;
free_irq(host->gpio_irq, host);
dev_info(host->dev, "Enter rk29_sdmmc_suspend\n");
if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){
- ret = mmc_suspend_host(host->mmc, state);
+ ret = mmc_suspend_host(host->mmc,state);
if(!host->enable_sd_warkup)
free_irq(host->gpio_irq, host);
}
clk_enable(host->clk);
rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 1);
if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){
- if(!host->enable_sd_warkup)
+ if(!host->enable_sd_warkup){
ret = request_irq(host->gpio_irq,
rk29_sdmmc_detect_change_isr,
rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING,
"sd_detect",
host);
- if(ret < 0)
- dev_err(host->dev, "gpio request_irq error\n");
- mmc_detect_change(host->mmc, 0);
+ if(ret < 0)
+ dev_err(host->dev, "gpio request_irq error\n");
+ }
+ host->is_init = 1;
ret = mmc_resume_host(host->mmc);
+ mmc_detect_change(host->mmc, 0);
}
#endif
return ret;