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

📄 ftsdc010.c

📁 SD卡驱动程序,是基于GM8180的体系的完整代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* drivers/block/CPESD/ftsdc010.c ******************************************************************************* *  FTSDC010 Device Driver * *  Copyright (C) 2005 GM Corp. (http://www.grain-media.com) *   *  All Rights Reserved *  * Porting to Linux 2.6 on 20050815 * Author: Chris Lee, I-Jui Sung, Peter Liao (support APB DMA) * Version: 0.2 * History: *          0.1 new creation *          0.2 Porting to meet the style of linux dma *          0.3 modify dma usage to virtual irq of dma interrupt *          0.4 (20050701) Improve r/w performance *	    0.5 Porting to Linux 2.6 and replace busy_loop checking with timer's timeout * Todo: ******************************************************************************* */#include "config.h"#include <linux/kernel.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/hdreg.h>	/* HDIO_GETGEO */#include <linux/fs.h>#include <linux/blkdev.h>#include <linux/buffer_head.h>	/* invalidate_bdev */#include <linux/bio.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/arch/spec.h>#include <asm/arch/irqs.h>#include <asm/signal.h>extern int a320_get_ahb_clk(void);extern asmlinkage long sys_kill(int pid, int sig);static pid_t mpid;#define IPMODULE SDC#define IPNAME   FTSDC010#ifdef CONFIG_FTSDC010_USE_APBDMA#define SD_DMA_CHANNEL	0#endif#ifdef CONFIG_FTSDC010_USE_AHBDMA#define SD_DMA_CHANNEL 	6#endif#ifdef CONFIG_FTSDC010_USE_APBDMA#include "asm/arch/apb_dma.h"#define CONFIG_FTSDC010_USE_APBDMA_POLL	1#undef 	CONFIG_FTSDC010_USE_APBDMA_POLL#endif#ifdef CONFIG_FTSDC010_USE_AHBDMA#include "asm/arch/ahb_dma.h"#endif/* Define CONFIG_FTSDC010_USE_TIMER_DELAY if you want to use software timer instead of busy loop checking */#define CONFIG_FTSDC010_USE_TIMER_DELAY//#undef	CONFIG_FTSDC010_USE_TIMER_DELAY#include "ftsdc010.h"#include <linux/interrupt.h>MODULE_AUTHOR("GM Corp.");MODULE_LICENSE("GM License");/* data window register */uint SDC_READ_FIFO_LEN = 4;uint SDC_WRITE_FIFO_LEN = 4;/* options */#define FORCE_PCI_CONSISTENCY	1	/* define it to 1 if met consistency problems */#define KERNEL_SECTOR_SIZE	512	/* Use this when we refer to kernel related sector size */static int hardsect_size = 512, error_flag = 0;#define NOT_DETECT    0#define AUTO_DETECT   1static uint SD_MODE = NOT_DETECT;module_param(SD_MODE, int, 0);MODULE_PARM_DESC(SD_MODE, "SD auto detect");/*------------------------------------------------------------------------------ * Predefine for block device */#define MAJOR_NR			sd_major	/* force definitions on in blk.h */static int sd_major=0;//SD_MAJOR;				/* must be declared before including blk.h */#define SD_SHIFT			4		/* max 16 partitions  */#define DEVICE_NAME			"SDC" 	/* name for messaging */#define DEVICE_REQUEST			sd_request#define DEVICE_NR(device)		(MINOR(device) >> SD_SHIFT)//#define DEVICE_INTR			sd_intrptr	/* pointer to the bottom half */#define DEVICE_NO_RANDOM				/* no entropy to contribute */#define DEVICE_OFF(d)					/* do-nothing *//*#include <linux/blk.h>#include <linux/blkpg.h>*/ /* blk_ioctl() *//*------------------------------------------------------------------------------ * Macro definition */#define FTSDC_VA_BASE			IP_VA_BASE(0)#define FTSDC_PA_BASE                   IP_PA_BASE(0)#define FTSDC_IRQ			IP_IRQ(0)#define SDC_W_REG(offset, value)	outl(value, IP_VA_BASE(0) + offset)#define SDC_R_REG(offset)		inl(IP_VA_BASE(0) + offset)/*------------------------------------------------------------------------------ * Global variable *//* The following items are obtained through kmalloc() in sd_module_init() */struct block_device_operations sd_fops;/* our device structure */typedef struct sd_dev {	int size;		/* device size in sectors */	int usage;		/* # of users currently */	int media_change;	/* Flag: media changed? */	struct gendisk *gd;	/* The gendisk structure */	spinlock_t lock;	/* For mutual exclusion */	struct request_queue *queue;    /* The device request queue */	int card_state;}sd_dev_t;static sd_dev_t *sd_devices = NULL;static sd_card_t sd_card_info;int sector_offset,Do_onetime;#ifdef CONFIG_FTSDC010_USE_APBDMA /* only used for dma mode */dma_addr_t dma_buf=0;wait_queue_head_t sd_dma_queue;static apb_dma_parm_t parm;int bh_busy=0;#endif#ifdef CONFIG_FTSDC010_USE_AHBDMA /* only used for dma mode */dma_addr_t dma_buf=0;wait_queue_head_t sd_dma_queue;static ahb_dma_parm_t parm;int bh_busy=0;#endifint sync_mode=0;static uint first_run = 0;uint sd_err_code;#define FILE_FORMAT_HARD_DISK_LIKE	0#define FILE_FORMAT_FLOPPY_LIKE		1#define FILE_FORMAT_UNIVERSAL		2#define FILE_FORMAT_UNKNOW			3#define FILE_FORMAT_RESERVED		4#define K 1000uint TAAC_TimeUnitTable[] =	{ // unit is ns	1, 10, 100, 1 * K, 10 * K, 100 * K, 1 * K * K, 10 * K * K};uint TRANS_SPEED_RateUintTable[] = {	100 * K, 1 * K * K, 10 * K * K, 100 * K * K};uint TRANS_SPEED_TimeValueTable_u[] = { // unit=1/10	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80};uint VDD_CURR_MIN_Table_u[] = { // unit=1/10	5, 10, 50, 100, 250, 350, 600, 1000};uint VDD_CURR_MAX_Table_u[] = {	1, 5, 10, 25, 35, 45, 80, 200};uint TAAC_TimeValueTable_u[] = { // unit=1/10	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80};/*------------------------------------------------------------------------------ * Local declaration of function */static int sd_revalidate(struct gendisk *gd);static int sd_media_changed(struct gendisk *gd);int sd_card_setup(void);int sd_check_err(uint status);int sd_get_scr(sd_card_t *info, uint *scr);int sd_set_transfer_state(sd_card_t *info);uint sd_block_size_convert(uint size);int sd_read_sector(sd_card_t *info, uint addr, uint count, unchar *buf);void sd_reset_host_controller(void);/*------------------------------------------------------------------------------ * Local function *//* * SD host controller operation */#ifndef CONFIG_FTSDC010_USE_TIMER_DELAYint sdc_send_cmd(uint cmd, uint arg, uint *rsp){	int i;	uint status, count = 0;	/* clear command relative bits of status register */	SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL | SDC_STATUS_REG_RSP_TIMEOUT | SDC_STATUS_REG_RSP_CRC_OK| SDC_STATUS_REG_CMD_SEND);	/* write argument to arugument register if necessary */	SDC_W_REG(SDC_ARGU_REG, arg);	/* send command */	SDC_W_REG(SDC_CMD_REG, cmd | SDC_CMD_REG_CMD_EN);	/* wait for the CMD_SEND bit of status register is set */	while (count++ < SDC_GET_STATUS_RETRY_COUNT) {		status = SDC_R_REG(SDC_STATUS_REG);		if (!(cmd & SDC_CMD_REG_NEED_RSP)) {			/* if this command does not need response, wait command sent flag */			if (status & SDC_STATUS_REG_CMD_SEND) {				/* clear command sent bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_CMD_SEND);				sd_err_code = ERR_NO_ERROR;				return TRUE;			}		} else {			/* if this command needs response */			if (status & SDC_STATUS_REG_RSP_TIMEOUT) {				/* clear response timeout bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_TIMEOUT);				sd_err_code = ERR_RSP_TIMEOUT_ERROR;				printk("%s() ERR_RSP_TIMEOUT_ERROR\n", __func__);				return FALSE;			} else if (status & SDC_STATUS_REG_RSP_CRC_FAIL) {				/* clear response fail bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL);				sd_err_code = ERR_RSP_CRC_ERROR;				printk("%s() ERR_RSP_CRC_ERROR\n", __func__);				return FALSE;			} else if (status & SDC_STATUS_REG_RSP_CRC_OK) {				/* clear response OK bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_OK);				/* if it is long response */				if (cmd & SDC_CMD_REG_LONG_RSP)					for (i = 0; i < 4; i++, rsp++)						*rsp = SDC_R_REG(SDC_RESPONSE0_REG + (i * 4));				else					*rsp = SDC_R_REG(SDC_RESPONSE0_REG);				sd_err_code = ERR_NO_ERROR;				return TRUE;			}		}	}	sd_err_code = ERR_SEND_COMMAND_TIMEOUT;	P_DEBUG("%s() ERR_SEND_COMMAND_TIMEOUT\n", __func__);	return FALSE;}#elseint sdc_send_cmd(uint cmd, uint arg, uint *rsp){	int i;	uint status;	unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT;	P_DEBUG("SD Cmd is %d(%#x)\n",cmd&0x3f, cmd&0x7C0);	/* clear command relative bits of status register */	SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL | SDC_STATUS_REG_RSP_TIMEOUT | SDC_STATUS_REG_RSP_CRC_OK| SDC_STATUS_REG_CMD_SEND);	/* write argument to arugument register if necessary */	SDC_W_REG(SDC_ARGU_REG, arg);	/* send command */	SDC_W_REG(SDC_CMD_REG, cmd | SDC_CMD_REG_CMD_EN);	/* wait for the CMD_SEND bit of status register is set */	while (time_before(jiffies, timeout)) {		status = SDC_R_REG(SDC_STATUS_REG);		if (!(cmd & SDC_CMD_REG_NEED_RSP)) {			/* if this command does not need response, wait command sent flag */			if (status & SDC_STATUS_REG_CMD_SEND) {				/* clear command sent bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_CMD_SEND);				sd_err_code = ERR_NO_ERROR;				return TRUE;			}		} else {			/* if this command needs response */			if (status & SDC_STATUS_REG_RSP_TIMEOUT) {				/* clear response timeout bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_TIMEOUT);				sd_err_code = ERR_RSP_TIMEOUT_ERROR;				printk("%s() ERR_RSP_TIMEOUT_ERROR\n", __func__);				return FALSE;			} else if (status & SDC_STATUS_REG_RSP_CRC_FAIL) {				/* clear response fail bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL);				sd_err_code = ERR_RSP_CRC_ERROR;				printk("%s() ERR_RSP_CRC_ERROR\n", __func__);				error_flag = 1;				return FALSE;			} else if (status & SDC_STATUS_REG_RSP_CRC_OK) {				/* clear response OK bit */				SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_OK);				/* if it is long response */				if (cmd & SDC_CMD_REG_LONG_RSP)					for (i = 0; i < 4; i++, rsp++)						*rsp = SDC_R_REG(SDC_RESPONSE0_REG + (i * 4));				else					*rsp = SDC_R_REG(SDC_RESPONSE0_REG);				sd_err_code = ERR_NO_ERROR;				return TRUE;			}		}	}	sd_err_code = ERR_SEND_COMMAND_TIMEOUT;	P_DEBUG("%s() ERR_SEND_COMMAND_TIMEOUT\n", __func__);	return FALSE;}#endifint sdc_check_tx_ready(void){	uint status;	#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY	int count = 0;	while (count++ < SDC_GET_STATUS_RETRY_COUNT) {		status = SDC_R_REG(SDC_STATUS_REG);		if (status & SDC_STATUS_REG_FIFO_UNDERRUN) {			/* clear FIFO underrun bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_UNDERRUN);			return TRUE;		} else if (status & SDC_STATUS_REG_DATA_TIMEOUT) {			/* clear data timeout bit */			printk("Wait Write FIFO TimeOut\n");			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT);			sd_err_code = ERR_DATA_TIMEOUT_ERROR;			return FALSE;		}	}	#else	unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT;	while (time_before(jiffies, timeout)) {		status = SDC_R_REG(SDC_STATUS_REG);		if (status & SDC_STATUS_REG_FIFO_UNDERRUN) {			/* clear FIFO underrun bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_UNDERRUN);			return TRUE;		} else if (status & SDC_STATUS_REG_DATA_TIMEOUT) {			/* clear data timeout bit */			printk("Wait Write FIFO TimeOut\n");			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT);			sd_err_code = ERR_DATA_TIMEOUT_ERROR;			return FALSE;		}	}	#endif	sd_err_code = ERR_WAIT_UNDERRUN_TIMEOUT;	P_DEBUG("%s() ERR_WAIT_UNDERRUN_TIMEOUT\n", __func__);	return FALSE;}int sdc_check_rx_ready(void){	uint status;	#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY	int count = 0;	while (count++ < SDC_GET_STATUS_RETRY_COUNT) {		status = SDC_R_REG(SDC_STATUS_REG);		if (status & SDC_STATUS_REG_FIFO_OVERRUN) {			/* clear FIFO overrun bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_OVERRUN);			return TRUE;		} else if (status & SDC_STATUS_REG_DATA_TIMEOUT) {			/* clear data timeout bit */			printk("Wait Read FIFO TimeOut\n");			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT);			sd_err_code = ERR_DATA_TIMEOUT_ERROR;			return FALSE;		}	}	#else	unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT;	while (time_before(jiffies, timeout)) {		status = SDC_R_REG(SDC_STATUS_REG);		if (status & SDC_STATUS_REG_FIFO_OVERRUN) {			/* clear FIFO overrun bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_OVERRUN);			return TRUE;		} else if (status & SDC_STATUS_REG_DATA_TIMEOUT) {			/* clear data timeout bit */			printk("Wait Read FIFO TimeOut\n");			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT);			sd_err_code = ERR_DATA_TIMEOUT_ERROR;			return FALSE;		}	}	#endif	sd_err_code = ERR_WAIT_OVERRUN_TIMEOUT;	P_DEBUG("%s() ERR_WAIT_OVERRUN_TIMEOUT\n", __func__);	return FALSE;}int sdc_check_data_crc(void){	uint status=0;	#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY	int count = 0;	while (count++ < SDC_GET_STATUS_RETRY_COUNT) {		status = SDC_R_REG(SDC_STATUS_REG);		if (status & SDC_STATUS_REG_DATA_CRC_OK) {			P_DEBUGG("%s : receive data ok, status=0x%x\n", __func__, status);			/* clear data CRC OK bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_OK);			return TRUE;		} else if (status & SDC_STATUS_REG_DATA_CRC_FAIL) {			/* clear data CRC fail bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_FAIL);			sd_err_code = ERR_DATA_CRC_ERROR;			printk("%s() ERR_DATA_CRC_ERROR\n", __func__);			return FALSE;		} else if (status & SDC_STATUS_REG_DATA_TIMEOUT) {			/* clear data timeout bit */			SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT);

⌨️ 快捷键说明

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