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

📄 s3c_mmc.c

📁 mmc 方式通讯的在CPU PXA270下的WINCE 5驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * BRIEF MODULE DESCRIPTION * Low-level MMC functions for S3C24A0 and S3C2440 MMC controllers * Based on: omap_mmc.c and mmc driver for s3c2410 for ipaq * * Copyright 2002 Hewlett-Packard Company * * Copyright 2003 MontaVista Software Inc. * Author: MontaVista Software, Inc. *	   source@mvista.com * * Modified for the S3C24A0 by Naushad naushad@samsung.com: * Copyright (c) 2005 Samsung Electronics. * *  This program is free software; you can redistribute	 it and/or modify it *  under  the terms of	 the GNU General  Public License as published by the *  Free Software Foundation;  either version 2 of the	License, or (at your *  option) any later version. * *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  You should have received a copy of the  GNU General Public License along *  with this program; if not, write  to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>/*#include <linux/irq.h>*/#include <linux/delay.h>#include <linux/timer.h>#include <linux/mmc/mmc_ll.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/arch/irq.h>#include <asm/arch/clocks.h>#include <linux/pm.h>#include <linux/delay.h>#include "s3c_mmc.h"#define S3C_SDIO 1#undef ASSERT#define  ASSERT(expr) \if(!(expr)) { \            printk(" Assertion failed ! %s, %s,%s,line=%d\n",\                       #expr,__FILE__,__FUNCTION__,__LINE__);\}#define MMC_DEBUG 	DEBUGextern struct s3c_mmc_lowlevel s3c24a0_mmc_lowlevel;extern struct s3c_mmc_lowlevel s3c2440_mmc_lowlevel;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;	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_lowlevel *lowlevel;/************************************************************************** * 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);		}	}}static struct s3c_mmc_data g_s3c_mmc_data;#define MMC_IRQ_TIMEOUT (3*HZ)static __inline__ void mmc_delay(void) {  mdelay(100); }/*=>CEE LDM*/#include <linux/device.h>static int s3c_mmc_dpm_suspend(struct device * dev, u32 state, u32 level);static int s3c_mmc_dpm_resume(struct device * dev, u32 level);static struct device_driver s3c_mmc_driver_ldm = {	.name		= "elfin-mmc",	.devclass	= NULL,	.probe		= NULL,	.suspend	= s3c_mmc_dpm_suspend,	.resume		= s3c_mmc_dpm_resume,	.remove		= NULL,};static struct device s3c_mmc_device_ldm = {	.name	= "ELFIN MMC",	.bus_id = "MMC",	.driver = NULL,	.power_state = DPM_POWER_ON,};static void s3c_mmc_ldm_register(void){	extern void apb_bus_register(struct device *device, struct device_driver *driver);		apb_bus_register(&s3c_mmc_device_ldm, &s3c_mmc_driver_ldm);}static void s3c_mmc_ldm_unregister(void){	extern void apb_bus_unregister(struct device *device, struct device_driver *driver);		apb_bus_unregister(&s3c_mmc_device_ldm, &s3c_mmc_driver_ldm);}/*CEE LDM=>*//************************************************************************** *   Clock routines **************************************************************************/static void s3c_mmc_start_clock(void){	rSDICON |= CLOCK_OUT_EN;}static int s3c_mmc_stop_clock(void){	rSDICON  &= ~CLOCK_OUT_EN;	return MMC_NO_ERROR;}static int s3c_mmc_set_clock( u32 rate ){	int retval;	int prescaler = 0;	unsigned long pclk;	/* Does not seem to work consistently if clock rate is above 10000000 */	if ( 10000000 < rate )	{		rate = 10000000;	}		pclk = elfin_get_bus_clk(GET_PCLK);		prescaler = (pclk/rate) - 1;	retval = s3c_mmc_stop_clock(); 		if ( retval )			return retval;		rSDIPRE=prescaler;	s3c_mmc_start_clock();	g_s3c_mmc_data.clock = rate;		return MMC_NO_ERROR;	}static void s3c_mmc_set_transfer( u16 block_len, u16 nob,int cmd ){	MMC_DEBUG(2,": block_len=%d nob=%d", block_len, nob);        rSDIDTIMER = SDIDTIMER_DEFAULT;	if ( block_len > 0x1000) {		MMC_DEBUG(2,"ERROR BLOCK SIZE");	}	rSDIBSIZE = block_len;	if ( nob  > 0x1000) {		MMC_DEBUG(2,"ERROR Num BLOCK ");	}	rSDIDCON   =  nob;	/* Wide Bus Mode Disable */	switch (cmd) {		case MMC_READ_SINGLE_BLOCK:		case MMC_READ_MULTIPLE_BLOCK:			rSDIDCON |=RECV_AF_CMD_NODIRECT|                		   DATA_TRANS_BLOCK|BUSY_AF_CMD_NODIRECT|STANDARD_BUS_MODE;                	rSDIDCON |= (DATA_RECV_START | DATA_START);    					break;		case MMC_WRITE_BLOCK:		case MMC_WRITE_MULTIPLE_BLOCK:			rSDIDCON |= TRAS_AF_RESPONSE_NODIRECT|	                   DATA_TRANS_BLOCK|BUSY_AF_CMD_NODIRECT|STANDARD_BUS_MODE;	        	rSDIDCON |= (DATA_TRANS_START | DATA_START);			break;		default:		  	break;	}}                                                                                                                          /******* * 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;        }	if(rSDIDSTA & MMC_STATUS_DATA_TRANSFER_DONE)		rSDIDSTA = MMC_STATUS_DATA_TRANSFER_DONE;}/******* * Prototype  *       staitc int  chk_CMDend(int cmd, int be_resp) * Purpose: *        1. CMD0 use this function. *        2. Debug  *        	Aofter 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	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 */				}

⌨️ 快捷键说明

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