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

📄 mmc_samsung.c

📁 The sd/mmc driver for s3c2410, it is much better than the one from samsung
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * 2002 (C) Copyrigt SAMSUMNG ELECTRONICS  *           SW.LEE <hitchcar@sec.samsung.com> *  * 	    Low-level MMC functions for the S3CXX * * Copyright 2002 Hewlett-Packard Company * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author:  Andrew Christian *          6 May 2002 * SW.LEE <hitchcar@sec.samsung.com> *    Wrote MMC driver for S3C2410 * Jamey Hicks <jamey.hicks@hp.com>  July 7, 2003 *    Generalized the S3C2410 MMC driver for other instantiations of this samsung asic core.  */#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <asm/irq.h>       #include <asm/unaligned.h>#include <asm/arch/hardware.h>#include <asm/io.h> /* ioremap *///#include <linux/mmc/mmc_ll.h>#include "mmc_ll.h"//#include <asm/arch/h5400-gpio.h>//#include <asm/arch/h5400-asic.h>//#include <asm/arch/h5400-irqs.h>#include "mmc_samsung.h"#include "sdi_reg_s3c2410.h"#undef ASSERT#define  ASSERT(expr) if(!(expr)) { printk(" Assertion failed ! %s, %s,%s,line=%d\n", #expr,__FILE__,__FUNCTION__,__LINE__);}struct s3c_mmc_lowlevel *lowlevel;/*#define mmc_enable_irq(x)#define mmc_disable_irq(x)*/struct response_info {        int length;        u16 flags;};static struct response_info rinfo[] = {	{ 0,  MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE                     }, /* R0 */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1                              }, /* R1  */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1 | MMC_CMD_DATA_CONT_BUSY_BIT }, /* R1b */	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CID */	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CSD */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R3                              }, /* R3  */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R4                              }, /* R4  */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R5                              }, /* R5  */	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R6                              }, /* R6  */};enum s3c_request_type {	RT_NO_RESPONSE,	RT_RESPONSE_ONLY,	RT_READ,	RT_WRITE};struct s3c_mmc_data {	struct timer_list        sd_detect_timer;	struct timer_list        reset_timer;	struct timer_list        irq_timer;                                          /* Panic timer - make sure we get a response */	u32                      clock;        /* Current clock frequency */	struct mmc_request      *request;        enum s3c_request_type  type;                        /* used in s3c_set_transfer() */         u32    size2send;	/* MAX(datasize)= request->nob * request->block_len  */         u32    size2read;      /* read byts from SD Card */         u32    insert ;};/*static*/ struct s3c_mmc_data g_s3c_mmc_data;EXPORT_SYMBOL(g_s3c_mmc_data);#define MMC_IRQ_TIMEOUT (3*HZ)static __inline__ void mmc_delay(void) {  mdelay(100); }/************************************************************************** * Utility routines for debuging **************************************************************************/struct cmd_to_name {	int   id;	char *name;};static struct cmd_to_name cmd_names[] = {	{ MMC_CIM_RESET, "CIM_RESET" },	{ MMC_GO_IDLE_STATE, "GO_IDLE_STATE" },	{ MMC_SEND_OP_COND, "SEND_OP_COND" },	{ MMC_ALL_SEND_CID, "ALL_SEND_CID" },	{ MMC_SET_RELATIVE_ADDR, "SET_RELATIVE_ADDR" },	{ MMC_SET_DSR, "SET_DSR" },	{ MMC_SELECT_CARD, "SELECT_CARD" },	{ MMC_SEND_CSD, "SEND_CSD" },	{ MMC_SEND_CID, "SEND_CID" },	{ MMC_READ_DAT_UNTIL_STOP, "READ_DAT_UNTIL_STOP" },	{ MMC_STOP_TRANSMISSION, "STOP_TRANSMISSION" },	{ MMC_SEND_STATUS	, "SEND_STATUS	" },	{ MMC_GO_INACTIVE_STATE, "GO_INACTIVE_STATE" },	{ MMC_SET_BLOCKLEN, "SET_BLOCKLEN" },	{ MMC_READ_SINGLE_BLOCK, "READ_SINGLE_BLOCK" },	{ MMC_READ_MULTIPLE_BLOCK, "READ_MULTIPLE_BLOCK" },	{ MMC_WRITE_DAT_UNTIL_STOP, "WRITE_DAT_UNTIL_STOP" },	{ MMC_SET_BLOCK_COUNT, "SET_BLOCK_COUNT" },	{ MMC_WRITE_BLOCK, "WRITE_BLOCK" },	{ MMC_WRITE_MULTIPLE_BLOCK, "WRITE_MULTIPLE_BLOCK" },	{ MMC_PROGRAM_CID, "PROGRAM_CID" },	{ MMC_PROGRAM_CSD, "PROGRAM_CSD" },	{ MMC_SET_WRITE_PROT, "SET_WRITE_PROT" },	{ MMC_CLR_WRITE_PROT, "CLR_WRITE_PROT" },	{ MMC_SEND_WRITE_PROT, "SEND_WRITE_PROT" },	{ MMC_ERASE_GROUP_START, "ERASE_GROUP_START" },	{ MMC_ERASE_GROUP_END, "ERASE_GROUP_END" },	{ MMC_ERASE, "ERASE" },	{ MMC_FAST_IO, "FAST_IO" },	{ MMC_GO_IRQ_STATE, "GO_IRQ_STATE" },	{ MMC_LOCK_UNLOCK, "LOCK_UNLOCK" },	{ MMC_APP_CMD, "APP_CMD" },	{ MMC_GEN_CMD, "GEN_CMD" },};static char * get_cmd_name( int cmd ){	int i;	int len = sizeof(cmd_names) / sizeof(struct cmd_to_name);	for ( i = 0 ; i < len ; i++ )		if ( cmd == cmd_names[i].id )			return cmd_names[i].name;	return "UNKNOWN";}struct status_bit_to_name {	u16   mask;	int   shift;	char *name;};struct status_bit_to_name cmd_status_bit_names[] = {  {MMC_STATUS_CRC_RESPONSE_ERROR ,-1," MMC_STATUS_CRC_RESPONSE_ERROR"},  {MMC_STATUS_CMD_SENT_DONE      ,-1," MMC_STATUS_CMD_SENT_DONE"},  {MMC_STATUS_RESPONSE_TIMEOUT   ,-1,"MMC_STATUS_RESPONSE_TIMEOUT"},  {MMC_STATUS_RESPONSE_RECV_DONE ,-1,"MMC_STATUS_RESPONSE_RECV_DONE"},  {MMC_STATUS_TRANS_ON           ,-1,"MMC_STATUS_TRANS_ON"},  {MMC_STATUS_RESPONSE_INDEX     ,-1,"MMC_STATUS_RESPONSE_INDEX"}};struct status_bit_to_name data_status_bit_names[] = {  {  MMC_STATUS_RD_WAIT           ,-1, "MMC_STATUS_RD_WAIT"},  {  MMC_STATUS_IO_INT_DETECT     ,-1, "MMC_STATUS_RD_WAIT"},  {  MMC_STATUS_IO_INT_DETECT     ,-1, "MMC_STATUS_IO_INT_DETECT"},  {  MMC_STATUS_FIFO_ERROR        ,-1, "MMC_STATUS_IO_INT_DETECT"},  {  MMC_STATUS_CRC_WRITE_ERROR   ,-1, "MMC_STATUS_CRC_WRITE_ERROR"},  {  MMC_STATUS_CRC_READ_ERROR    ,-1, "MMC_STATUS_CRC_READ_ERROR"},  {  MMC_STATUS_DATA_BUSY_TIMEOUT ,-1, "MMC_STATUS_DATA_BUSY_TIMEOUT"},  {  MMC_STATUS_DATA_TRANSFER_DONE,-1, "MMC_STATUS_DATA_TRANSFER_DONE"},  {  MMC_STATUS_BUSY_FINISH       ,-1, "MMC_STATUS_BUSY_FINISH"},  {  MMC_STATUS_STARTBIT_ERROR    ,-1, "MMC_STATUS_BUSY_FINISH"},  {  MMC_STATUS_TX_DATA_ON_PROGRESS,-1,"MMC_STATUS_BUSY_FINISH"},  {  MMC_STATUS_RX_DATA_ON_PROGRESS,-1,"MMC_STATUS_BUSY_FINISH"}};struct status_bit_to_name fifo_status_bit_names[] = {  {  MMC_STATUS_FIFO_READY_FOR_TX   ,-1,"MMC_STATUS_FIFO_READY_FOR_TX" },  {  MMC_STATUS_FIFO_READY_FOR_RX   ,-1,"MMC_STATUS_FIFO_READY_FOR_RX" },  {  MMC_STATUS_FIFO_TX_HALF_FULL   ,-1,"MMC_STATUS_FIFO_TX_HALF_FULL" },  {  MMC_STATUS_FIFO_EMPTY          ,-1,"MMC_STATUS_FIFO_EMPTY" },  {  MMC_STATUS_FIFO_RX_LAST_DATA   ,-1,"MMC_STATUS_FIFO_RX_LAST_DATA" },  {  MMC_STATUS_FIFO_RX_FULL        ,-1,"MMC_STATUS_FIFO_RX_FULL" },  {  MMC_STATUS_FIFO_RX_HALF_FULL   ,-1,"MMC_STATUS_FIFO_RX_HALF_FULL" },  {  MMC_STATUS_FIFO_COUNT_MASK     ,-1,"MMC_STATUS_FIFO_COUNT" },};/******* * Prototype static void decode_status( u16 status ) * Purpose: *        1. verify SD Command status / SD Data Status *           FIFO status * Entry * Exit * Exceptions: *****************************************************/static void decode_status( u16 status[]){	int i;	int cmd_len  = sizeof( cmd_status_bit_names)/sizeof(struct status_bit_to_name);	int data_len = sizeof(data_status_bit_names)/sizeof(struct status_bit_to_name);	int fifo_len = sizeof(fifo_status_bit_names)/sizeof(struct status_bit_to_name);	struct status_bit_to_name *b = cmd_status_bit_names;	for ( i = 0 ; i <cmd_len ; i++, b++ ) {		if ( status[0] & b->mask ) {			if ( b->shift >= 0 )				printk("%s[%d] ",b->name,((status[0] & b->mask) >> b->shift));			else				printk("%s ", b->name);		}	}		b = data_status_bit_names;	for ( i = 0 ; i <data_len ; i++, b++ ) {		if ( status[1] & b->mask ) {			if ( b->shift >= 0 )				printk("%s[%d] ",b->name,((status[1]& b->mask)>> b->shift));			else				printk("%s ",b->name);		}	}	b = fifo_status_bit_names;	for ( i = 0 ; i <fifo_len ; i++, b++ ) {		if ( status[2]& b->mask ) {			if ( b->shift >= 0 )				printk("%s[%d] ",b->name,((status[2]&b->mask)>> b->shift));			else				printk("%s ", b->name);		}	}}/******* * Prototype  *     static  void mmc_s3c_reset_timeout( unsigned long nr ) * Purpose: *        1. timeout + reset  * Entry * Exit * Exceptions: *       I don't know how to implement but *         1. clock down or slow *         2. FIFO RESETw *         3. MMC Interrupt disable and enable *****************************************************/static void mmc_s3c_reset_timeout( unsigned long nr ){//	struct s3c_mmc_data *sd = (struct s3c_mmc_data *) nr;	/* Send 80 clocks to get things started *//*#ifdef CONFIG_MMC_DEBUG	START_MMC_DEBUG(2) { 		u16 status = S3C_ASIC1_MMC_Status;		printk(__FUNCTION__ ": enabling irq mask=%04x status=0x%04x (", 		       S3C_ASIC1_MMC_InterruptMask, status);		decode_status(status); 		printk(")\n"); 	} END_MMC_DEBUG;#endif*///	mod_timer( &g_s3c_mmc_data.irq_timer, jiffies + MMC_IRQ_TIMEOUT); }static void mmc_s3c_start_clock(void){       rSDICON |= CLOCK_OUT_EN;}/******* * Prototype  *   static int mmc_s3c_stop_clock(void) *    * Purpose: *    * Entry * Exit * Exceptions: *   must add routine to check the status register fields. *****************************************************************/static int mmc_s3c_stop_clock(void){       //rSDIDCON &= ~CMD_START;       rSDICON  &= ~CLOCK_OUT_EN;       return MMC_NO_ERROR;}static int mmc_s3c_set_clock( u32 rate ){	int retval;	int prescaler = 0;	/* Does not seem to work consistently if clock rate is above 10000000 */	if ( 10000000 < rate )	{		rate = 10000000;	}	prescaler = (2*PCLK)/(rate) - 1;	retval = mmc_s3c_stop_clock(); 	if ( retval )	return retval;	rSDIPRE=prescaler;	mmc_s3c_start_clock();	g_s3c_mmc_data.clock = rate  ;	return MMC_NO_ERROR;}/******* * Prototype  *  	static int mmc_s3c_adjust_clock( u32 clock_rate ) * * Purpose: *       * Entry * Exit * Exceptions: *          BAUD RATE = PCLK/2/(PRESCALER +1) *          rSDIPRE = PRESCALER( 8 bits)  *******************************************************************/static int mmc_s3c_adjust_clock( u32 clock_rate ){	int retval;	retval = mmc_s3c_set_clock( clock_rate );	mmc_s3c_start_clock();	return retval;}/******* * Prototype  *       staitc void sd_status_clear(int index )  * Purpose: * Entry: *      0 : cmd status reg. *      1 : data status reg.	 *      2 : fifo status reg. * Exit * Exceptions: *           if you want to advance performance ,get rid of this func. *****************************************************************/static void sd_status_clear(int index){	switch ( index ) {		case 0:			rSDICSTA = MMC_CMD_STATUS_WRITEONE_CLEAR;			break;		case 1:			rSDICSTA = MMC_CMD_STATUS_WRITEONE_CLEAR;			rSDIDSTA = MMC_DATA_STATUS_WRITEONE_CLEAR;			break;		case 2:			rSDICSTA = MMC_CMD_STATUS_WRITEONE_CLEAR;			rSDIDSTA = MMC_DATA_STATUS_WRITEONE_CLEAR;			//rSDIFSTA = MMC_FIFO_STATUS_WRITEONE_CLEAR; /* Read Only */			break;		default:			break;	}}/******* * Prototype  *       staitc int  chk_CMDend(int cmd, int be_resp) * Purpose: *        1. CMD0 use this function. *        2. Debug  *        	After issuing one command , you can see response chk_CMDend  *        	while making busy-waiting. * Entry * Exit * Exceptions: *           not sure  whether other command needs chk_CMDend func. *****************************************************************/static int chk_CMDend(int cmd, int be_resp){	int status;	#define CONFIG_MMC_SPINLOOP_TIMEOUT 10000000	MMC_DEBUG(2, "");	if(!be_resp)	{		int count = 0;		status = rSDICSTA;		while ( !(status & MMC_STATUS_CMD_SENT_DONE) && (count++ < CONFIG_MMC_SPINLOOP_TIMEOUT)) {			status = rSDICSTA;		}		MMC_DEBUG(2,"   STATUS=0x%08X",rSDICSTA);		if (count >= CONFIG_MMC_SPINLOOP_TIMEOUT) {			MMC_DEBUG(0, "cmd timed out status=%#x", status);			return -EIO;		}		MMC_DEBUG(2,"    Ending  Progressing");		sd_status_clear(0);		return 0;	}   	else	// With response   	{		int count = 0;   	 	status=rSDICSTA;		while ( !(status&MMC_STATUS_CMD_SENT_DONE)&&!(status&MMC_STATUS_RESPONSE_RECV_DONE)			&& (count++ < CONFIG_MMC_SPINLOOP_TIMEOUT)) {			printk(".");			status = rSDICSTA;			}		if(cmd==MMC_SEND_OP_COND || cmd==MMC_SEND_CSD || cmd==MMC_READ_DAT_UNTIL_STOP)				// CRC no check		{	    		if( (status&0xf00) != 0xa00 )  // Check error		   	{				rSDICSTA=status;   // Clear error state				if(((status&0x400)==0x400)) {					MMC_DEBUG(2," TIMEOUT ERROR");						return -EIO;	// Timeout error				}				else {					MMC_DEBUG(2," RESPONSE OK ");				}    	   		}			rSDICSTA=status;	// Clear cmd & rsp end state		}		else	// CRC check		{			if( (status&0x1f00) != 0xa00 )	// Check error	    		{				MMC_DEBUG(2," ERROR CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x",cmd, rSDICSTA, rSDIRSP0);				rSDICSTA=status;   // Clear error state				if(((status&0x400)==0x400))		    		return -EIO;	// Timeout error    	    		}	   		rSDICSTA=status;		}		return 0;    	}}static void  mmc_CMD0(void) {	MMC_DEBUG(2,"");	rSDICARG = 0x0;          rSDICCON = START_TRANSMISSION_PRE;        mmc_s3c_start_clock ();        rSDICCON |= CMD_START;        mdelay(1);	chk_CMDend(0,0);}/******* * Prototype  *  	static int mmc_s3c_reset( struct s3c_mmc_data *sd ) * * Purpose: *      1. mmc_cim_init_stack(struct mmc_dev *dev,int first ) issue "MMC_CIM_RESET" *      2. implement "CMD0" * Entry * Exit * Exceptions: *     It is nessecary to get clock slow that obtains the sufficient response time. *****************************************************************************/static int mmc_s3c_reset( struct s3c_mmc_data *sd ){	int retval = 0 ;	MMC_DEBUG(2,"");//	retval = mmc_s3c_adjust_clock( MMC_CLOCK_SLOW );	g_s3c_mmc_data.type = RT_NO_RESPONSE;

⌨️ 快捷键说明

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