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

📄 mmc_pxa.c

📁 linux下mmc_sd卡的驱动.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;#ifndef PIO	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; #endif	MMC_NOB = 1;	MMC_BLKLEN = transfer->blksz;    	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl );	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )		goto error;    /* transfer the data to the caller supplied buffer */	if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 )		goto error;        	if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )		goto error;	transfer->buf += ret;	transfer->cnt -= ret;	transfer->nob -= 1;    	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )		goto error;    	ret = 0;    error:	return ret;}/* This procedure sequentally writes data blocks to a card at a given address */static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ){	int ret = -EIO;	u16 argh = 0UL, argl = 0UL;       // printk(KERN_EMERG"%s::%s\n\n", __FILE__, __FUNCTION__);    	/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default * for the current card */  	if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) {		argh = transfer->blksz >> 16;		argl = transfer->blksz;		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )			goto error;    		MMC_CMD = CMD(16); /* SET_BLOCK_LEN */		MMC_ARGH = argh;		MMC_ARGL = argl;		MMC_CMDAT = MMC_CMDAT_R1;        		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )			goto error;	}    	argh = transfer->addr >> 16;	argl = transfer->addr;/* 1. stop bus clock */	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )		goto error;/* 2. setup controller registers to start multiple block transfer */	MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */	MMC_ARGH = argh;	MMC_ARGL = argl;	MMC_NOB = transfer->nob;	MMC_BLKLEN = transfer->blksz;	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;#ifndef PIO	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; #endif/* 3. start clock */	if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) )		goto error;    /* 4. wait for cmd to complete */	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl );	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) 		goto error;/* 6. transfer the data to the caller supplied buffer */	while ( transfer->cnt > 0 ) {		if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type,				transfer->buf, transfer->cnt )) < 0 )			goto error;        		if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )			goto error;		transfer->buf += ret;		transfer->cnt -= ret;	}    	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )		goto error;    	ret = 0;    error:	return ret;}static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs ){	mmc_controller_t ctrlr = (mmc_controller_t)dev_id;	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;        static int  irq_n=1;#ifdef PIO	register int i, cnt, j;	register char *buf;        unsigned long * posi;        char remain=0;        unsigned long value;#endif   	hostdata->mmc_i_reg = MMC_I_REG;	hostdata->mmc_stat = MMC_STAT;	hostdata->mmc_cmdat = MMC_CMDAT;        hostdata->mmc_cmd = MMC_CMD;          //  printk(KERN_EMERG"NO. %d MMC INTERRUPT OCCOUR \n", irq_n);      /*  printk(KERN_EMERG"%s::%s::MMC_I_MASK=0x%08x\n", __FILE__,__FUNCTION__, MMC_I_MASK);        printk(KERN_EMERG"%s::%s::MMC_I_REG=0x%08x\n", __FILE__,__FUNCTION__,  MMC_I_REG );        printk(KERN_EMERG"%s::%s::MMC_STAT=0x%08x\n", __FILE__, __FUNCTION__, MMC_STAT);        printk(KERN_EMERG"%s::%s::MMC_CMDAT=0x%08x\n", __FILE__, __FUNCTION__, MMC_CMDAT);        printk(KERN_EMERG"%s::%s::MMC_CMD=0x%08x\n", __FILE__, __FUNCTION__, MMC_CMD);       */      //     printk(KERN_EMERG"%s::%s::hostdata->state is 0x%08x\n", __FILE__, __FUNCTION__, hostdata->state);              irq_n++;#if CONFIG_MMC_DEBUG_IRQ 	if ( --hostdata->irqcnt <= 0 ) {		//printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" );		goto complete;	}#endif	switch ( hostdata->state ) {	case PXA_MMC_FSM_IDLE:	case PXA_MMC_FSM_CLK_OFF:	case PXA_MMC_FSM_END_IO:	case PXA_MMC_FSM_END_BUFFER:	case PXA_MMC_FSM_END_CMD:		goto complete;#ifdef PIO          	case PXA_MMC_FSM_BUFFER_IN_TRANSIT:            // printk(KERN_EMERG"PXA_MMC_FSM_BUFFER_IN_TRANSIT\n");        	if ( hostdata->mmc_stat & MMC_STAT_ERRORS )         		goto complete;        		buf = hostdata->iobuf.buf.pos;        	cnt = (hostdata->iobuf.buf.cnt < 32) ? 			hostdata->iobuf.buf.cnt : 32;                		if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) { //printk(KERN_EMERG"EXECUTE THE WRITE OPERATION \n");			/*if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) )				break; */                        posi = (unsigned long *) buf;                                                remain = cnt % 4;                        cnt = cnt / 4;                        if (remain) cnt++;                			for ( i = 0; i < cnt; i++ )                              {                                  value  = *posi++;                                  MMC_TXFIFO = value;				//MMC_TXFIFO = *buf++;                             }			if ( remain )		        	MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL; 		} else { /* i.e. MMC_CMDAT_READ */			/*if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) )				break;*/                                // unsigned long  value;                                                                        posi = (unsigned long *) buf;                        remain = cnt % 4;                        cnt = cnt / 4;                          			for( i = 0; i < cnt; i++ )                           {                                 value = MMC_RXFIFO;                                *posi++ = value;                                           			       //*buf = MMC_RXFIFO ;                              // printk("MMC_STAT is 0x%08x, MMC_I_REG is 0x%08x, buf[%d] is 0x%08x\n",MMC_STAT ,MMC_I_REG, i , value);                                //buf++;                                                                                    }                             if (remain)                                 {  value = MMC_RXFIFO;                                   buf = (char *)posi;                                   for(j=0; j<remain; j++ )                                       { *buf++ = (value & 0xff);                                          value = value >>8;                                        }                                                                 }                  		}        		hostdata->iobuf.buf.pos =  (char *)posi;		hostdata->iobuf.buf.cnt -= (i*4 + remain);               // printk("hostdata->iobuf.buf.cnt is %d\n", hostdata->iobuf.buf.cnt);		if ( hostdata->iobuf.buf.cnt <= 0 ) {			pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );                        MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n");			goto complete;		}  		break; #endif /* PIO */	default:		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n", 				hostdata->state );		goto complete;	}   	return;	complete:   	MMC_I_MASK = MMC_I_MASK_ALL;	complete( &hostdata->completion );	return;}#ifndef PIOstatic void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs ){	mmc_controller_t ctrlr = (mmc_controller_t)dev_id;	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;	u32 dcsr;	u32 ddadr;	int chan = hostdata->iobuf.buf.chan;		ddadr = DDADR( chan );	dcsr = DCSR( chan );	DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN;		MMC_DEBUG( MMC_DEBUG_LEVEL3, 			"MMC DMA interrupt: chan=%d ddadr=0x%08x "			"dcmd=0x%08x dcsr=0x%08x\n", 			chan, ddadr, DCMD( chan ), dcsr );/* bus error */	if ( dcsr & DCSR_BUSERR ) {		MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n",				chan );		pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR );		goto complete;	}/* data transfer completed */	if ( dcsr & DCSR_ENDINTR ) {		MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" );		pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );		goto complete;	}	return;complete:	complete( &hostdata->completion );	return;}#endifstatic int pxa_mmc_init( mmc_controller_t ctrlr ){	int ret = -ENODEV;	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;#ifndef PIO	register int i;	register pxa_dma_desc *desc;#endif/* hardware initialization *//* I. prepare to transfer data *//* 1. allocate buffer */#ifndef PIO	hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL,				(PXA_MMC_IODATA_SIZE>>5)				* sizeof( pxa_dma_desc ),				&hostdata->iobuf.buf.read_desc_phys_addr, 0 );	if ( !hostdata->iobuf.buf.read_desc ) {		ret = -ENOMEM;		goto error;	}	hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL,				(PXA_MMC_IODATA_SIZE>>5)				* sizeof( pxa_dma_desc ),				&hostdata->iobuf.buf.write_desc_phys_addr, 0 );	if ( !hostdata->iobuf.buf.write_desc ) {		ret = -ENOMEM;		goto error;	}	hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC, 					PXA_MMC_IODATA_SIZE,					&hostdata->iobuf.buf.phys_addr, 0 );#else	hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC );#endif	if ( !hostdata->iobuf.iodata ) {		ret = -ENOMEM;		goto error;	}/* 2. initialize iobuf */	hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX;	hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE;	hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER;#ifndef PIO  /* request DMA channel */	if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW,					pxa_mmc_dma_irq, ctrlr )) < 0 ) {		MMC_ERROR( "failed to request DMA channel\n" );		goto error;	}		DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;	DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;		for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) {		desc = &hostdata->iobuf.buf.read_desc[i];		desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr				+ ((i + 1) * sizeof( pxa_dma_desc ));		desc->dsadr = MMC_RXFIFO_PHYS_ADDR;		desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);		desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR				|DCMD_WIDTH1|DCMD_BURST32|(1<<5);				desc = &hostdata->iobuf.buf.write_desc[i];		desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr				+ ((i + 1) * sizeof( pxa_dma_desc ));		desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);		desc->dtadr = MMC_TXFIFO_PHYS_ADDR;		desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR				|DCMD_WIDTH1|DCMD_BURST32|(1<<5);	}	desc = &hostdata->iobuf.buf.read_desc[i];	desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr +				(i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;	desc->dsadr = MMC_RXFIFO_PHYS_ADDR;	desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);	desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR			|DCMD_WIDTH1|DCMD_BURST32|(1<<5);			desc = &hostdata->iobuf.buf.write_desc[i];	desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr +				(i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;	desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);	desc->dtadr = MMC_TXFIFO_PHYS_ADDR;	desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR			|DCMD_WIDTH1|DCMD_BURST32|(1<<5);#endif/* II. MMC *//*  1) request irq */	if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) {		MMC_ERROR( "failed to request IRQ_MMC\n" );		goto error;	}    /*  2) initialize h/w and ctrlr */	//set_GPIO_mode( GPIO6_MMCCLK_MD );        init_gpio( );	CKEN |= CKEN12_MMC; /* enable MMC unit clock */	ret = 0;	goto out;error:#ifndef PIO/* free DMA resources */	if ( hostdata->iobuf.buf.chan >= 0 ) {		DRCMRRXMMC = 0;		DRCMRTXMMC = 0;		pxa_free_dma( hostdata->iobuf.buf.chan );	}	if ( hostdata->iobuf.iodata )		consistent_free( hostdata->iobuf.iodata, 				 PXA_MMC_IODATA_SIZE,				 hostdata->iobuf.buf.phys_addr );	if ( hostdata->iobuf.buf.read_desc )			consistent_free( hostdata->iobuf.buf.read_desc,				(PXA_MMC_IODATA_SIZE>>5)				* sizeof( pxa_dma_desc ),				hostdata->iobuf.buf.read_desc_phys_addr );	if ( hostdata->iobuf.buf.write_desc )			consistent_free( hostdata->iobuf.buf.write_desc,				(PXA_MMC_IODATA_SIZE>>5)				* sizeof( pxa_dma_desc ),				hostdata->iobuf.buf.write_desc_phys_addr );#else	kfree( hostdata->iobuf.iodata );#endifout:	return ret; }static void pxa_mmc_remove( mmc_controller_t ctrlr ){	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;	/*  1) free buffer(s) */#ifndef PIO	consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE,			 hostdata->iobuf.buf.phys_addr );	consistent_free( hostdata->iobuf.buf.read_desc,	 		 (PXA_MMC_IODATA_SIZE>>5)			 * sizeof( pxa_dma_desc ),			 hostdata->iobuf.buf.read_desc_phys_addr );	consistent_free( hostdata->iobuf.buf.write_desc,			 (PXA_MMC_IODATA_SIZE>>5)			 * sizeof( pxa_dma_desc ),			 hostdata->iobuf.buf.write_desc_phys_addr );/*  2) release DMA channel */	if ( hostdata->iobuf.buf.chan >= 0 ) {		DRCMRRXMMC = 0;		DRCMRTXMMC = 0;		pxa_free_dma( hostdata->iobuf.buf.chan );	}#else	kfree( hostdata->iobuf.iodata );#endif/* II. MMC *//*  1) release irq */	free_irq( IRQ_MMC, ctrlr );	CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */}static int pxa_mmc_probe( mmc_controller_t ctrlr ){	return 1;}#ifdef CONFIG_PMstatic int pxa_mmc_suspend( mmc_controller_t ctrlr ){	int ret = -EBUSY;	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;		MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n", 			PXA_MMC_STATE_LABEL( hostdata->state ) );	if ( hostdata->state == PXA_MMC_FSM_IDLE ) {		/* save registers */		SAVED_MMC_CLKRT = MMC_CLKRT;		SAVED_MMC_RESTO = MMC_RESTO;		SAVED_MMC_SPI = MMC_SPI;		SAVED_DRCMRRXMMC = DRCMRRXMMC;		SAVED_DRCMRTXMMC = DRCMRTXMMC;#if 0 /* FIXME */		/* send CMD0 */		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )			goto error;		MMC_CMD = CMD(0); /* CMD0 with zero argument */		MMC_ARGH = 0UL;		MMC_ARGL = 0UL; 		MMC_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -