⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bvd_mmc.c

📁 pxa270下的sd卡驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -