📄 bvd_mmc.c
字号:
nob = request->nob; break; default: nob = 1; } switch (request->rtype) { case RESPONSE_NONE: cmdat |= MMC_CMDAT_RES_NORESP; break; case RESPONSE_R1B: cmdat |= MMC_CMDAT_BUSY; /*FALLTHRU*/ case RESPONSE_R1: case RESPONSE_R4: case RESPONSE_R5: case RESPONSE_R6: cmdat |= MMC_CMDAT_RES_RESP; break; case RESPONSE_R3: cmdat |= MMC_CMDAT_RES_R3; break; case RESPONSE_R2_CID: case RESPONSE_R2_CSD: cmdat |= MMC_CMDAT_RES_R2; break; default: break; } /* Set command index */ if (request->cmd == MMC_CIM_RESET) { MMC_CMD = MMC_GO_IDLE_STATE & MMC_CMD_MASK; } else { MMC_CMD = request->cmd & MMC_CMD_MASK; } /* Set argument */ MMC_ARGL = request->arg & MMC_ARGL_MASK; MMC_ARGH = (request->arg >> 16) & MMC_ARGH_MASK; MMC_BLKLEN = request->block_len & MMC_BLKLEN_MASK; MMC_NOB = nob & MMC_NOB_MASK; MMC_RDTO = ~0 & MMC_RDTO_MASK; MMC_RESTO = ~0 & MMC_RESTO_MASK; MMC_CMDAT = cmdat; /* Send command */ DEBUG(3, ": Send cmd %d cmdat: %x arg: %d resp %d\n", request->cmd, cmdat, request->arg, request->rtype); /* Setup DMA if necessary */ switch (request->cmd) { case MMC_READ_SINGLE_BLOCK: case MMC_READ_MULTIPLE_BLOCK: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_RX_DMA_DONE | MMC_EVENT_CLK_OFF); bvd_mmc_dma_rx_start(&bvd_mmc_data); break; case MMC_WRITE_BLOCK: case MMC_WRITE_MULTIPLE_BLOCK: case MMC_PROGRAM_CID: case MMC_PROGRAM_CSD: case MMC_SEND_WRITE_PROT: case MMC_LOCK_UNLOCK: case MMC_GEN_CMD: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_DATA_DONE | MMC_EVENT_TX_DMA_DONE | MMC_EVENT_PROG_DONE | MMC_EVENT_CLK_OFF); bvd_mmc_dma_tx_start(&bvd_mmc_data); break; case MMC_WRITE_DAT_UNTIL_STOP: case MMC_READ_DAT_UNTIL_STOP: printk(KERN_ERR "Unsupported MMC data transfer command: %d\n", request->cmd); bvd_mmc_wait_for(0); break; default: bvd_mmc_wait_for(MMC_EVENT_RESPONSE | MMC_EVENT_CLK_OFF); break; } bvd_mmc_data.timeout.expires = jiffies + MMC_COMMAND_TIMEOUT; add_timer(&bvd_mmc_data.timeout); barrier(); bvd_mmc_start_clock(); return MMC_NO_ERROR;}/* Start the command execution */void bvd_mmc_send_command(struct mmc_request *request){ int retval; DEBUG(2, "send command [%d %x]\n", request->cmd, request->arg); /* Sanity check */ if (bvd_mmc_data.request != NULL) { printk(KERN_ERR "MMC command sent while another command " " in processing\n"); request->result = MMC_ERROR_DRIVER_FAILURE; mmc_cmd_complete(request); } /* Save current request for the future processing */ bvd_mmc_data.request = request; /* Indicate we have no result yet */ request->result = MMC_NO_RESPONSE; if (request->cmd == MMC_CIM_RESET) { /* On reset, drop MMC clock down */ retval = bvd_mmc_set_clock(MMC_CLOCK_SLOW); if (retval) { bvd_mmc_request_complete(&bvd_mmc_data, retval); return; } } retval = bvd_mmc_exec_command(request); if (retval) { bvd_mmc_request_complete(&bvd_mmc_data, retval); }}/* Fetch response data from the response FIFO */static void bvd_mmc_fetch_response(u8 *buf, int len){ while (len-- > 0) { u16 rdata = MMC_RES; *buf++ = (rdata >> 8) & 0xff; if (len-- > 0) *buf++ = rdata & 0xff; }}/* Obtain response to the command and store it to response buffer */static void bvd_mmc_get_response(struct mmc_request *request){ u8 *buf; if (!request) { DEBUG(1, "Oops - fetch response for zero request ?\n"); return; } buf = request->response; DEBUG(2, "fetch response for request %d, cmd %d\n", request->rtype, request->cmd); request->result = MMC_NO_ERROR; switch (request->rtype) { case RESPONSE_R1: case RESPONSE_R1B: case RESPONSE_R6: case RESPONSE_R3: case RESPONSE_R4: case RESPONSE_R5: bvd_mmc_fetch_response(buf, 5); DEBUG(3, "request %d, response [%02x %02x %02x %02x %02x]\n", request->rtype, buf[0], buf[1], buf[2], buf[3], buf[4]); break; case RESPONSE_R2_CID: case RESPONSE_R2_CSD: bvd_mmc_fetch_response(buf, 17); DEBUG(3, "request %d, response [", request->rtype);#if CONFIG_MMC_DEBUG_VERBOSE > 2 if (g_mmc_debug >= 3) { int n; for (n = 0; n < 17; n++) printk("%02x ", buf[n]); printk("]\n"); }#endif break; case RESPONSE_NONE: bvd_mmc_fetch_response(buf, 0); DEBUG(3, "No response\n"); break; default: bvd_mmc_fetch_response(buf, 0); DEBUG(3, "unhandled response type for request %d\n", request->rtype); break; }}/* Card service IRQ handler */static void bvd_mmc_int(int irq, void *dev, struct pt_regs *regs){ int status, irqtype; bvd_mmc_data_t *mmc = (bvd_mmc_data_t *)dev; status = MMC_STAT; irqtype = MMC_I_REG; DEBUG(3, "MMC service IRQ [MMC_STAT %x, MMC_I_REG %x, MMC_I_MASK %x], CD %p, request %p\n", status, irqtype, MMC_I_MASK, mmc, mmc->request); /* Checking for data or response timeout */ if ((status & (MMC_STAT_TIME_OUT_READ | MMC_STAT_TIME_OUT_RES)) || (irqtype & MMC_I_TINT)) { DEBUG(1, "MMC/SD timeout, MMC_STAT 0x%x\n", status); bvd_mmc_request_complete(mmc, MMC_ERROR_TIMEOUT); return; } /* Checking for CRC error */ if ((status & (MMC_STAT_CRC_RD_ERR | MMC_STAT_CRC_WR_ERR | MMC_STAT_RES_CRC_ERR)) || (irqtype & (MMC_I_RES_ERR | MMC_I_DAT_ERR))) { DEBUG(1, "MMC/CD CRC error, MMC_STAT 0x%x\n", status); switch(mmc->request->cmd) { case MMC_ALL_SEND_CID: case MMC_SEND_CSD: case MMC_SEND_CID: /* workaround for sighting #55580 */ /* ignore CRC error for these commands */ break; case MMC_SEND_STATUS: /* workaround for sighting #59136 */ if ( (MMC_CLKRT & 0x7) == MMC_CLKRT_FREQ_19_5MHZ) { struct mmc_request *req = mmc->request; bvd_mmc_set_clock(9750000); del_timer(&mmc->timeout); bvd_mmc_wait_for(0); mmc->request = NULL; bvd_mmc_send_command(req); return; } /* else fall-through */ default: bvd_mmc_request_complete(mmc, MMC_ERROR_CRC); return; } } /* If the command and response sequence has completed, get the response */ if ((mmc->event_mask & MMC_EVENT_RESPONSE) && (irqtype & MMC_I_END_CMD_RES)) { bvd_mmc_get_response(mmc->request); bvd_mmc_event(MMC_EVENT_RESPONSE); } /* Handle data transfer done event */ if ((mmc->event_mask & MMC_EVENT_DATA_DONE) && (irqtype & MMC_I_DATA_TRAN_DONE)) { bvd_mmc_event(MMC_EVENT_DATA_DONE); } /* Handle programming done event */ if ((mmc->event_mask & MMC_EVENT_PROG_DONE) && (irqtype & MMC_I_PRG_DONE)) { bvd_mmc_event(MMC_EVENT_PROG_DONE); } /* Handle clock off event */ if ((mmc->event_mask == MMC_EVENT_CLK_OFF) && (MMC_I_REG & MMC_I_CLK_IS_OFF)) { bvd_mmc_event(MMC_EVENT_CLK_OFF); }}/* Timeout handler */static void bvd_mmc_timeout(unsigned long data){ struct bvd_mmc_data *mmc = (struct bvd_mmc_data *)data; printk(KERN_ERR "MMC timeout: waiting events 0x%02x\n", mmc->event_mask); bvd_mmc_request_complete(mmc, MMC_ERROR_TIMEOUT);}#ifdef CONFIG_PM/* * Standard PM functions, if CONFIG_PM is used *//* Suspend the MMC slot */static int bvd_mmc_suspend(void){ DEBUG(1, "not implemented\n"); return 0;}/* Resume the MMC slot */static void bvd_mmc_resume(void){ DEBUG(1, "not implemented\n");}static int bvd_mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ switch(req) { case PM_SUSPEND: mmc_eject(0); bvd_mmc_suspend(); break; case PM_RESUME: mmc_insert(0); bvd_mmc_resume(); 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 */int bvd_mmc_slot_init(void){ int retval; int channel; /* Request basic card servicing IRQ */ retval = request_irq(IRQ_MMC, bvd_mmc_int, SA_INTERRUPT | SA_SAMPLE_RANDOM, "MMC/SD", &bvd_mmc_data); if (retval) { printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); return retval; } /* Request MMC Rx DMA channel */ channel = pxa_request_dma("MMC Rx", DMA_PRIO_MEDIUM, bvd_mmc_dma_rx_callback, &bvd_mmc_data); if (channel < 0) { printk(KERN_ERR "pxa_request_dma failed for MMC Rx\n"); goto err1; } bvd_mmc_data.dma_rx_ch = channel; /* Request MMC Tx DMA channel */ channel = pxa_request_dma("MMC Tx", DMA_PRIO_MEDIUM, bvd_mmc_dma_tx_callback, &bvd_mmc_data); if (channel < 0) { printk(KERN_ERR "pxa_request_dma failed for MMC Tx\n"); goto err2; } bvd_mmc_data.dma_tx_ch = channel; init_timer(&bvd_mmc_data.timeout); bvd_mmc_data.timeout.function = bvd_mmc_timeout; bvd_mmc_data.timeout.data = (unsigned long)&bvd_mmc_data; #ifdef CONFIG_PM /* Register MMC slot as as power-managed device */ pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, bvd_mmc_pm_callback);#endif DEBUG(2, "MMC initialized with code %d\n", retval); return retval;err2: pxa_free_dma(bvd_mmc_data.dma_rx_ch);err1: free_irq(IRQ_MMC, &bvd_mmc_data); return -1;}/* Shut down the slot and relax software about MMC slot */void bvd_mmc_slot_cleanup(void){ long flags; DEBUG(2, "Bye, MMC\n"); local_irq_save(flags); /* Shut down the slot */ bvd_mmc_slot_down(); /* Free DMA channels */ pxa_free_dma(bvd_mmc_data.dma_rx_ch); pxa_free_dma(bvd_mmc_data.dma_tx_ch); /* Free both IRQs */ free_irq(IRQ_MMC, &bvd_mmc_data); local_irq_restore(flags);}MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -