?? davinci_mmc.c
字號(hào):
flags); dev_dbg(&mmc_dev, "MMCSD: Data timeout, CMD%d and status is %x\r\n", host->cmd->opcode, status); end_transfer = 1; host->cmd->error |= MMC_ERR_TIMEOUT; } dev_dbg(&mmc_dev, "MMCSD: Data timeout, CMD%d and status is %x\r\n", host->cmd->opcode, status); } if (status & MMCSD_EVENT_ERROR_DATACRC) { /* Data CRC error */ if (host->data) { host->data->error |= MMC_ERR_BADCRC; dev_dbg(&mmc_dev, "MMCSD: Data CRC error, bytes left %d\r\n", host->bytes_left); end_transfer = 1; } else { dev_dbg(&mmc_dev, "MMCSD: Data CRC error\r\n"); } } if (status & MMCSD_EVENT_ERROR_CMDTIMEOUT) { /* Command timeout */ if (host->cmd) { /* Timeouts are normal in case of * MMC_SEND_STATUS */ if (host->cmd->opcode != MMC_ALL_SEND_CID) { dev_dbg(&mmc_dev, "MMCSD: Command timeout, CMD%d and status is %x\r\n", host->cmd->opcode, status); spin_lock_irqsave(&mmc_lock, flags); new_card_state = 0; is_card_initialized = 0; spin_unlock_irqrestore (&mmc_lock, flags); } host->cmd->error |= MMC_ERR_TIMEOUT; end_command = 1; } } if (status & MMCSD_EVENT_ERROR_CMDCRC) { /* Command CRC error */ dev_dbg(&mmc_dev, "Command CRC error\r\n"); if (host->cmd) { host->cmd->error |= MMC_ERR_BADCRC; end_command = 1; } } if (status & MMCSD_EVENT_EOFCMD) { /* End of command phase */ end_command = 1; } if (host->data == NULL) { status = mmcsd_regs->mmc_st0; if (status != 0) { dev_dbg(&mmc_dev, "Status is %x at end of ISR when host->data is NULL", status); status = 0; } } else { status = mmcsd_regs->mmc_st0; } } if (end_command) { mmc_davinci_cmd_done(host, host->cmd); } if (end_transfer) { mmc_davinci_xfer_done(host, host->data); } } else { if (host->cmd_code == 13) { if (status & MMCSD_EVENT_EOFCMD) { spin_lock_irqsave(&mmc_lock, flags); new_card_state = 1; spin_unlock_irqrestore(&mmc_lock, flags); } else { spin_lock_irqsave(&mmc_lock, flags); new_card_state = 0; is_card_initialized = 0; spin_unlock_irqrestore(&mmc_lock, flags); } spin_lock_irqsave(&mmc_lock, flags); is_card_detect_progress = 0; spin_unlock_irqrestore(&mmc_lock, flags); if (is_req_queued_up) { mmc_davinci_request(que_mmc_host, que_mmc_request); spin_lock_irqsave(&mmc_lock, flags); is_req_queued_up = 0; spin_unlock_irqrestore(&mmc_lock, flags); } } if (host->cmd_code == 1) { if (status & MMCSD_EVENT_EOFCMD) { spin_lock_irqsave(&mmc_lock, flags); new_card_state = 1; is_card_initialized = 0; spin_unlock_irqrestore(&mmc_lock, flags); } else { spin_lock_irqsave(&mmc_lock, flags); new_card_state = 0; is_card_initialized = 0; spin_unlock_irqrestore(&mmc_lock, flags); } spin_lock_irqsave(&mmc_lock, flags); is_card_detect_progress = 0; spin_unlock_irqrestore(&mmc_lock, flags); if (is_req_queued_up) { mmc_davinci_request(que_mmc_host, que_mmc_request); spin_lock_irqsave(&mmc_lock, flags); is_req_queued_up = 0; spin_unlock_irqrestore(&mmc_lock, flags); } } if (host->cmd_code == 0) { if (status & MMCSD_EVENT_EOFCMD) { host->is_core_command = 0; host->cmd_code = 1; dev_dbg(&mmc_dev, "MMC-Probing mmc with cmd1\n"); /* Issue cmd1 */ mmcsd_regs->mmc_arghl = 0x80300000; mmcsd_regs->mmc_cmd = 0x00000601; } else { spin_lock_irqsave(&mmc_lock, flags); new_card_state = 0; is_card_initialized = 0; is_card_detect_progress = 0; spin_unlock_irqrestore(&mmc_lock, flags); } } } return IRQ_HANDLED;}static struct mmc_host_ops mmc_davinci_ops = { .request = mmc_davinci_request, .set_ios = mmc_davinci_set_ios,};void mmc_check_card(unsigned long data){ struct mmc_davinci_host *host = (struct mmc_davinci_host *)data; unsigned long flags; if ((!is_card_detect_progress) || (!is_init_progress)) { if (is_card_initialized) { host->is_core_command = 0; host->cmd_code = 13; spin_lock_irqsave(&mmc_lock, flags); is_card_detect_progress = 1; spin_unlock_irqrestore(&mmc_lock, flags); /* Issue cmd13 */ mmcsd_regs->mmc_arghl = 0x10000; mmcsd_regs->mmc_cmd = 0x0000028D; } else { host->is_core_command = 0; host->cmd_code = 0; spin_lock_irqsave(&mmc_lock, flags); is_card_detect_progress = 1; spin_unlock_irqrestore(&mmc_lock, flags); /* Issue cmd0 */ mmcsd_regs->mmc_arghl = 0; mmcsd_regs->mmc_cmd = 0x4000; } mmcsd_regs->mmc_im = (MMCSD_EVENT_EOFCMD | MMCSD_EVENT_ERROR_CMDCRC | MMCSD_EVENT_ERROR_DATACRC | MMCSD_EVENT_ERROR_CMDTIMEOUT | MMCSD_EVENT_ERROR_DATATIMEOUT); }}static void davinci_mmc_check_status(unsigned long data){ unsigned long flags; struct mmc_davinci_host *host = (struct mmc_davinci_host *)data; if (!is_card_busy) { if (host->old_card_state ^ new_card_state) { mmc_detect_change(host->mmc, 0); spin_lock_irqsave(&mmc_lock, flags); host->old_card_state = new_card_state; spin_unlock_irqrestore(&mmc_lock, flags); } else { mmc_check_card(data); } } mod_timer(&host->timer, jiffies + MULTIPILER_TO_HZ * HZ);}static void init_mmcsd_host(void){ /* CMD line portion is diabled and in reset state */ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | 0x1; /* DAT line portion is diabled and in reset state */ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 1); mmcsd_regs->mmc_clk = 0x0; mmcsd_regs->mmc_clk = mmcsd_regs->mmc_clk | (1 << 8); mmcsd_regs->mmc_tor = 0xFFFF; mmcsd_regs->mmc_tod = 0xFFFF; mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(0x1); mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 1);}static int davinci_mmcsd_probe(struct device *dev){ struct mmc_davinci_host *host; struct mmc_host *mmc; int ret; mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), dev); if (!mmc) { ret = -ENOMEM; goto out; } mmcsd_regs = (volatile mmcsd_regs_base *)IO_ADDRESS(MMCSD_REGS_BASE_ADDR); init_mmcsd_host(); mmc->ops = &mmc_davinci_ops; mmc->f_min = 312500; mmc->f_max = 20000000; mmc->ocr_avail = MMC_VDD_32_33; host = mmc_priv(mmc); host->mmc = mmc; /* Important */ host->use_dma = mmcsd_cfg.use_dma; host->irq = MMCINT_INTERRUPT; host->sd_support = 1; ret = request_irq(MMCINT_INTERRUPT, mmc_davinci_irq, 0, DRIVER_NAME, host); if (ret) goto out; dev_set_drvdata(dev, host); mmc_add_host(mmc); init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = davinci_mmc_check_status; host->timer.expires = jiffies + MULTIPILER_TO_HZ * HZ; add_timer(&host->timer); return 0; out: /* TBD: Free other resources too. */ return ret;}static int davinci_mmcsd_remove(struct device *dev){ struct mmc_davinci_host *host = dev_get_drvdata(dev); dev_set_drvdata(dev, NULL); if (host) { mmc_remove_host(host->mmc); free_irq(host->irq, host); } del_timer(&host->timer); davinci_free_dma(DAVINCI_DMA_MMCTXEVT); davinci_free_dma(DAVINCI_DMA_MMCRXEVT); return 0;}#ifdef CONFIG_PMstatic int davinci_mmcsd_suspend(struct device *dev, u32 state, u32 level){ struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; if (mmc && level == SUSPEND_DISABLE) ret = mmc_suspend_host(mmc, state); return ret;}static int davinci_mmcsd_resume(struct device *dev, u32 level){ struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; if (mmc && level == RESUME_ENABLE) ret = mmc_resume_host(mmc); return ret;}#else#define davinci_mmcsd_suspend NULL#define davinci_mmcsd_resume NULL#endifstatic struct device_driver davinci_mmcsd_driver = { .name = DRIVER_NAME, .bus = &platform_bus_type, .probe = davinci_mmcsd_probe, .remove = davinci_mmcsd_remove, .suspend = davinci_mmcsd_suspend, .resume = davinci_mmcsd_resume,};static void mmc_release(struct device *dev){ /* Nothing to release? */}static u64 mmc_dma_mask = 0xffffffff;static struct resource mmc_resources[] = { { .start = IO_ADDRESS(MMCSD_REGS_BASE_ADDR), .end = IO_ADDRESS((MMCSD_REGS_BASE_ADDR) + 0x74), .flags = IORESOURCE_MEM, }, { .start = MMCINT_INTERRUPT, .flags = IORESOURCE_IRQ, },};static struct platform_device mmc_davinci_device = { .name = DRIVER_NAME, .id = 1, .dev = { .release = mmc_release, .dma_mask = &mmc_dma_mask, }, .num_resources = ARRAY_SIZE(&mmc_resources), .resource = mmc_resources,};static int davinci_mmcsd_init(void){ int ret = 0; struct clk *clkp = NULL; clkp = clk_get(NULL, "MMCSDCLK"); if (clkp != NULL) { mmc_clkp = clkp; clk_use(mmc_clkp); clk_enable(mmc_clkp); mmc_input_clk = clk_get_rate(mmc_clkp); ret = platform_device_register(&mmc_davinci_device); if (ret != 0) goto free1; ret = driver_register(&davinci_mmcsd_driver); mmc_davinci_device.dev.driver = &davinci_mmcsd_driver; mmc_dev = mmc_davinci_device.dev; if (ret == 0) return 0; free1: platform_device_unregister(&mmc_davinci_device); } return -ENODEV;}static void __exit davinci_mmcsd_exit(void){ driver_unregister(&davinci_mmcsd_driver); platform_device_unregister(&mmc_davinci_device); clk_disable(mmc_clkp); clk_unuse(mmc_clkp);}module_init(davinci_mmcsd_init);module_exit(davinci_mmcsd_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("MMCSD driver for Davinci MMC controller");
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -