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

📄 bvd_mmc.c

📁 spi driver for sd /mmc card
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* 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_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_LOCK_UNLOCK:		bvd_mmc_wait_for(MMC_EVENT_RESPONSE |				 MMC_EVENT_DATA_DONE |				 MMC_EVENT_PROG_DONE |				 MMC_EVENT_CLK_OFF);		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;	case SEND_SCR:		bvd_mmc_wait_for(MMC_EVENT_RESPONSE | 				 MMC_EVENT_DATA_DONE |				 MMC_EVENT_CLK_OFF);		break;	case MMC_STOP_TRANSMISSION:		bvd_mmc_wait_for(MMC_EVENT_RESPONSE |		                 MMC_EVENT_DATA_DONE |		                 MMC_EVENT_PROG_DONE |		                 MMC_EVENT_CLK_OFF);		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);	}        /* CRC error check. add by w20598 */	if (mmc_crc_error)	{	    /* prevent continuous CRC error interrupt after an CRC error happens */	    /* this will make for IRQ23(Memory to Memeory DMA) diable */	    disable_irq(IRQ_MMC); 	    mmc_crc_error = 0;            bvd_mmc_request_complete(&bvd_mmc_data, MMC_ERROR_CRC);	}		/* 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, 1-bit bus width */		bvd_mmc_data.use_4bit = 0;		/* 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;		}	}	if (request->cmd == SD_SEND_OP_COND) {		DEBUG(3, "Have an SD card\n");		bvd_mmc_data.sd = 1;	}	if (request->cmd == MMC_SEND_OP_COND) {		DEBUG(3, "Have an MMC card\n");		bvd_mmc_data.sd = 0;		/* always use 1bit for MMC */		bvd_mmc_data.use_4bit = 0;	}	if (request->cmd == SET_BUS_WIDTH) {		if (request->arg == 0x2) {			DEBUG(2, "Use 4-bit bus width\n");			bvd_mmc_data.use_4bit = 1;		}		else {			DEBUG(2, "Use 1-bit bus width\n");			bvd_mmc_data.use_4bit = 0;		}	}	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;	}}/* SD card returns SCR register as data. MMC core expect it in the   response buffer, after normal response. */static void bvd_mmc_get_extra_response(struct mmc_request *request){	u8 *buf = request->response;	if (request->cmd == SEND_SCR) {		int i;		DEBUG(3, "extra response: [");		for (i = 0; i < 8; i+=4) 			*((u32*)(buf + i + 5)) = MMC_RXFIFO;#if CONFIG_MMC_DEBUG_VERBOSE > 2		for (i = 0; i < 8; i++) {			if (g_mmc_debug >= 3)				printk(" %02x", buf[i + 5]);		}		printk(" ]\n");#endif	}}/* Program I/O mode data transfer */static void bvd_mmc_tx(struct mmc_request *request){	int i, count;		DEBUG(2, "\n");	if (!request->cnt) return;	count = (request->cnt < 32) ? request->cnt : 32;	for (i=0; i < count; i+=4)		MMC_TXFIFO = *((u32*)(request->buffer+i));	if (count < 32) 		MMC_PRTBUF = 0x1;	request->buffer += count;	request->cnt -= count;}/* 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);		if (!mmc_crc_error)		{		switch (mmc->request->cmd) {			/* FIXME: workaround for sighting #55580 */		case MMC_ALL_SEND_CID:		case MMC_SEND_CSD:		case MMC_SEND_CID:			/* ignore CRC error for these commands */			break;			/* FIXME: workaround for sighting #59136 */		case MMC_SEND_STATUS:			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;			}                  			/* FIXME: multi-block CRC issue */		case MMC_READ_SINGLE_BLOCK:		case MMC_READ_MULTIPLE_BLOCK:		    mmc_crc_error = 1; 		    bvd_mmc_wait_for(MMC_EVENT_RX_DMA_DONE);		    return;		case MMC_WRITE_BLOCK:		case MMC_WRITE_MULTIPLE_BLOCK:		    mmc_crc_error = 1;                    bvd_mmc_wait_for(MMC_EVENT_TX_DMA_DONE);                    return;			/* else fall-through */		default:			bvd_mmc_request_complete(mmc, MMC_ERROR_CRC);			return;		}		} /* if (! mmc_crc_error) */	}	/* 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);	}	/* Transfer data in program I/O mode */	if ((mmc->event_mask & MMC_EVENT_DATA_DONE) &&	    (irqtype & MMC_I_TXFIFO_WR_REQ)) {		bvd_mmc_tx(mmc->request);	}	/* Handle data transfer done event */		if ((mmc->event_mask & MMC_EVENT_DATA_DONE) && 	    (irqtype & MMC_I_DATA_TRAN_DONE)) {		bvd_mmc_get_extra_response(mmc->request);		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);	if (!mmc_crc_error)            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, "suspend mmc slot\n");	/*set GPIO output high to save power*/	CKEN &= ~CKEN12_MMC;	set_GPIO(GPIO_MMC_CLK);	set_GPIO_mode(GPIO_MMC_CLK | GPIO_OUT);	set_GPIO(GPIO_MMC_CMD);	set_GPIO_mode(GPIO_MMC_CMD | GPIO_OUT);	set_GPIO(GPIO_MMC_DATA0);	set_GPIO_mode(GPIO_MMC_DATA0 | GPIO_OUT);	set_GPIO(GPIO_MMC_DATA1);	set_GPIO_mode(GPIO_MMC_DATA1 | GPIO_OUT);	set_GPIO(GPIO_MMC_DATA2);	set_GPIO_mode(GPIO_MMC_DATA2 | GPIO_OUT);#ifdef CONFIG_ARCH_EZXBASE	set_GPIO(GPIO_MMC_DATA3);		set_GPIO_mode(GPIO_MMC_DATA3 | GPIO_IN);#endif		return 0;}/* Resume the MMC slot */static void bvd_mmc_resume(void){	DEBUG(1, "resume mmc slot\n");	#ifdef CONFIG_ARCH_EZXBASE		#ifndef CONFIG_ARCH_EZX_HAINAN    if( GPLR(GPIO_MMC_DETECT) & GPIO_bit(GPIO_MMC_DETECT) )#else    if(ezx_mmc_get_slot_state())#endif#else	if( GPLR(GPIO_MMC_DATA3) & GPIO_bit(GPIO_MMC_DATA3) )#endif		{		CKEN |= CKEN12_MMC;		set_GPIO_mode(GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT);		set_GPIO_mode(GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);		set_GPIO_mode(GPIO_MMC_DATA0  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);#ifdef CONFIG_ARCH_EZXBASE				set_GPIO_mode(GPIO_MMC_DATA1  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);		set_GPIO_mode(GPIO_MMC_DATA2  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);		set_GPIO_mode(GPIO_MMC_DATA3  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);#endif		}	}static int bvd_mmc_pm_callback(struct pm_dev *pm_dev,			       pm_request_t req, void *data){	switch(req) {	case PM_SUSPEND:		bvd_mmc_suspend();		break;			case PM_RESUME:#ifdef CONFIG_ARCH_EZX_E680		e680_reconfig_gpio();#else 		bvd_mmc_resume();#endif		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;		/* Use 1-bit by default */	bvd_mmc_data.use_4bit = 0;	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 + -