📄 mmc_pxa.c
字号:
/* * linux/drivers/mmc/mmc_pxa.c * driver for Cotulla MMC controller * * Authors: Vladimir Shebordaev, Igor Oblakov * Copyright: MontaVista Software Inc. * * $Id: mmc_pxa.c,v 0.3.1.12 2002/09/25 19:25:48 ted Exp ted $ * * 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. *//* The driver is modified by Ray.xian, the driver can support MMC and SD in PXA270 * my E-mail: mingrayxian@163.com */#include <linux/version.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <mmc/types.h>#include <mmc/mmc.h>#include <mmc/ioctl.h>//#define CONFIG_MMC_DEBUG//#define CONFIG_MMC_DEBUG_VERBOSE 0#include "types.h"#include "mmc.h"#include "mmc_pxa.h"#include <asm-arm/arch-pxa/pxa-regs.h>static mmc_controller_t host = NULL;static inline int pxa_mmc_send_cmd55( mmc_controller_t );//init GPIOstatic void init_gpio(void){ //MMCLK PIN32 OUT-AF2 GPCR1 |= 0x1; GPDR1 = GPDR1 | (1<<0); GAFR1_L = (GAFR1_L&0xfffffffc) | (2<<0); //MMDAT0 PIN92 GPSR2 |= 0x10000000; GPDR2 |= 0x10000000; // GPDR2 = GPDR2 & ~(1<<28) ; GAFR2_U = (GAFR2_U & 0xfcffffff) | (1<<24) ; //MMDAT1 PIN109 GPSR3 |= (1<<13); GPDR3 |= (1<<13); GAFR3_L = (GAFR3_L & 0xf3ffffff) | (1<<26) ; //MMDAT2 PIN110 GPSR3 |= (1<<14); GPDR3 |= (1<<14); GAFR3_L = (GAFR3_L & 0xcfffffff) | (1<<28); //MMDAT3 PIN111 GPSR3 |= (1<<15); GPDR3 |= (1<<15); GAFR3_L = (GAFR3_L & 0x3fffffff) | (1<<30); //MMCMD PIN112 GPSR3 |= 0x00010000; GPDR3 |= 0x00010000; //GPDR3 = GPDR3 & ~(1<<16); GAFR3_U = (GAFR3_U & 0xfffffffc) | (1<<0); // GPSR3 |= 0x0000e000; GPDR3 |= 0x0000e000; GAFR3_L = (GAFR3_L & 0x03ffffff) | 0x54000000;}/* service routines */static inline int pxa_mmc_check_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ){ int ret = -1; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; if ( hostdata->state != state ) { //MMC_DEBUG( MMC_DEBUG_LEVEL3, "state (%s vs %s)\n", PXA_MMC_STATE_LABEL( hostdata->state ), PXA_MMC_STATE_LABEL( state ) ); goto error; } ret = 0;error: return ret;}static inline void pxa_mmc_set_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ){ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; hostdata->state = state;}static inline int pxa_mmc_init_completion( mmc_controller_t ctrlr, u32 mask ){ int ret = -1; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; if ( xchg( &hostdata->busy, 1 ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "another interrupt " "is already been expected\n" ); goto error; } #if CONFIG_MMC_DEBUG_IRQ hostdata->irqcnt = 1000;#endif init_completion( &hostdata->completion ); MMC_I_MASK = MMC_I_MASK_ALL & ~mask; ret = 0;error: return ret;}#if CONFIG_MMC_DEBUG_IRQ static struct timer_list timer;static void wait_timeo( unsigned long arg ) { pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)arg; hostdata->timeo = 1; complete( &hostdata->completion ); return;}#endifstatic inline int pxa_mmc_wait_for_completion( mmc_controller_t ctrlr, u32 mask ){ int ret = -1; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; if ( !xchg( &hostdata->busy, 1 ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "there were no " "interrupt awaited for\n" ); goto error; }#if CONFIG_MMC_DEBUG_IRQ hostdata->timeo = 0; del_timer( &timer ); timer.function = wait_timeo; timer.expires = jiffies + 1UL*HZ; timer.data = (unsigned long)hostdata; add_timer( &timer );#endif wait_for_completion( &hostdata->completion );#if CONFIG_MMC_DEBUG_IRQ del_timer( &timer ); if ( hostdata->timeo ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "irq timed out: " "mask=%x stat=%x\n", mask, MMC_STAT ); goto error; }#endif /* verify interrupt */ //if ( (mask == ~0UL) || !( hostdata->mmc_i_reg & ~mask ) ) ret = 0; error: xchg( &hostdata->busy, 0 ); return ret;}static inline int pxa_mmc_stop_bus_clock( mmc_controller_t ctrlr ){ int ret = -1; if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_CLK_OFF ) ) { goto out;} if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "BUFFER_IN_TRANSIT\n" ); goto error; } if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_CLK_IS_OFF ) ) { goto error;} MMC_STRPCL = MMC_STRPCL_STOP_CLK; if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_CLK_IS_OFF ) ) {goto error;} /* MMC_I_MASK = MMC_I_MASK_ALL ; MMC_STRPCL |= 1; while(!(MMC_I_REG & (1<<4)) ) { } printk(KERN_EMERG"%s::%s::MMC_I_REG is 0x%08x\n", __FILE__, __FUNCTION__, MMC_I_REG); */ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is off\n" ); pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_CLK_OFF ); out: ret = 0;error: return ret;}static inline int pxa_mmc_start_bus_clock( mmc_controller_t ctrlr ){ int ret = -1; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) && (hostdata->state != PXA_MMC_FSM_END_IO) ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) ); goto error; } MMC_STRPCL = MMC_STRPCL_START_CLK; wmb(); //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is on\n" ); ret = 0;error: return ret;}/* int pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t response )Effects: initializes completion to wait for END_CMD_RES intr, waits for intr to occur, checks controller and card status Requiers: controller is in CLK_OFF stateModifies: moves controller to the END_CMD stateReturns: */ static mmc_error_t pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t format, int send_abort ){ mmc_error_t ret = MMC_ERROR_GENERIC; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; int mask, nwords; u32 status; MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD%d(0x%04x%04x)\n", MMC_CMD & 0x3f, MMC_ARGH, MMC_ARGL);/* FIXME: check arguments */ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) && (hostdata->state != PXA_MMC_FSM_END_IO) ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) ); goto error; } mask = MMC_I_MASK_END_CMD_RES; if ( pxa_mmc_init_completion( ctrlr, mask ) ) goto error; MMC_PRTBUF = MMC_PRTBUF_BUF_FULL; /* start the clock */ if ( pxa_mmc_start_bus_clock( ctrlr ) ) goto error; /* wait for END_CMD_RES intr */ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_END_CMD_RES ) ) goto error;/* check status */ /*modify here*/ { register int i; nwords = (format == MMC_NORESPONSE) ? 0 : (format == MMC_R1) ? 3 : (format == MMC_R2) ? 8 : (format == MMC_R3) ? 3 : (format == MMC_R6) ? 3 : -1; ret = nwords; // printk("nword is 0x%d\n", nwords); for ( i = nwords - 1; i >= 0 ; i-- ) { u32 res = MMC_RES; int ibase = i<<1; // printk(__FILE__" RESPONE is 0x%08x\n", res); hostdata->mmc_res[ibase] = ((u8 *)&res)[0]; hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1]; --ret; } } /*modify here*/ if ( hostdata->mmc_stat & MMC_STAT_TIME_OUT_RESPONSE ) { // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response timeout\n"); ret = MMC_ERROR_TIME_OUT_RESPONSE; goto error; } else if ( hostdata->mmc_stat & MMC_STAT_READ_TIME_OUT ) { // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read timeout\n"); ret = MMC_ERROR_READ_TIME_OUT; goto error; } else if ( hostdata->mmc_stat & MMC_STAT_RES_CRC_ERROR ) { // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response crc err\n"); if ( ((MMC_CMD & 2)|| (MMC_CMD & 9) || (MMC_CMD & 10) ) && (hostdata->mmc_res[ ((nwords-1)<<1)] & 0x80 )) { //printk("MMC_STAT_RES_CRC_ERROR occour, the word [127]is 0x%08x\n", hostdata->mmc_res[(nwords-1)<<1]); } else { ret = MMC_ERROR_RES_CRC_ERROR; goto error;} } else if ( hostdata->mmc_stat & MMC_STAT_CRC_READ_ERROR ) { // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read crc err\n"); ret = MMC_ERROR_CRC_READ_ERROR; goto error; } else if ( hostdata->mmc_stat & MMC_STAT_CRC_WRITE_ERROR ) { // MMC_DEBUG(MMC_DEBUG_LEVEL3, "write crc err\n"); ret = MMC_ERROR_CRC_WRITE_ERROR; goto error; } /* nwords = (format == MMC_NORESPONSE) ? 0 : (format == MMC_R1) ? 3 : (format == MMC_R2) ? 8 : (format == MMC_R3) ? 3 : -1; ret = nwords; printk(__FILE__" "__FUNCTION__"nword is 0x%d\n", nwords);*/ if ( nwords > 0 ) {// register int i;/* MMC_DEBUG( MMC_DEBUG_LEVEL3, "nwords=%d\n", nwords ); for ( i = nwords - 1; i >= 0 ; i-- ) { u32 res = MMC_RES; int ibase = i<<1; printk(__FILE__" "__FUNCTION__"RESPONE is 0x%08x\n", res); hostdata->mmc_res[ibase] = ((u8 *)&res)[0]; hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1]; --ret; } */ #ifdef CONFIG_MMC_DEBUG switch ( format ) { case MMC_R1: MMC_DUMP_R1( ctrlr ); break; case MMC_R2: MMC_DUMP_R2( ctrlr ); break; case MMC_R3: MMC_DUMP_R3( ctrlr ); break; default: MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown response format\n" ); ret = MMC_ERROR_GENERIC; goto error; }#endif/* check card status for R1(b) commands */ if ( format == MMC_R1 ) { u8 cmd; ((u8 *)&status)[0] = hostdata->mmc_res[1]; ((u8 *)&status)[1] = hostdata->mmc_res[2]; ((u8 *)&status)[2] = hostdata->mmc_res[3]; ((u8 *)&status)[3] = hostdata->mmc_res[4]; cmd = PXA_MMC_RESPONSE( ctrlr, 5 )&0x3f; /*MMC_DEBUG( MMC_DEBUG_LEVEL3, //printk( KERN_INFO __FUNCTION__"(): "cmd=%u status: 0x%08x\n", cmd, status ); */ switch ( cmd ) { case 11: case 18: case 20: case 25: if ( !(status & 0x00000100) ) /* FIXME */ goto mmc_error; default: break; } if ( status & MMC_CARD_STATUS_OUT_OF_RANGE ) { ret = MMC_ERROR_OUT_OF_RANGE; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ADDRESS_ERROR ) { ret = MMC_ERROR_ADDRESS_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_BLOCK_LEN_ERROR ) { ret = MMC_ERROR_ADDRESS_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ERASE_SEQ_ERROR ) { ret = MMC_ERROR_ERASE_SEQ_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ERASE_PARAM ) { ret = MMC_ERROR_ERASE_PARAM; goto mmc_error; } else if ( status & MMC_CARD_STATUS_WP_VIOLATION ) { ret = MMC_ERROR_WP_VIOLATION; goto mmc_error; } else if ( status & MMC_CARD_STATUS_CARD_IS_LOCKED ) { ret = MMC_ERROR_CARD_IS_LOCKED; goto mmc_error; } else if ( status & MMC_CARD_STATUS_LOCK_UNLOCK_FAILED ) { ret = MMC_ERROR_LOCK_UNLOCK_FAILED; goto mmc_error; } else if ( status & MMC_CARD_STATUS_COM_CRC_ERROR ) { ret = MMC_ERROR_COM_CRC_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ILLEGAL_COMMAND ) { // ret = MMC_ERROR_ILLEGAL_COMMAND; // goto mmc_error; } else if ( status & MMC_CARD_STATUS_CARD_ECC_FAILED ) { ret = MMC_ERROR_CARD_ECC_FAILED; goto mmc_error; } else if ( status & MMC_CARD_STATUS_CC_ERROR ) { ret = MMC_ERROR_CC_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ERROR ) { ret = MMC_ERROR_ERROR; goto mmc_error; } else if ( status & MMC_CARD_STATUS_UNDERRUN ) { ret = MMC_ERROR_UNDERRUN; goto mmc_error; } else if ( status & MMC_CARD_STATUS_OVERRUN ) { ret = MMC_ERROR_OVERRUN; goto mmc_error; } else if ( status & MMC_CARD_STATUS_CID_CSD_OVERWRITE ) { ret = MMC_ERROR_CID_CSD_OVERWRITE; goto mmc_error; } else if ( status & MMC_CARD_STATUS_ERASE_RESET ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -