📄 jz_mmc.c
字号:
break; default: break; } /* Set command index */ if (request->cmd == MMC_CIM_RESET) { REG_MSC_CMD = MMC_GO_IDLE_STATE; } else { REG_MSC_CMD = request->cmd; } /* Set argument */ REG_MSC_ARG = request->arg; if (request->cmd == SEND_SCR) { /* get SCR from DataFIFO */ REG_MSC_BLKLEN = 8; REG_MSC_NOB = 1; } else { REG_MSC_BLKLEN = request->block_len; REG_MSC_NOB = request->nob; } /* Set command */ REG_MSC_CMDAT = cmdat; DEBUG(1, ": Send cmd %d cmdat: %x arg: %d resp %d\n", request->cmd, cmdat, request->arg, request->rtype); /* Send command */ jz_mmc_start_clock(); /* Wait for command completion */ while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) ; if (timeout == 0) { jz_mmc_request_complete(mmc, MMC_ERROR_TIMEOUT); return MMC_ERROR_TIMEOUT; } REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */ /* Check for status */ retval = jz_mmc_check_status(mmc->request); if (retval) { jz_mmc_request_complete(mmc, retval); return retval; } /* Complete command with no response */ if (request->rtype == RESPONSE_NONE) { jz_mmc_request_complete(mmc, MMC_NO_ERROR); return MMC_NO_ERROR; } /* get response */ jz_mmc_get_response(mmc->request); /* Setup DMA if necessary */ if (mmc->events & MMC_EVENT_RX_DMA_DONE) { jz_mmc_dma_rx_start(mmc); } if (mmc->events & MMC_EVENT_TX_DMA_DONE) { jz_mmc_dma_tx_start(mmc); } /* Unmask some interrupts */ if (mmc->events & MMC_EVENT_DATA_DONE) { REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE; } if (mmc->events & MMC_EVENT_PROG_DONE) { REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE; } /* If no events, complete this command */ if (mmc->events == 0) { jz_mmc_request_complete(mmc, MMC_NO_ERROR); } return MMC_NO_ERROR;}/* Start the command execution */void jz_mmc_send_command(struct mmc_request *request){ int retval; DEBUG(2, "send command [%d %x]\n", request->cmd, request->arg); /* Save current request for the future processing */ jz_mmc_data.request = request; /* Indicate we have no result yet */ request->result = MMC_NO_RESPONSE; if (request->cmd == MMC_CIM_RESET) { /* On reset, 1-bit bus width */ jz_mmc_data.use_4bit = 0; /* Reset MMC/SD controller */ __msc_reset(); /* On reset, drop MMC clock down */ jz_mmc_set_clock(MMC_CLOCK_SLOW); /* On reset, stop MMC clock */ jz_mmc_stop_clock(); } if (request->cmd == SD_SEND_OP_COND) { DEBUG(3, "Have an SD card\n"); jz_mmc_data.sd = 1; } if (request->cmd == MMC_SEND_OP_COND) { DEBUG(3, "Have an MMC card\n"); jz_mmc_data.sd = 0; /* always use 1bit for MMC */ jz_mmc_data.use_4bit = 0; } if (request->cmd == SET_BUS_WIDTH) { if (request->arg == 0x2) { DEBUG(2, "Use 4-bit bus width\n"); jz_mmc_data.use_4bit = 1; } else { DEBUG(2, "Use 1-bit bus width\n"); jz_mmc_data.use_4bit = 0; } } retval = jz_mmc_exec_command(request); if (retval) { jz_mmc_request_complete(&jz_mmc_data, retval); }}/* Card service IRQ handler */static void jz_mmc_int(int irq, void *dev, struct pt_regs *regs){ jz_mmc_data_t *mmc = (jz_mmc_data_t *)dev; struct mmc_request *request = mmc->request; u16 irqtype, status; int retval; irqtype = REG_MSC_IREG; status = REG_MSC_STAT; DEBUG(3, "MMC service IRQ [MMC_STAT %x, MMC_I_REG %x, MMC_I_MASK %x CMD=%d]\n", status, irqtype, REG_MSC_IMASK, request->cmd); /* Check status */ retval = jz_mmc_check_status(request); if (retval) { REG_MSC_IREG = irqtype; /* clear status */ jz_mmc_request_complete(mmc, retval); return; } /* Handle data transfer done event */ if (irqtype & MSC_IREG_DATA_TRAN_DONE) { REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ mmc->events &= ~MMC_EVENT_DATA_DONE; /* SD card returns SCR register as data. MMC core expect it in the response buffer, after normal response. */ if (request->cmd == SEND_SCR) { u8 *buf; u32 i, data; buf = request->response; /* Read SCR */ for (i = 0; i < 2; i++) { data = REG_MSC_RXFIFO; DEBUG(3, ": SCR: %x\n", data); *(buf + (i * 4) + 8) = (data >> 24) & 0xff; *(buf + (i * 4) + 7) = (data >> 16) & 0xff; *(buf + (i * 4) + 6) = (data >> 8) & 0xff; *(buf + (i * 4) + 5) = data & 0xff; } } if (mmc->events == 0) { jz_mmc_request_complete(mmc, MMC_NO_ERROR); return; } } /* Handle programming done event */ if (irqtype & MSC_IREG_PRG_DONE) { REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ mmc->events &= ~MMC_EVENT_PROG_DONE; if (mmc->events == 0) { jz_mmc_request_complete(mmc, MMC_NO_ERROR); return; } }}/* Returns true if MMC slot is empty */static int jz_mmc_slot_is_empty(int slot){ int empty; DEBUG(3, "detect slot\n"); empty = (__msc_card_detected(slot) == 0) ? 1: 0; if (empty) { /* wait for card insertion */ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); } else { /* wait for card removal */ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); } return empty;}/* Return true if MMC slot is write-protected */static int jz_mmc_slot_is_wp(int slot){ int wp; __gpio_as_input(MSC_WP_PIN); wp = __gpio_get_pin(MSC_WP_PIN); return wp;}static void jz_mmc_detect_int(int irq, void *dev, struct pt_regs *regs){ DEBUG(2, "card detect IRQ\n"); if (jz_mmc_slot_is_empty(0)) { DEBUG(3, "no card in slot\n"); mmc_eject(0); /* wait for card insertion */ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); } else { DEBUG(3, "found the card in slot\n"); mmc_insert(0); /* wait for card removal */ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); }}#ifdef CONFIG_PM/* * Standard PM functions, if CONFIG_PM is used *//* Suspend the MMC slot */static int jz_mmc_suspend(void){ DEBUG(1, "suspend mmc slot\n"); jz_mmc_slot_down(); return 0;}/* Resume the MMC slot */static void jz_mmc_resume(void){ DEBUG(1, "resume mmc slot\n"); jz_mmc_slot_up(); jz_mmc_set_clock(jz_mmc_data.clock);}static int jz_mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ switch(req) { case PM_SUSPEND: mmc_eject(0); jz_mmc_suspend(); break; case PM_RESUME: jz_mmc_resume(); if (jz_mmc_slot_is_empty(0)) { mmc_eject(0); } else { mmc_insert(0); } break; default: printk(KERN_ERR "MMC/SD: invalid PM request %d\n", req); break; } return 0;}#endif /* CONFIG_PM *//* Initialize the slot and prepare software layer to operate with it */static int jz_mmc_slot_init(void){ int retval; int channel; /* Startup MMC/SD slot */ jz_mmc_slot_up(); /* Request basic card servicing IRQ */ retval = request_irq(IRQ_MSC, jz_mmc_int, SA_INTERRUPT, "MMC/SD", &jz_mmc_data); if (retval) { printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); return retval; } /* Request card detect interrupt */ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_int, SA_INTERRUPT, "MMC card detect", &jz_mmc_data); if (retval) { printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n"); goto err1; } /* Request MMC Rx DMA channel */ channel = jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback, SA_INTERRUPT, &jz_mmc_data); if (channel < 0) { printk(KERN_ERR "jz_request_dma failed for MMC Rx\n"); goto err2; } jz_mmc_data.dma_rx_ch = channel; /* Request MMC Tx DMA channel */ channel = jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback, SA_INTERRUPT, &jz_mmc_data); if (channel < 0) { printk(KERN_ERR "jz_request_dma failed for MMC Tx\n"); goto err3; } jz_mmc_data.dma_tx_ch = channel; DEBUG(2, "dma_rx_ch=%d dma_tx_ch=%d\n", jz_mmc_data.dma_rx_ch, jz_mmc_data.dma_tx_ch); /* Use 1-bit by default */ jz_mmc_data.use_4bit = 0;#ifdef CONFIG_PM /* Register MMC slot as as power-managed device */ pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, jz_mmc_pm_callback);#endif DEBUG(2, "MMC initialized with code %d\n", retval); return retval;err3: jz_free_dma(jz_mmc_data.dma_rx_ch);err2: free_irq(MSC_HOTPLUG_IRQ, &jz_mmc_data);err1: free_irq(IRQ_MSC, &jz_mmc_data); return -1;}/* Shut down the slot and relax software about MMC slot */static void jz_mmc_slot_cleanup(void){ long flags; DEBUG(2, "Bye, MMC\n"); local_irq_save(flags); /* Shut down the slot */ jz_mmc_slot_down(); /* Free DMA channels */ jz_free_dma(jz_mmc_data.dma_rx_ch); jz_free_dma(jz_mmc_data.dma_tx_ch); /* Free both IRQs */ free_irq(MSC_HOTPLUG_IRQ, &jz_mmc_data); free_irq(IRQ_MSC, &jz_mmc_data); local_irq_restore(flags);}/***********************************************************/static struct mmc_slot_driver jz_dops = { owner: THIS_MODULE, name: "JZ MMC/SD", ocr: 0x00ff8000, flags: MMC_SDFLAG_MMC_MODE | MMC_SDFLAG_SD_MODE, init: jz_mmc_slot_init, cleanup: jz_mmc_slot_cleanup, is_empty: jz_mmc_slot_is_empty, is_wp: jz_mmc_slot_is_wp, send_cmd: jz_mmc_send_command, set_clock: jz_mmc_set_clock};int __initjz_mmc_init(void){ int retval; retval = mmc_register_slot_driver(&jz_dops, 1); if (retval < 0) printk(KERN_INFO "MMC: unable to register slot\n"); printk("JZ MMC/SD driver registered\n"); return retval;}void __exitjz_mmc_cleanup(void){ DEBUG(1,"\n"); mmc_unregister_slot_driver(&jz_dops);}module_init(jz_mmc_init);module_exit(jz_mmc_cleanup);MODULE_DESCRIPTION("JZ MMC");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -