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

📄 s3c2440mci.c

📁 嵌入式Linux下SD卡的驱动 驱动主要以三星2410板设计的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/mmc/s3c2410mci.h - Samsung S3C2410 SDI Interface driver * *  Copyright (C) 2004 Thomas Kleffel, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.   2005.07.09 godori from www.aesop-embedded.org(ghcstop@empal.com)            porting sdi interface(DMA mode) to S3C2440A            ==> irq mode?: see s3c2410mci.c.irq_mode_single_block_fault                            & this file's s3c2410sdi_irq()(fsta & dsta control routine)            DMA mode transfer rate(10MBytes file tranfer time is 7 sec with single block mode)            ==> HIGH system load with media player  2005.07.10 godori from www.aesop-embedded.org(ghcstop@empal.com)            porting sdi interface(IRQ mode) to S3C2440A            ==> dma mode?: s3c2410mci.c.dma            IRQ mode transfer rate: slow than DMA mode            ==> Low system load with media player:   */#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/dma-mapping.h>#include <linux/mmc/host.h>#include <linux/mmc/protocol.h>#include <asm/dma.h>#include <asm/dma-mapping.h>#include <asm/arch/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/hardware/amba.h>#include <asm/hardware/clock.h>#include <asm/mach/mmc.h>#include <asm/arch/regs-sdi.h>#include <asm/arch/regs-gpio.h>//#define S3C2410SDI_DMA_BACKBUF#ifdef CONFIG_MMC_DEBUG#define DBG(x...)       printk(KERN_DEBUG x)#else#define DBG(x...)       do { } while (0)#endif#include "s3c2410mci.h"#define DRIVER_NAME "mmci-s3c2410"#define PFX DRIVER_NAME ": "#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)// #define KERN_DEBUG KERN_INFO/* * ISR for SDI Interface IRQ * Communication between driver and ISR works as follows: *   host->mrq 			points to current request *   host->complete_what	tells the ISR when the request is considered done *     COMPLETION_CMDSENT	  when the command was sent *     COMPLETION_RSPFIN          when a response was received *     COMPLETION_XFERFINISH	  when the data transfer is finished *     COMPLETION_XFERFINISH_RSPFIN both of the above. *   host->complete_request	is the completion-object the driver waits for * * 1) Driver sets up host->mrq and host->complete_what * 2) Driver prepares the transfer * 3) Driver enables interrupts * 4) Driver starts transfer * 5) Driver waits for host->complete_rquest * 6) ISR checks for request status (errors and success) * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error * 7) ISR completes host->complete_request * 8) ISR disables interrupts * 9) Driver wakes up and takes care of the request*/static irqreturn_t s3c2410sdi_irq(int irq, void *dev_id, struct pt_regs *regs){	struct s3c2410sdi_host *host;	u32 sdi_csta, sdi_dsta, sdi_dcnt;	u32 sdi_cclear, sdi_dclear;	unsigned long iflags;		#ifdef CONFIG_CPU_S3C2440		u32 sdi_fsta;		int i, txfifocnt, datalen;		u32 sdi_data;	#endif		host = (struct s3c2410sdi_host *)dev_id;	//Check for things not supposed to happen	if(!host) return IRQ_HANDLED;		sdi_csta 	= readl(host->base + S3C2410_SDICMDSTAT);	sdi_dsta 	= readl(host->base + S3C2410_SDIDSTA);	sdi_dcnt 	= readl(host->base + S3C2410_SDIDCNT);	#ifdef CONFIG_CPU_S3C2440		sdi_fsta = readl(host->base + S3C2410_SDIFSTA);	#endif				spin_lock_irqsave( &host->complete_lock, iflags);		if( host->complete_what==COMPLETION_NONE ) {		goto clear_imask;	}		if(!host->mrq) { 		goto clear_imask;	}		sdi_csta 	= readl(host->base + S3C2410_SDICMDSTAT);	sdi_dsta 	= readl(host->base + S3C2410_SDIDSTA);	sdi_dcnt 	= readl(host->base + S3C2410_SDIDCNT);	sdi_cclear	= 0;	sdi_dclear	= 0;			if(sdi_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {		host->mrq->cmd->error = MMC_ERR_TIMEOUT;		goto transfer_closed;	}	if(sdi_csta & S3C2410_SDICMDSTAT_CMDSENT) {		if(host->complete_what == COMPLETION_CMDSENT) {			host->mrq->cmd->error = MMC_ERR_NONE;			goto transfer_closed;		}		sdi_cclear |= S3C2410_SDICMDSTAT_CMDSENT;	}	if(sdi_csta & S3C2410_SDICMDSTAT_CRCFAIL) {		if(host->mrq->cmd->flags & MMC_RSP_CRC) {			host->mrq->cmd->error = MMC_ERR_BADCRC;			goto transfer_closed;		}		sdi_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;	}	if(sdi_csta & S3C2410_SDICMDSTAT_RSPFIN) {		if(host->complete_what == COMPLETION_RSPFIN) {			host->mrq->cmd->error = MMC_ERR_NONE;			goto transfer_closed;		}		if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {			host->mrq->cmd->error = MMC_ERR_NONE;			host->complete_what = COMPLETION_XFERFINISH;		}		sdi_cclear |= S3C2410_SDICMDSTAT_RSPFIN;	}	#ifdef CONFIG_CPU_S3C2440		if( sdi_fsta & S3C2410_SDIFSTA_FF_FAIL ) 		{			host->mrq->cmd->error = MMC_ERR_NONE;			host->mrq->data->error = MMC_ERR_FIFO;			goto transfer_closed;		}		else if(sdi_fsta & S3C2410_SDIFSTA_FF_LASTXFER) 		{			host->mrq->cmd->error = MMC_ERR_NONE;			host->mrq->data->error = MMC_ERR_FIFO;    		sdi_fsta |= S3C2410_SDIFSTA_FIFORESET;    		writel(sdi_fsta, host->base + S3C2410_SDIFSTA);			goto transfer_closed;		}	#else		if(sdi_dsta & S3C2410_SDIDSTA_FIFOFAIL) {			host->mrq->cmd->error = MMC_ERR_NONE;			host->mrq->data->error = MMC_ERR_FIFO;			goto transfer_closed;		}	#endif	if(sdi_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {		host->mrq->cmd->error = MMC_ERR_NONE;		host->mrq->data->error = MMC_ERR_BADCRC;		goto transfer_closed;	}	if(sdi_dsta & S3C2410_SDIDSTA_CRCFAIL) {		host->mrq->cmd->error = MMC_ERR_NONE;		host->mrq->data->error = MMC_ERR_BADCRC;		goto transfer_closed;	}	if(sdi_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {		host->mrq->cmd->error = MMC_ERR_NONE;		host->mrq->data->error = MMC_ERR_TIMEOUT;		goto transfer_closed;	}    if( host->mrq->data )     {    	datalen = host->mrq->data->blocks << host->mrq->data->blksz_bits; 		if( host->mrq->data->flags & MMC_DATA_READ ) 		{		    if( (sdi_fsta&S3C2410_SDIFSTA_RFLAST) == S3C2410_SDIFSTA_RFLAST )        	{				for(i=(sdi_fsta & 0x7f)/4;i>0;i--) 				{					sdi_data = readl(host->base + S3C2410_SDIDATA);					*((u32 *)(host->mrq->data->req->buffer + host->mrq->data->bytes_process)) = sdi_data;					host->mrq->data->bytes_process += 4;				}												if(host->complete_what == COMPLETION_XFERFINISH) {					host->mrq->cmd->error = MMC_ERR_NONE;					host->mrq->data->error = MMC_ERR_NONE;								sdi_fsta = 0;   	   				sdi_fsta |= S3C2410_SDIFSTA_RFLAST;					writel(sdi_fsta, host->base + S3C2410_SDIFSTA);								sdi_dsta   = 0;					sdi_dsta |= S3C2410_SDIDSTA_XFERFINISH;					writel(sdi_dsta, host->base + S3C2410_SDIDSTA);								goto transfer_closed;				}                	}        	else if( (sdi_fsta&S3C2410_SDIFSTA_RFFULL) == S3C2410_SDIFSTA_RFFULL )        	{        		for(i=0;i<8;i++)        		{					sdi_data = readl(host->base + S3C2410_SDIDATA);					*((u32 *)(host->mrq->data->req->buffer + host->mrq->data->bytes_process)) = sdi_data;					host->mrq->data->bytes_process += 4;				}        	}        }        else         {		    if (sdi_fsta & S3C2410_SDIFSTA_TXEMPTY) 		    {            	txfifocnt = 16;             	            	while (txfifocnt && host->mrq->data->bytes_process < datalen)            	{                	sdi_data = *((unsigned int *)(host->mrq->data->req->buffer + host->mrq->data->bytes_process));                	writel(sdi_data, host->base + S3C2410_SDIDATA);                	host->mrq->data->bytes_process += 4;                	txfifocnt--;            	}        	}        }    }		if(sdi_dsta & S3C2410_SDIDSTA_XFERFINISH) {		if(host->complete_what == COMPLETION_XFERFINISH) {			host->mrq->cmd->error = MMC_ERR_NONE;			host->mrq->data->error = MMC_ERR_NONE;						sdi_fsta = 0;   			sdi_fsta |= S3C2410_SDIFSTA_RFLAST;	    	writel(sdi_fsta, host->base + S3C2410_SDIFSTA);	    		    	sdi_dsta   = 0;	    	sdi_dsta |= S3C2410_SDIDSTA_XFERFINISH;	    	writel(sdi_dsta, host->base + S3C2410_SDIDSTA);						goto transfer_closed;		}		if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {			host->mrq->data->error = MMC_ERR_NONE;			host->complete_what = COMPLETION_RSPFIN;		}		sdi_dclear |= S3C2410_SDIDSTA_XFERFINISH;	}	writel(sdi_cclear, host->base + S3C2410_SDICMDSTAT);	writel(sdi_dclear, host->base + S3C2410_SDIDSTA);	spin_unlock_irqrestore( &host->complete_lock, iflags);	return IRQ_HANDLED;transfer_closed:	host->complete_what = COMPLETION_NONE;	complete(&host->complete_request);	writel(0, host->base + S3C2410_SDIIMSK);	spin_unlock_irqrestore( &host->complete_lock, iflags);	return IRQ_HANDLED;	clear_imask:	writel(0, host->base + S3C2410_SDIIMSK);	spin_unlock_irqrestore( &host->complete_lock, iflags);	return IRQ_HANDLED;}/* * ISR for the CardDetect Pin*/static irqreturn_t s3c2410sdi_irq_cd(int irq, void *dev_id, struct pt_regs *regs){	struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)dev_id;	mmc_detect_change(host->mmc);//printk("ghc: interrupt occur ***********************\n");	return IRQ_HANDLED;}static void s3c2410sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) { 	struct s3c2410sdi_host *host = mmc_priv(mmc);	u32 sdi_carg, sdi_ccon, sdi_timer;	u32 sdi_bsize, sdi_dcon, sdi_imsk, sdi_fsta;	sdi_ccon = mrq->cmd->opcode & S3C2410_SDICMDCON_INDEX;	sdi_ccon|= S3C2410_SDICMDCON_SENDERHOST;	sdi_ccon|= S3C2410_SDICMDCON_CMDSTART;	sdi_carg = mrq->cmd->arg;	#ifdef CONFIG_ARCH_SMDK2410	    //FIXME: Timer value ?!	    sdi_timer= 0xF000;	#elif defined(CONFIG_CPU_S3C2440)	    sdi_timer= 0x7fffff;	#endif		sdi_bsize= 0;	sdi_dcon = 0;	sdi_imsk = 0;	sdi_imsk |= S3C2410_SDIIMSK_RESPONSEND;	sdi_imsk |= S3C2410_SDIIMSK_CRCSTATUS;	host->complete_what = COMPLETION_CMDSENT;	if (mrq->cmd->flags & MMC_RSP_MASK) {		host->complete_what = COMPLETION_RSPFIN;		sdi_ccon |= S3C2410_SDICMDCON_WAITRSP;		sdi_imsk |= S3C2410_SDIIMSK_CMDTIMEOUT;	} else {		//We need the CMDSENT-Interrupt only if we want are not waiting		//for a response		sdi_imsk |= S3C2410_SDIIMSK_CMDSENT;	}	if(mrq->cmd->flags & MMC_RSP_LONG) {		sdi_ccon|= S3C2410_SDICMDCON_LONGRSP;	}	if(mrq->cmd->flags & MMC_RSP_CRC) {		sdi_imsk |= S3C2410_SDIIMSK_RESPONSECRC;	}	if (mrq->data) {

⌨️ 快捷键说明

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