www.pudn.com > canbus.rar > spi.c


/* 
 
Module Name:	SPI.CPP 
 
Abstract:		SPI Interface Routines for Samsung SC2410 CPU 
   
Notes:			Presently, only the SPI Channel 0 is supported. 
 
Environment:	Samsung SC2410 CPU 
 
Date: 			2004/01/28 
 
By: 			Li zhongmin 
    
*/ 
 
#include	 //fla 
#include	  //fla 
#include	  //fla 
#include	 
#include    //fla 
#include   //fla 
extern unsigned long eintmask,spcon0,spsta0,sppin0,sppre0,sptdat0,sprdat0,spcon1,spsta1,sppin1,sppre1,sptdat1,sprdat1; //fla from mcpcan.c 
//#include 	"2410addr.h" 
#include 	"def.h" 
#include 	"spi.h" 
#include	"option.h" 
 
volatile DWORD g_dwWaitCounter = 0; 
//---------------------------------------------------------------------------------- 
//extern str[256]; 
 
// Used to wait the specified # of clock cycles 
#define WAIT(x)		{ for(g_dwWaitCounter=0; g_dwWaitCounter6  fla 
	 
	//*(unsigned int *)rGPGUP  = 0xfffff; 
	writel(0xfffff,rGPGUP); 
	 
#endif 
 
/*     
    //GPG4 Output Port [9:8] 01      -> LCD_PWREN Enable 
    rGPGCON = (rGPGCON & 0xfffffcff) | (1<<8); 
    rGPGDAT = (rGPGDAT & 0xffef) | (1<<4); 
*/ 
    //=== PORT H GROUP 
    //Ports  :  GPH10    GPH9  GPH8 GPH7  GPH6  GPH5 GPH4 GPH3 GPH2 GPH1  GPH0  
    //Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0 
    //Binary :   10   ,  10     10 , 11    11  , 10   10 , 10   10 , 10    10 
    //*(unsigned int *)rGPHCON = 0x2afaaa; 
    writel(0x2afaaa,rGPHCON); 
     
     
    //*(unsigned int *)rGPHUP  = 0x7ff;    // The pull up function is disabled GPH[10:0] 
    writel(0x7ff,rGPHUP); 
     
    //External interrupt will be falling edge triggered.  
    //*(unsigned int *)rEXTINT0 = 0x22222222;    // EINT[7:0] 
    writel(0x22222222,S3C2410_EXTINT0); 
     
    //*(unsigned int *)rEXTINT1 = 0x22222222;    // EINT[15:8] 
    writel(0x22222222,S3C2410_EXTINT1); 
     
    //*(unsigned int *)rEXTINT2 = 0x22222222;    // EINT[23:16] 
    writel(0x22222222,S3C2410_EXTINT2); 
     
    //fla init interr again! 
    //s3c2410_gpio_cfgpin(S3C2410_GPG0, S3C2410_GPG0_EINT8); 
    writel(readl(S3C2410_INTMSK)& (~(1<<5)),S3C2410_INTMSK); 
    writel(readl(eintmask)& (~(1<<8)),eintmask); 
    writel(readl(S3C2410_EXTINT1)|(0x00000007)&(0xfffffffb),S3C2410_EXTINT1); 
    //s3c2410_gpio_pullup(S3C2410_GPG0,0); //dis 
     
     
} 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		SPI_Init() 
 
Description:	Initializes the Serial Peripheral Interface (SPI) 
 
Notes:			This routine assumes that the control registers (see  
				the globals section above) have already been initialized. 
 
Returns:		Boolean indicating success. 
-------------------------------------------------------------------*/ 
BOOL SPI_Init(VOID) 
{ 
	int index; 
 
//	index = *(unsigned int *)rCLKCON; 
//	*(unsigned int *)rCLKCON = index; 
//	index = 0; 
//	index = *(unsigned int *)rCLKCON; 
//	printk("rCLKCON = %d\n",index); 
 
	 
	//*(unsigned int *)rGPGDAT = (*(unsigned int *)rGPGDAT)|CHIP_DESELECT_nSS0; 
	writel(readl(rGPGDAT)|CHIP_DESELECT_nSS0,rGPGDAT); 
	 
	//chip select SPI1 ??? 
	 
	//----- 1. IMPORTANT: By default, the internal clock is disabled.  To configure the controller ------ 
	//					  we must first enable it. 
	StartSPIClock(); 
     
	SetSPIClockRate(CLK_RATE_SLOW); 
 
	//----- 2. Configure the GPIO pins for SPI mode ----- 
	// 
	//		   nSPICS0  (chip select)		= GPG2 
	//		   SPICLK0  (SPI clock)			= GPE13 
	//		   SPIMOSIO (SPI output data)	= GPE12 
/*    
	*(unsigned int *)rGPGCON = (*(unsigned int *)rGPGCON) & CLEAR_GPG2_MASK; 
	*(unsigned int *)rGPGCON = (*(unsigned int *)rGPGCON) | ENABLE_GPG2_OUTPUT; 
	*(unsigned int *)rGPGUP  = (*(unsigned int *)rGPGUP)  & ENABLE_GPG2_PULLUP; 
//	port_outl(rGPGUP , (port_inl(rGPGUP) & 0x0)); 
	*(unsigned int *)rGPGCON = (*(unsigned int *)rGPECON) & 0xf03fffff; 
	*(unsigned int *)rGPECON = (*(unsigned int *)rGPECON) | ENABLE_SPICLK0 | ENABLE_SPIMSIO; 
//	*(unsigned int *)rGPEUP  = (*(unsigned int *)rGPEUP£© | DISABLE_SPICLK_SPIMSIO_PULLUP;	// Disable pullup-resistor for SPICLK0 and SPIMOSIO   the name is too long  
//	*(unsigned int *)rGPEUP  = (*(unsigned int *)rGPEUP)  | TEST;    //#define TEST 0x00003800 in spi.h 
	*(unsigned int *)rGPEUP  = (*(unsigned int *)rGPEUP)  | 0x00003800; 
//	port_outl(rGPEUP , (port_inl(rGPEUP)  | 0xffffffff)); 
*/ 
	Port_Init(); 
 
	//----- 3. Configure the SPI controller with reasonable default values ----- 
	 
	//*(unsigned int *)rSPCON0 = SPI_MODE_POLLING | SPI_SELECT_MASTER | SPI_CLOCK_ENABLE; 
	writel(SPI_MODE_POLLING | SPI_SELECT_MASTER | SPI_CLOCK_ENABLE,spcon0); 
	 
	//*(unsigned int *)rSPCON1 = SPI_MODE_POLLING | SPI_SELECT_MASTER | SPI_CLOCK_ENABLE; 
	writel(SPI_MODE_POLLING | SPI_SELECT_MASTER | SPI_CLOCK_ENABLE,spcon1); 
 
	for( index = 0; index < 20; index++) 
		//*(unsigned char *)rSPTDAT0 =  0xFF; 
    writel(0xFF,sptdat0); 
	 
	for( index = 0; index < 20; index++) 
		//*(unsigned char *)rSPTDAT1 =  0xFF; 
		writel(0xFF,sptdat1); 
 
    //StopSPIClock(); 
 
	return TRUE; 
} 
 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		SPI_Deinit() 
 
Description:	Deinitializes the Serial Peripheral Interface (SPI) 
 
Notes:			This routine DOES NOT unmap the control registers; 
				the caller is responsible for freeing this memory. 
 
Returns:		Boolean indicating success. 
-------------------------------------------------------------------*/ 
BOOL SPI_Deinit(VOID) 
{ 
	//----- 1. Stop the SPI clocks ----- 
    StopSPIClock(); 
 
	return TRUE; 
} 
 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		SPI_SendByte() 
 
Description:	Sends the specified byte out onto the SPI bus. 
 
Returns:		Boolean indicating success. 
-------------------------------------------------------------------*/ 
BOOL SPI_SendByte(BYTE bData, BYTE* pData) 
{ 
    //----- 0. Start clock 
    //StartSPIClock(); 
 
	//----- 1. Chip select the slave device (active low) ----- 
	//rGPGDAT &= CHIP_SELECT_nSS0; 
 
	//----- 2. Wait until the controller is ready to transfer ----- 
	if(SPI_WaitTxRxReady()==FALSE) return FALSE; 
	 
 
//	printk("after the 1st wait in SPI_SendByte.\n"); 
 
	//----- 3. Put the byte out onto the SPI bus ----- 
	 
	//*(unsigned char *)rSPTDAT0 =  bData; 
	//printk("in spi.c:the maped addr of sptdat = %#p\n",sptdat0); 
	writel(bData,sptdat0); 
	 
	 
	//----- 4. Delay a little bit so the byte finishes clocking out before the chip select line is deasserted ----- 
	if(SPI_WaitTxRxReady()==FALSE) return FALSE; 
	 
//	printk("after the 2nd wait in SPI_SendByte.\n"); 
 
	//*pData = *(unsigned char *)rSPRDAT0; 
	*pData = readl(sprdat0); 
 
	//----- 5. Deselect the slave device (active low) ----- 
	//rGPGDAT |= CHIP_DESELECT_nSS0; 
 
   // StopSPIClock(); 
 
	return TRUE; 
} 
 
BOOL SPI_ReadByte(BYTE *pData) 
{ 
    BOOL    bRet = TRUE; 
     
    //----- 0. Start clock 
    //StartSPIClock(); 
 
	//----- 1. Chip select the slave device (active low) ----- 
	//rGPGDAT &= CHIP_SELECT_nSS0; 
 
	//----- 2. Wait until the controller is ready to transfer ----- 
	if(SPI_WaitTxRxReady()==FALSE) return FALSE; 
 
	//----- 3. Put the byte out onto the SPI bus ----- 
	 
	//*pData = *(unsigned char *)rSPRDAT0; 
	*pData = readl(sprdat0); 
	//----- 4. Delay a little bit so the byte finishes clocking out before the chip select line is deasserted ----- 
	//if(SPI_WaitTxRxReady()==FALSE) return FALSE; 
 
	//----- 5. Deselect the slave device (active low) ----- 
	//rGPGDAT |= CHIP_DESELECT_nSS0; 
 
   // StopSPIClock(); 
 
	return bRet;	 
} 
 
BOOL SPI_WaitTxRxReady(VOID) 
{ 
	int waitCount; 
//	int reg; 
	 
	//----- 1. Wait until the controller is ready to transfer ----- 
	waitCount = 1000; 
	while(!((readl(spsta0)) & SPI_TRANSFER_READY)) 
	{ 
		if(--waitCount == 0) 
		{ 
//			reg = *(unsigned int *)rSPSTA0; 
//			printk("rSPSTA0 = %d\n",reg); 
//			printk("WaitTxRxReady return FALSE.\n");			 
 
//			ssleep(1); 
//			msleep(1); 
 
			mdelay(10); 
		//	udelay(1); 
//			ndelay(1); 
 
			return FALSE; 
		} 
	} 
	 
	return TRUE; 
	 
} 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		SPI_SendWord() 
 
Description:	Sends the specified word out onto the SPI bus. 
 
Returns:		Boolean indicating success. 
-------------------------------------------------------------------*/ 
/*BOOL SPI_SendWord(WORD wData) 
{ 
    BOOL    bRet = TRUE; 
	DWORD   waitCount = 0; 
 
    StartSPIClock(); 
 
	//----- 1. Chip select the slave device (active low) ----- 
	rGPGDAT &= CHIP_SELECT_nSS0; 
 
	//----- 2. Wait until the controller is ready to transfer ----- 
	waitCount = 1000; 
	while(!(rSPSTA0 & SPI_TRANSFER_READY)) 
	{ 
		if(--waitCount == 0) 
		{ 
            bRet = FALSE; 
			goto SEND_ERROR; 
		} 
	} 
 
	//----- 3. Send first half of word ----- 
	rSPTDAT0 = (wData & 0xFF00) >> 8; 
 
	//----- 4. Wait until the controller is ready to transfer ----- 
	waitCount = 1000; 
	while(!(rSPSTA0 & SPI_TRANSFER_READY)) 
	{ 
		if(--waitCount == 0) 
		{ 
			//RETAILMSG(1, (TEXT("WAVEDEV.DLL: SPI_SendWord() - timeout occurred while waiting to transfer byte\r\n"))); 
            bRet = FALSE; 
			goto SEND_ERROR; 
		} 
	} 
 
	//----- 5. Send second half of word ----- 
	rSPTDAT0 = (wData & 0x00FF); 
 
	//----- 6. Delay a little bit so the byte finishes clocking out before the chip select line is deasserted ----- 
	WAIT(10000); 
 
	//----- 7. Deselect the slave device (active low) ----- 
	rGPGDAT |= CHIP_DESELECT_nSS0; 
 
SEND_ERROR: 
 
    StopSPIClock(); 
 
	return bRet; 
} 
*/ 
 
//------------------------------------ Helper Routines ------------------------------------ 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		StartSPIClock() 
 
Description:	Enables the SPI clock. 
 
Returns:		N/A 
-------------------------------------------------------------------*/ 
VOID StartSPIClock(VOID) 
{ 
	//*(unsigned int *)rCLKCON = (*(unsigned int *)rCLKCON)|SPI_INTERNAL_CLOCK_ENABLE;// Enable the CPU clock to the SPI controller 
  writel(readl(S3C2410_CLKCON)|SPI_INTERNAL_CLOCK_ENABLE,S3C2410_CLKCON); 
	 
	 
	//*(unsigned int *)rSPCON0 = (*(unsigned int *)rSPCON0)|SPI_CLOCK_ENABLE|SPI_SELECT_MASTER;// Enable the SPI clock 
	writel(readl(spcon0)|SPI_CLOCK_ENABLE|SPI_SELECT_MASTER,spcon0); 
	 
	return; 
} 
 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		StopSPIClock() 
 
Description:	Disables the SPI clock. 
 
Returns:		N/A 
-------------------------------------------------------------------*/ 
VOID StopSPIClock(VOID) 
{ 
	//*(unsigned int *)rCLKCON = (*(unsigned int *)rCLKCON) & ~SPI_INTERNAL_CLOCK_ENABLE;	// Disable the CPU clock to the SPI controller 
  	writel(readl(S3C2410_CLKCON) & ~SPI_INTERNAL_CLOCK_ENABLE,S3C2410_CLKCON); 
 
 
	//*(unsigned int *)rSPCON0 = (*(unsigned int *)rCLKCON) & ~SPI_CLOCK_ENABLE;				// Disable the SPI clock 
	writel(readl(spcon0)& ~SPI_CLOCK_ENABLE,spcon0);//fla should be a error in up line! 
	//writel(readl(spcon0)&0x6f,spcon0);//Disable the SPI clock 
	return; 
} 
 
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
Function:		SetSPIClockRate() 
 
Description:	Sets the SPI clock (a.k.a. baud) rate: 
 
Params:			ClockRate       0x00 =      25Mhz 
								0x01 = 1/2  25Mhz 
								0x02 = 1/4  25Mhz 
								0x03 = 1/8  25Mhz 
								0x04 = 1/16 25Mhz 
								0x05 = 1/32 25Mhz 
								0x06 = 1/64 25Mhz 
								0x07 = 99.121Khz 
 
Returns:		N/A 
-------------------------------------------------------------------*/ 
VOID SetSPIClockRate(DWORD ClockRate) 
{ 
	UINT16 prescale; 
 
    //----- 1. Set the clock rate  ----- 
	//		   NOTE: Using the prescale value, the clock's baud rate is 
	//				 determined as follows: baud_rate = (PCLK / 2 / (prescale + 1)) 
	// 
	//				 Hence, the prescale value can be computed as follows: 
	//				 prescale = ((PCLK / 2) / baud_rate) - 1 
	switch(ClockRate) 
	{ 
		case CLK_RATE_FULL:						// 25 Mhz			 
		prescale = (PCLK / 40000000) - 1; 
		break; 
 
		case CLK_RATE_HALF:						// 1/2  25 Mhz						 
		prescale = (PCLK / 30000000) - 1; 
		break; 
 
		case CLK_RATE_FOUR:						// 1/4  25 Mhz						 
		prescale = (PCLK / 10000000) - 1; 
		break; 
 
		case CLK_RATE_EIGHT:					// 1/8  25 Mhz						 
		prescale = (PCLK / 500000) - 1; 
		break; 
 
		case CLK_RATE_SIXTEEN:					// 1/16 25 Mhz						 
		prescale = (PCLK / 2500000) - 1; 
		break; 
 
		case CLK_RATE_THIRTY2:					// 1/32 25 Mhz						 
		prescale = (PCLK / 1250000) - 1; 
		break; 
 
		case CLK_RATE_SIXTY4:					// 1/64 25 Mhz						 
		prescale = (PCLK / 625000) - 1; 
		break; 
 
		case CLK_RATE_SLOW:						// 99.121 kHz (i.e. ~1/256 25Mhz) 
		prescale = 255; 
		break; 
 
		default: 
		return; 
		break; 
	} 
 
	//*(unsigned int *)rSPPRE0 = prescale; 
  writel(prescale,sppre0); 
 
    return; 
}