所以,对于处在内核空间的驱动来说,发送数据是往SPI_TX_DATA寄存器里写数据,接收是往SPI_RX_DATA寄存器里读数据。当然没这么简单!!
3 SPI发数据流程分析
提醒一点:SPI支持全双工,注意外设是半双工还是全双工?
按照上文设置,我们每次发送和接收一个byte。
(1)置0 NSSOUT
(2)往SPI_TX_DATA寄存器写一个byte,byte数据会自动移入TX FIFO,因为(1)中已经选中了外设,所以SPI master会自动读取TX FIFO中的byte数据移入TX移位寄存器,并开始发往bus。
(3)也就是说,驱动只需要从内核空间往SPI_TX_DATA寄存器上写数据,就完成了SPI发数据的操作了。
(4)全双工,意味着,发数据的同时也要从SPI_RX_DATA寄存器中读一个byte数据。但是,有可能第一次读并不会真正读到数据,因为没有数据被接收到RX移位寄存器。所以忽略这次的读取数据。
(5)置1 NSSOUT
4 SPI接收数据流程分析
如果外设是单双工,考虑在读数据的时候对spi复位!因为如果读数据发生在写数据后面,数据已经在发数据时读取到RX FIFO中了,只需从SPI_RX_DATA中取出数据就行了。
(1)置0 NSSOUT
(2)因为全双工,在发送数据的同时,spi master会读取byte字节并移入RX FIFO。所以从SPI_RX_DATA寄存器读取一个byte,byte数据会自动R从X FIFO移入到SPI_RX_DATA寄存器。(3)也就是说,驱动只需要从内核空间往SPI_RX_DATA寄存器读取数据,就完成了SPI接收数据的操作了。
(4)全双工,意味着,接收数据的同时也要从SPI_TX_DATA寄存器中发送一个byte数据。但是,读数据的时候发送的数据可能不是真正想要发送的数据,因为有些外设不是全双工工作。
(5)置1 NSSOUT
5 SPI收发条件判断
这是SPI收发协议里最难的部分了。
SPI状态寄存器:

1 是否准备好发数据?
/* spi_wait_TX_ready()- wait for TX_READY and TX_DONE */
static BOOL spi_wait_TX_ready( void)
{
unsignedlong loops = msecs_to_loops(10);
u32val = 0;
do{
val= readl(spiregs + S3C_SPI_STATUS);
}while(!((val & SPI_STUS_TX_DONE) && (val & SPI_STUS_TX_FIFORDY))&& loops--);
if(loops == 0)
returnFALSE;
else
returnTRUE;
}
2 发数据是否完成?
/* spi_wait_TX_done()- wait for TX_DONE */
static BOOL spi_wait_TX_done( void)
{
unsignedlong loops = msecs_to_loops(10);
u32val = 0;
do{
val= readl(spiregs + S3C_SPI_STATUS);
}while(!(val & SPI_STUS_TX_DONE) &&loops--);
if(loops == 0)
returnFALSE;
else
returnTRUE;
}
3 是否准备好接收数据?
/* spi_wait_RX_ready()- wait for RX_READY */
static BOOL spi_wait_RX_ready( void)
{
unsignedlong loops = msecs_to_loops(10);
u32val = 0;
do{
val= readl(spiregs + S3C_SPI_STATUS);
}while(!(val & SPI_STUS_TRAILCNT_ZERO) && loops--);
if(loops == 0)
returnFALSE;
else
returnTRUE;
}
6 最终全双工SPI从半双工外设发送和接收数据函数
BOOL spi_sendbyte( BYTE data)
{
BYTEchr;
u32spi_chcfg = spiregs + S3C_CH_CFG;
if(!spi_wait_TX_ready())
{
printk(%s:failed to get tx channel.
);
returnFALSE;
}
writel(data, spiregs + S3C_SPI_TX_DATA);
while(!spi_wait_RX_ready());
readl(spiregs + S3C_SPI_RX_DATA);
returnTRUE;
}
/* spi_flush_fifo()- Clear the TxFIFO , RxFIFO and TX/RX shift register
* @spiregs: the SPI register address*/
VOID spi_flush_fifo(void *spiregs)
{
/* soft rest the spi controller, flush theFIFO */
if(spi_wait_TX_done())
{
writel(readl(spiregs+ S3C_CH_CFG) | SPI_CH_SW_RST, spiregs + S3C_CH_CFG);
writel(readl(spiregs+ S3C_CH_CFG) & ~SPI_CH_SW_RST, spiregs + S3C_CH_CFG);
}
}
/* spi_readbyte()- Read a byte received on SPI0 */
BYTE spi_readbyte( void)
{
u32tmp;
u32spi_chcfg = spiregs + S3C_CH_CFG;
BYTEret;
if(!spi_wait_TX_ready())
returnFALSE;
spi_flush_fifo(spiregs);
writel(0xFF, spiregs + S3C_SPI_TX_DATA);
if(spi_wait_RX_ready())
{
tmp= readl(spiregs + S3C_SPI_RX_DATA);
ret= tmp & 0xff;
}
returnret;
}