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;
}