1064 lines
28 KiB
C
1064 lines
28 KiB
C
#include <string.h>
|
|
|
|
#include "kdrv_ssp.h"
|
|
#include "kdrv_clock.h"
|
|
#include "kdrv_gpio.h"
|
|
#include "kmdw_memory.h"
|
|
#include "io.h"
|
|
//#include "ARMCM4_FP.h"
|
|
|
|
//#define SSP_WAIT_REMOVE
|
|
#define SPI_Buffer_size (0x00001400)
|
|
|
|
//uint8_t *gRx_buff_SP_SLAVE = (uint8_t *)KDP_DDR_DRV_COM_BUS_RX0_START_ADDR ; //(uint8_t *)KDP_DDR_DRV_SSP1_RX0_START_ADDR;
|
|
//volatile uint8_t *gTx_buff_SP_SLAVE = (uint8_t *)KDP_DDR_DRV_COM_BUS_TX_START_ADDR; //(uint8_t *)KDP_DDR_DRV_SSP1_TX_START_ADDR;
|
|
uint8_t gRx_buff_temp[300];
|
|
|
|
uint32_t gTx_buff_index_SP_SLAVE = 0; //data length
|
|
uint32_t gTx_buff_current_index_SP_SLAVE = 0 ;
|
|
uint32_t gRx_buff_index_SP_SLAVE = 0; //data length
|
|
|
|
|
|
struct st_ssp_spi driver_ssp_ctx;
|
|
|
|
|
|
#if(SSP_SPI_MASTER_DEV==COM_BUS_TYPE_SSP1 || SSP_SPI_MASTER_DEV==COM_BUS_TYPE_SSP0)
|
|
|
|
#define SSP_MASTER_BUFFER (1024)
|
|
uint8_t gTx_buff_SP_MASTER[SSP_MASTER_BUFFER];
|
|
uint8_t gRx_buff_SP_MASTER[SSP_MASTER_BUFFER];
|
|
uint32_t gTx_buff_index_SP_MASTER = 0; //data length
|
|
uint32_t gTx_buff_current_index_SP_MASTER = 0 ;
|
|
uint32_t gRx_buff_index_SP_MASTER = 0; //data length
|
|
struct st_ssp_spi driver_ssp_master_ctx;
|
|
#endif
|
|
|
|
static void SPI0_ISR(void);
|
|
static void SPI1_ISR(void);
|
|
static void kdrv_ssp_spi_irqhandler(kdrv_ssp_spi_dev_id_t handle);
|
|
|
|
IRQn_Type gSPIIRQTbl[2] = {
|
|
SSP_FTSSP010_0_1_IRQ, //SPI0
|
|
SSP_FTSSP010_1_1_IRQ, //SPI1
|
|
};
|
|
|
|
kdrev_ssp_spi_isr_t gSPIISRs[2] = {
|
|
SPI0_ISR,
|
|
SPI1_ISR
|
|
};
|
|
|
|
uint32_t sdl_in_bytes = 16; //1; //12;
|
|
uint32_t pcl = 0; //25; //8; //*0*/8;
|
|
|
|
static void SPI0_ISR(void)
|
|
{
|
|
kdrv_ssp_spi_irqhandler(SSP_SPI_PORT0);
|
|
}
|
|
|
|
static void SPI1_ISR(void)
|
|
{
|
|
kdrv_ssp_spi_irqhandler(SSP_SPI_PORT1);
|
|
}
|
|
|
|
static void kdrv_ssp_set_sclkdiv(kdrv_ssp_spi_dev_id_t handle, uint32_t sclkdiv)
|
|
{
|
|
uint32_t cr1;
|
|
|
|
cr1 = regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr1;
|
|
cr1 &= ~ssp_CR1_SCLKDIV_MASK;
|
|
cr1 |= ssp_CR1_SCLKDIV(sclkdiv);
|
|
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr1 = cr1;
|
|
|
|
}
|
|
|
|
static void kdrv_ssp_reset(kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.SSPRST = 1;
|
|
}
|
|
|
|
static void kdrv_ssp_clear_txhw(uint32_t port)
|
|
{
|
|
regSSP0_ctrl(port)->st.bf.kdrv_ssp_sspcr2.TXFCLR = 1;
|
|
}
|
|
|
|
static void kdrv_ssp_clear_rxhw(kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.RXFCLR = 1;
|
|
}
|
|
/**
|
|
* CR1.SDL has 7 bits means maximum: 2^7 = 127 + 1 bits.
|
|
* 128 bits = 16 bytes
|
|
*/
|
|
static uint32_t kdrv_ssp_set_data_length(kdrv_ssp_spi_dev_id_t handle, uint32_t sdl)
|
|
{
|
|
uint32_t cr1;
|
|
|
|
cr1 = regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr1;
|
|
cr1 &= ~ssp_CR1_SDL_MASK;
|
|
|
|
cr1 |= ssp_CR1_SDL(sdl);
|
|
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr1 = cr1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void kdrv_ssp_spi_enable(kdrv_ssp_spi_dev_id_t handle, uint32_t tx, uint32_t rx)
|
|
{
|
|
//uint32_t cr2 = 0;
|
|
|
|
if( tx == 0 )
|
|
{
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.SSPEN = 0;
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.TXDOE = 0;
|
|
}
|
|
|
|
if( rx == 0 )
|
|
{
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.SSPEN = 0;
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.TXDOE = 0;
|
|
}
|
|
|
|
if (tx || rx)
|
|
{
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.SSPEN = 1;
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.TXDOE = 1;
|
|
|
|
if (tx)
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.TXEN = 1;
|
|
|
|
if (rx)
|
|
regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspcr2.RXEN = 1;
|
|
}
|
|
}
|
|
|
|
void kdrv_ssp_enable_fs(kdrv_ssp_spi_dev_id_t handle, uint32_t tx, uint32_t rx, uint32_t fs)
|
|
{
|
|
uint32_t cr2 = 0;
|
|
|
|
if (tx || rx)
|
|
cr2 = (ssp_CR2_SSPEN | ssp_CR2_TXDOE);
|
|
|
|
if (tx)
|
|
cr2 |= ssp_CR2_TXEN;
|
|
|
|
if (rx)
|
|
cr2 |= ssp_CR2_RXEN;
|
|
|
|
if (fs)
|
|
cr2 |= ssp_CR2_FS;
|
|
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr2 = cr2;
|
|
|
|
}
|
|
|
|
/**
|
|
* Return the number of entries TX FIFO can be written to
|
|
*/
|
|
static uint32_t kdrv_ssp_txfifo_depth( uint32_t port )
|
|
{
|
|
uint32_t depth;
|
|
|
|
depth = ssp_FEA_TXFIFO_DEPTH(
|
|
regSSP0_feature(port)->st.dw.kdrv_ssp_sspfeature);
|
|
depth += 1;
|
|
return depth;
|
|
}
|
|
|
|
static uint32_t kdrv_ssp_txfifo_not_full(uint32_t port) //0: full, 1: not full
|
|
{
|
|
return regSSP0_ctrl(port)->st.bf.kdrv_ssp_sspstatus.TFNF;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the number of entries RX FIFO can be written to
|
|
*/
|
|
static uint32_t kdrv_ssp_rxfifo_depth(uint32_t port)
|
|
{
|
|
uint32_t depth;
|
|
|
|
depth = ssp_FEA_RXFIFO_DEPTH(
|
|
regSSP0_feature(port)->st.dw.kdrv_ssp_sspfeature);
|
|
depth += 1;
|
|
return depth;
|
|
}
|
|
|
|
uint32_t kdrv_ssp_rxfifo_full( kdrv_ssp_spi_dev_id_t handle ) //1:full, 0: not full
|
|
{
|
|
return regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspstatus.RFF;
|
|
}
|
|
|
|
static void kdrv_ssp_spi_set_interrupt( kdrv_ssp_spi_dev_id_t handle, uint8_t nval)
|
|
{
|
|
uint32_t data = 0;
|
|
|
|
data = regSSP0_ctrl(handle)->st.dw.kdrv_ssp_intrcr;
|
|
if( (nval & 0x10 ) == 0x10 ) //DMA_RX
|
|
{
|
|
data &= ~(0x10);
|
|
data |= (0x10);
|
|
}
|
|
|
|
if( (nval & 0x08) == 0x08 )
|
|
{
|
|
data &= ~(0x08);
|
|
data |= (0x08);
|
|
}
|
|
|
|
if( (nval & 0x04 ) == 0x04 )
|
|
{
|
|
data &= ~(0x04);
|
|
data |= (0x04);
|
|
}
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_intrcr = data;
|
|
}
|
|
|
|
|
|
|
|
static uint32_t kdrv_ssp_get_rxfifo_int_thflag( kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
uint32_t ent;
|
|
|
|
ent = regSSP0_ctrl(handle)->st.bf.kdrv_ssp_intrstatus.RFTHI;
|
|
return ent;
|
|
}
|
|
|
|
|
|
static uint32_t kdrv_ssp_get_txfifo_int_thflag( kdrv_ssp_spi_dev_id_t handle )
|
|
{
|
|
uint32_t ent;
|
|
|
|
ent = regSSP0_ctrl(handle)->st.bf.kdrv_ssp_intrstatus.TFTHI;
|
|
return ent;
|
|
}
|
|
|
|
static void kdrv_ssp_write_word(uint32_t port, const void *data, uint32_t wsize)
|
|
{
|
|
uint32_t tmp = 0;
|
|
|
|
if (data) {
|
|
switch (wsize) {
|
|
case 1:
|
|
tmp = *(const uint8_t *)data;
|
|
break;
|
|
|
|
case 2:
|
|
tmp = *(const uint16_t *)data;
|
|
break;
|
|
|
|
default:
|
|
tmp = *(const uint32_t *)data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
regSSP0_ctrl(port)->st.dw.kdrv_ssp_txrxdr = tmp;
|
|
}
|
|
|
|
static void kdrv_ssp_read_word_new( uint32_t port, volatile uint8_t *buf )
|
|
{
|
|
uint32_t data = regSSP0_ctrl(port)->st.dw.kdrv_ssp_txrxdr;
|
|
*buf = data;
|
|
return;
|
|
}
|
|
|
|
static void kdrv_ssp_read_word(uint32_t port, void *buf, uint32_t wsize)
|
|
{
|
|
uint32_t data = regSSP0_ctrl(port)->st.dw.kdrv_ssp_txrxdr;
|
|
|
|
if (buf) {
|
|
switch (wsize) {
|
|
case 1:
|
|
*(uint8_t *) buf = data;
|
|
break;
|
|
|
|
case 2:
|
|
*(uint16_t *) buf = data;
|
|
break;
|
|
|
|
default:
|
|
*(uint32_t *) buf = data;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* len unit is bytes
|
|
*
|
|
* Return number of fifo written.
|
|
*/
|
|
uint32_t kdrv_ssp_fill_in_fifo(uint32_t tx_addr, const void *buf,
|
|
uint32_t rx_addr, uint32_t *len)
|
|
{
|
|
uint32_t count = 0;
|
|
uint32_t rxfifo, fifo, wsize, i;
|
|
|
|
|
|
rxfifo = kdrv_ssp_rxfifo_depth(rx_addr); //get Rx FIOF level
|
|
|
|
|
|
//clear before start filling in
|
|
kdrv_ssp_clear_txhw(tx_addr);
|
|
|
|
i = 0;
|
|
while (kdrv_ssp_txfifo_not_full(tx_addr))
|
|
{
|
|
|
|
if (!*len || !buf)
|
|
break;
|
|
|
|
if (i == 0) {
|
|
i = sdl_in_bytes;
|
|
fifo = (sdl_in_bytes + 3) / 4;
|
|
}
|
|
|
|
//rx fifo doesn't have enough entries to receive
|
|
if ((count + fifo) > rxfifo)
|
|
break;
|
|
|
|
if (i > 3)
|
|
wsize = 4;
|
|
else
|
|
wsize = i;
|
|
|
|
kdrv_ssp_write_word(tx_addr, buf, wsize);
|
|
|
|
i -= wsize;
|
|
*len -= wsize;
|
|
fifo--;
|
|
count++;
|
|
// Always add 4 bytes for buffer pointer
|
|
(*(int8_t*)buf) += 4;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* count is the number of FIFO entries wanted to be read.
|
|
*
|
|
* Return the remaining number of fifo not read yet.
|
|
*/
|
|
uint32_t kdrv_ssp_take_out_fifo(uint32_t rx_addr, void *buf, uint32_t count)
|
|
{
|
|
uint32_t i, wsize;
|
|
|
|
i = 0;
|
|
while (count) {
|
|
|
|
if (!buf)
|
|
break;
|
|
|
|
while (!kdrv_ssp_rxfifo_valid_entries(rx_addr)) {
|
|
;
|
|
}
|
|
|
|
if (i == 0)
|
|
i = sdl_in_bytes;
|
|
|
|
if (i > 3)
|
|
wsize = 4;
|
|
else
|
|
wsize = i;
|
|
|
|
kdrv_ssp_read_word(rx_addr, buf, wsize);
|
|
|
|
i -= wsize;
|
|
count--;
|
|
(*(int8_t*)buf) += 4;
|
|
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static void kdrv_ssp_write_byte_new(uint32_t base, volatile uint8_t *data)
|
|
{
|
|
regSSP0_ctrl(base)->st.dw.kdrv_ssp_txrxdr = *data;
|
|
}
|
|
|
|
static uint32_t kdrv_ssp_set_pcl(uint32_t base, uint32_t val)
|
|
{
|
|
uint32_t cr3;
|
|
|
|
if (val & ~ssp_CR3_PCL_MASK) {
|
|
return 1;
|
|
}
|
|
|
|
cr3 = regSSP0_ctrl(base)->st.dw.kdrv_ssp_sspcr3;
|
|
cr3 &= ~ssp_CR3_PCL_MASK;
|
|
cr3 |= ssp_CR3_PCL(val);
|
|
|
|
regSSP0_ctrl(base)->st.dw.kdrv_ssp_sspcr3=cr3;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void kdrv_ssp_spi_tx_fifo_threshold(uint32_t nbase , uint8_t nval)
|
|
{
|
|
uint32_t ntemp ;
|
|
|
|
ntemp = regSSP0_ctrl(nbase)->st.dw.kdrv_ssp_intrcr;
|
|
|
|
ntemp &= ~ssp_INTCR_TFTHOD_MASK;
|
|
|
|
ntemp = ntemp | ( ssp_INTCR_TFTHOD( nval ) );
|
|
regSSP0_ctrl(nbase)->st.dw.kdrv_ssp_intrcr = ntemp;
|
|
|
|
}
|
|
|
|
|
|
static void kdrv_ssp_spi_rx_fifo_threshold(uint32_t nbase, uint8_t nval)
|
|
{
|
|
uint32_t ntemp ;
|
|
|
|
ntemp = regSSP0_ctrl(nbase)->st.dw.kdrv_ssp_intrcr;
|
|
|
|
ntemp &= ~ssp_INTCR_RFTHOD_MASK;
|
|
|
|
ntemp = ntemp | ( ssp_INTCR_RFTHOD( nval ) );
|
|
regSSP0_ctrl(nbase)->st.dw.kdrv_ssp_intrcr = ntemp;
|
|
|
|
}
|
|
|
|
uint32_t kdrv_ssp_rxfifo_valid_entries( uint32_t port )
|
|
{
|
|
uint32_t ent;
|
|
|
|
ent = ssp_STS_RFVE(regSSP0_ctrl(port)->st.dw.kdrv_ssp_sspstatus);
|
|
|
|
return ent;
|
|
}
|
|
|
|
uint32_t kdrv_ssp_busy(kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
return (regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspstatus.BUSY);
|
|
}
|
|
|
|
static uint32_t kdrv_ssp_tx_fifo_waiting_cnt(kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
return (regSSP0_ctrl(handle)->st.bf.kdrv_ssp_sspstatus.TFVE);
|
|
}
|
|
//check Tx done flag
|
|
static void kdrv_ssp_set_tx_done_flag( struct st_ssp_spi *stspi )
|
|
{
|
|
stspi->Tx_done_flag = 1;
|
|
|
|
#ifdef COM_BUS_RESPONSE_REQUEST_PIN
|
|
if (stCom_type.flags == KL520_COM_HAS_ADDITIONAL_IO)
|
|
{
|
|
kdrv_ssp_slave_request_inactive();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
uint8_t kdrv_ssp_get_tx_done_flag( struct st_ssp_spi *stspi )
|
|
{
|
|
return stspi->Tx_done_flag ;
|
|
}
|
|
|
|
void kdrv_ssp_spi_tx_dma_en( uint32_t nbase)
|
|
{
|
|
regSSP0_ctrl(nbase)->st.bf.kdrv_ssp_intrcr.TFDMAEN = 1;
|
|
}
|
|
|
|
void kdrv_ssp_spi_rx_dma_en(uint32_t nbase)
|
|
{
|
|
regSSP0_ctrl(nbase)->st.bf.kdrv_ssp_intrcr.RFDMAEN = 1;
|
|
}
|
|
|
|
static void kdrv_ssp_tx_write_fifo( struct st_ssp_spi *stspi )
|
|
{
|
|
|
|
uint32_t base_address = stspi->port_no;
|
|
volatile uint8_t dummy_data = 0xAA;
|
|
uint8_t i =0;
|
|
|
|
for( i=0; i < ( SPI_TX_FIFO_TH * 2 ); i++ )
|
|
{
|
|
if( stspi->Tx_buffer_current_index < stspi->Tx_buffer_index )
|
|
{
|
|
//write data
|
|
kdrv_ssp_write_byte_new( base_address, ( stspi->Tx_buffer+ stspi->Tx_buffer_current_index ) );
|
|
stspi->Tx_buffer_current_index = stspi->Tx_buffer_current_index+1;
|
|
|
|
}
|
|
else
|
|
{
|
|
kdrv_ssp_write_byte_new( base_address, &dummy_data );
|
|
kdrv_ssp_set_tx_done_flag(stspi);
|
|
//break;
|
|
}
|
|
|
|
if( kdrv_ssp_txfifo_not_full(base_address) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void kdrv_ssp_rx_read_fifo_partial( struct st_ssp_spi *stspi )
|
|
{
|
|
uint32_t base_address = stspi->port_no;
|
|
uint8_t nsize = kdrv_ssp_rxfifo_valid_entries( base_address );
|
|
uint8_t i=0;
|
|
|
|
//Rx
|
|
for( i=0; i<nsize; i++ )
|
|
{
|
|
kdrv_ssp_read_word_new( base_address , stspi->Rx_buffer+ stspi->Rx_buffer_index );
|
|
stspi->Rx_buffer_index = stspi->Rx_buffer_index + 1 ;
|
|
if( stspi->Rx_buffer_index >= stspi->pre_size )
|
|
{
|
|
stspi->Rx_buffer_index=0;
|
|
if(stspi->cb)
|
|
stspi->cb(ARM_SPI_EVENT_RECEIVE_COMPLETE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void kdrv_ssp_rx_polling_receive_all( struct st_ssp_spi *stspi )
|
|
{
|
|
|
|
uint32_t base_address = stspi->port_no;
|
|
|
|
/*uint8_t temp = 100, nfetch;
|
|
//kmdw_printf("------0x%X---------",(stspi->Rx_buffer_index));
|
|
while( (nfetch = kdrv_ssp_rxfifo_valid_entries( base_address )) != temp )
|
|
{
|
|
temp = nfetch;
|
|
#if ( SSP_SPI_MASTER_DEV == COM_BUS_TYPE_SSP1 )|| ( SSP_SPI_MASTER_DEV == COM_BUS_TYPE_SSP0 )
|
|
kdrv_delay_us(5);
|
|
#else
|
|
kdrv_delay_us(50);
|
|
#endif
|
|
}*/
|
|
|
|
while( (uint8_t)kdrv_ssp_rxfifo_valid_entries( base_address ) != 0 )
|
|
{
|
|
//nfetch--;
|
|
kdrv_ssp_read_word_new( base_address , ( stspi->Rx_buffer+ (stspi->Rx_buffer_index) ) );
|
|
stspi->Rx_buffer_index = stspi->Rx_buffer_index + 1 ;
|
|
}
|
|
}
|
|
|
|
void kdrv_ssp_spi_CS_set( uint32_t pin, uint8_t ndata )
|
|
{
|
|
kdrv_gpio_write_pin( (kdrv_gpio_pin_t) pin, ndata ); //as example
|
|
}
|
|
|
|
/**************************************************
|
|
**************************************************/
|
|
|
|
static void kdrv_ssp_spi_slave_initialize(kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi)
|
|
{
|
|
st_spi->port_no = handle;
|
|
st_spi->SDL = 7;
|
|
st_spi->target_Txfifo_depth = kdrv_ssp_txfifo_depth( st_spi->port_no );
|
|
st_spi->target_Rxfifo_depth = kdrv_ssp_rxfifo_depth( st_spi->port_no );
|
|
st_spi->tx_rx_en = 3;
|
|
|
|
st_spi->interrupt_en = 0x04;
|
|
st_spi->IP_type = 0;
|
|
st_spi->spi_sw_type = 1;
|
|
st_spi->sclkdiv = 0;
|
|
|
|
st_spi->Tx_buffer = (uint8_t *)kmdw_ddr_reserve(SPI_Buffer_size);
|
|
st_spi->Tx_buffer_index = 0;
|
|
st_spi->Tx_buffer_current_index = gTx_buff_current_index_SP_SLAVE;
|
|
st_spi->Rx_buffer = (uint8_t *)kmdw_ddr_reserve(SPI_Buffer_size);
|
|
st_spi->Rx_buffer_index = 0;
|
|
st_spi->buffer_max_size = SPI_Buffer_size;
|
|
st_spi->Rx_tempbuffer = gRx_buff_temp;
|
|
}
|
|
|
|
static void kdrv_ssp_spi_master_initialize(kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi)
|
|
{
|
|
st_spi->port_no = handle;
|
|
st_spi->SDL = 7;
|
|
st_spi->target_Txfifo_depth = kdrv_ssp_txfifo_depth( st_spi->port_no );
|
|
st_spi->target_Rxfifo_depth = kdrv_ssp_rxfifo_depth( st_spi->port_no );
|
|
st_spi->tx_rx_en = 3;
|
|
|
|
st_spi->interrupt_en = 0x00;
|
|
st_spi->IP_type = 3;
|
|
st_spi->spi_sw_type = 0;
|
|
st_spi->sclkdiv = 1;
|
|
|
|
st_spi->Tx_buffer = (uint8_t *)gTx_buff_SP_MASTER;
|
|
//st_spi->Tx_buffer_index = &gTx_buff_index_SP_MASTER;
|
|
st_spi->Tx_buffer_current_index = gTx_buff_current_index_SP_MASTER;
|
|
st_spi->Rx_buffer = (uint8_t *)gRx_buff_SP_MASTER;
|
|
//st_spi->Rx_buffer_index = &gRx_buff_index_SP_MASTER;
|
|
st_spi->buffer_max_size = SSP_MASTER_BUFFER;
|
|
st_spi->Rx_tempbuffer = gRx_buff_temp;
|
|
}
|
|
|
|
//clear Tx sw buf index
|
|
static void kdrv_ssp_clear_tx_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
stspi->Tx_buffer_index = 0;
|
|
}
|
|
|
|
//Get Tx sw buf index
|
|
uint32_t kdrv_ssp_get_tx_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
return stspi->Tx_buffer_index;
|
|
}
|
|
|
|
//check Tx current buf index
|
|
static void kdrv_ssp_clear_tx_current_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
stspi->Tx_buffer_current_index = 0;
|
|
}
|
|
|
|
uint16_t kdrv_ssp_get_tx_current_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
return stspi->Tx_buffer_current_index;
|
|
}
|
|
|
|
//clear Tx done flag
|
|
static void kdrv_ssp_clear_tx_done_flag( struct st_ssp_spi *stspi )
|
|
{
|
|
stspi->Tx_done_flag = 0;
|
|
}
|
|
|
|
//clear Rx sw buf index
|
|
static void kdrv_ssp_clear_rx_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
stspi->Rx_buffer_index = 0;
|
|
}
|
|
|
|
//Get Rx sw buf index
|
|
uint32_t kdrv_ssp_get_rx_buf_index( struct st_ssp_spi *stspi )
|
|
{
|
|
return stspi->Rx_buffer_index;
|
|
}
|
|
|
|
void kdrv_ssp_slave_request_active(void)
|
|
{
|
|
#ifdef COM_BUS_RESPONSE_REQUEST_PIN
|
|
kdrv_gpio_write_pin( COM_BUS_RESPONSE_REQUEST_PIN, 1 );
|
|
#endif
|
|
}
|
|
|
|
void kdrv_ssp_slave_request_inactive(void)
|
|
{
|
|
#ifdef COM_BUS_RESPONSE_REQUEST_PIN
|
|
kdrv_gpio_write_pin( COM_BUS_RESPONSE_REQUEST_PIN, 0 );
|
|
#endif
|
|
}
|
|
|
|
void kdrv_ssp_write_buff( struct st_ssp_spi *stspi, uint8_t *src, uint16_t nlen )
|
|
{
|
|
uint16_t i = 0;
|
|
stspi->Tx_buffer_current_index = 0;
|
|
stspi->Tx_buffer_index = 0;
|
|
|
|
memset((void *)stspi->Tx_buffer, 0 ,SSP_MASTER_BUFFER);
|
|
for( i = 0; i < nlen; i++ )
|
|
{
|
|
*( stspi->Tx_buffer + i ) = *( src + i );
|
|
stspi->Tx_buffer_index = stspi->Tx_buffer_index + 1;
|
|
}
|
|
}
|
|
|
|
void kdrv_ssp_pre_write_to_fifo( struct st_ssp_spi *stspi, uint8_t target_byte )
|
|
{
|
|
volatile uint8_t *tx_buf = stspi->Tx_buffer;
|
|
volatile uint32_t tx_buf_current_index = stspi->Tx_buffer_current_index;
|
|
volatile uint32_t tx_buf_index = stspi->Tx_buffer_index;
|
|
uint16_t i = 0;
|
|
|
|
for( i = 0; i < target_byte; i++ )
|
|
{
|
|
//dbg_msg( "*tx_index : %d, 0x%x", *tx_buf_index , *(tx_buf+i) );
|
|
kdrv_ssp_write_byte_new( stspi->port_no , (tx_buf+i) );
|
|
tx_buf_current_index = tx_buf_current_index + 1;
|
|
}
|
|
}
|
|
|
|
uint8_t kdrv_ssp_SPI_XOR_check(struct st_ssp_spi *stspi)
|
|
{
|
|
uint16_t i = 0;
|
|
uint16_t rx_size = stspi->Rx_buffer_index;
|
|
volatile uint8_t *rx_ptr = stspi->Rx_buffer;
|
|
uint8_t ntemp = 0;
|
|
|
|
ntemp = *rx_ptr;
|
|
for( i=1 ; i < (rx_size-1) ; i++ )
|
|
{
|
|
ntemp ^= *(rx_ptr +i);
|
|
}
|
|
|
|
if( ntemp != *(rx_ptr+rx_size-1) )
|
|
{
|
|
return 0; //xor check fail
|
|
}
|
|
return 1; //xor check pass
|
|
}
|
|
|
|
void kdrv_ssp_SPI_XOR_clc( struct st_ssp_spi *stspi )
|
|
{
|
|
uint16_t i = 0;
|
|
volatile uint32_t tx_size = stspi->Tx_buffer_index;
|
|
volatile uint8_t *tx_ptr = stspi->Tx_buffer;
|
|
uint8_t ntemp = 0;
|
|
|
|
ntemp = *tx_ptr;
|
|
for( i=1 ; i < tx_size ; i++ )
|
|
{
|
|
ntemp ^= *(tx_ptr +i);
|
|
}
|
|
|
|
*( tx_ptr + tx_size ) = ntemp;
|
|
tx_size = tx_size + 1 ;
|
|
}
|
|
|
|
static void kdrv_ssp_spi_irqhandler( kdrv_ssp_spi_dev_id_t handle )
|
|
{
|
|
if( kdrv_ssp_get_txfifo_int_thflag( handle ) != 0 )
|
|
{
|
|
kdrv_ssp_tx_write_fifo( &driver_ssp_ctx );
|
|
}
|
|
if( kdrv_ssp_get_rxfifo_int_thflag( handle ) != 0 )
|
|
{
|
|
kdrv_ssp_rx_read_fifo_partial( &driver_ssp_ctx );
|
|
}
|
|
}
|
|
|
|
/**************************************************
|
|
kdrv_ssp_spi_dev_id_t handle: SPI port
|
|
uint16_t op_mode: config SPI signal type
|
|
**************************************************/
|
|
kdrv_status_t kdrv_ssp_spi_open( kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi, uint16_t op_mode, ARM_SPI_SignalEvent_t cb )
|
|
{
|
|
uint32_t ntemp;
|
|
|
|
sdl_in_bytes = st_spi->SDL;
|
|
kdrv_ssp_reset(handle);
|
|
if( st_spi->IP_type == 0 || st_spi->IP_type == 1 )
|
|
{
|
|
//SPI act as slave
|
|
ntemp = op_mode | ( ssp_CR0_FFMT_SPI | ssp_CR0_SLV_SPI );
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr0 = ntemp;
|
|
}
|
|
else
|
|
{
|
|
//SPI act as master
|
|
ntemp = op_mode | ( ssp_CR0_FFMT_SPI | ssp_CR0_MSTR_SPI );//| ssp_CR0_SCLKFDBK);
|
|
regSSP0_ctrl(handle)->st.dw.kdrv_ssp_sspcr0 = ntemp;
|
|
}
|
|
st_spi->cb = cb;
|
|
kdrv_ssp_set_sclkdiv( handle, st_spi->sclkdiv );
|
|
|
|
|
|
kdrv_ssp_set_data_length( handle, sdl_in_bytes );
|
|
|
|
|
|
kdrv_ssp_set_pcl(handle, pcl);
|
|
|
|
//SPI DMA setting......
|
|
//kdrv_ssp_spi_tx_dma_en( st_spi->port_no ); //SPI0 as slave
|
|
//kdrv_ssp_spi_rx_dma_en(st_spi->port_no);
|
|
|
|
//clear before start filling in
|
|
kdrv_ssp_clear_txhw( handle );
|
|
kdrv_ssp_clear_rxhw( handle );
|
|
|
|
//add interrupt IRQ enable bit!!
|
|
#if ( SSP_SPI_MASTER_DEV == COM_BUS_TYPE_SSP1 )|| ( SSP_SPI_MASTER_DEV == COM_BUS_TYPE_SSP0 )
|
|
if( (st_spi->interrupt_en &0x10)>0 || (st_spi->interrupt_en &0x08)>0 || (st_spi->interrupt_en &0x04)>0 )
|
|
#endif
|
|
{
|
|
kdrv_ssp_spi_set_interrupt( handle, st_spi->interrupt_en ); // TxFIFO threshold: 1<<3, RxFIFO threshold flag: 1<<2
|
|
}
|
|
kdrv_ssp_spi_tx_fifo_threshold( handle, SPI_TX_FIFO_TH );
|
|
kdrv_ssp_spi_rx_fifo_threshold( handle, SPI_RX_FIFO_TH );
|
|
return KDRV_STATUS_OK;
|
|
}
|
|
|
|
kdrv_status_t kdrv_ssp_spi_uninitialize(kdrv_ssp_spi_dev_id_t handle)
|
|
{
|
|
return KDRV_STATUS_OK;
|
|
}
|
|
|
|
|
|
kdrv_status_t kdrv_ssp_api_spi_enable( kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi )
|
|
{
|
|
IRQn_Type irq_num = gSPIIRQTbl[handle];
|
|
kdrev_ssp_spi_isr_t isr = gSPIISRs[handle];
|
|
|
|
//if( st_spi->IP_type == 0 )
|
|
if(st_spi->interrupt_en & 0x0C)
|
|
{
|
|
NVIC_SetVector( irq_num, (uint32_t)isr );
|
|
NVIC_EnableIRQ( irq_num );
|
|
}
|
|
|
|
//SPI enable
|
|
kdrv_ssp_spi_enable( handle, 1, 1);
|
|
return KDRV_STATUS_OK;
|
|
}
|
|
|
|
kdrv_status_t kdrv_ssp_api_spi_disable( kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi )
|
|
{
|
|
IRQn_Type irq_num = gSPIIRQTbl[handle];
|
|
//if( st_spi->IP_type == 0 )
|
|
{
|
|
NVIC_DisableIRQ(irq_num);
|
|
}
|
|
|
|
//SPI enable
|
|
kdrv_ssp_spi_enable(handle, 0, 0);
|
|
return KDRV_STATUS_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
SPI master read and write data continuously in the same transaction time
|
|
support write command and read data in the same time.
|
|
rx_all: 0: receive data after transmit done
|
|
1: receive all data during transmit and receive
|
|
ps:
|
|
step 1. assign write command data size
|
|
step 2. assign read data size
|
|
step 3. SPI transmit write command and then read data continuously
|
|
************************************************************************/
|
|
void kdrv_ssp_SPI_master_transmit( struct st_ssp_spi *st_spi , uint32_t rx_target_size, uint8_t rx_all )
|
|
{
|
|
|
|
uint32_t i;
|
|
uint32_t tx_size = st_spi->Tx_buffer_index;
|
|
uint8_t dummy = 0xcc;
|
|
|
|
//dbg_msg_flash("[SPI]Tx size: %d", tx_size);
|
|
//dbg_msg_flash("[SPI]Rx size: %d", rx_target_size);
|
|
kdrv_ssp_spi_CS_set(chip_select_pin, SPI_CS_LOW);
|
|
//clear before start filling in
|
|
kdrv_ssp_clear_txhw(st_spi->port_no);
|
|
//send tx data
|
|
for ( i = 0; i < tx_size; i++ )
|
|
{
|
|
kdrv_ssp_write_byte_new( st_spi->port_no , (st_spi->Tx_buffer+i) );
|
|
|
|
if( ( (i+1) % (SPI_TX_FIFO_TH<<2) ) != 0 )
|
|
{
|
|
continue;
|
|
}
|
|
while(regSSP0_ctrl(st_spi->port_no)->st.bf.kdrv_ssp_sspstatus.TFVE);
|
|
kdrv_ssp_rx_polling_receive_all( st_spi );
|
|
}
|
|
while(regSSP0_ctrl(st_spi->port_no)->st.bf.kdrv_ssp_sspstatus.TFVE);
|
|
kdrv_ssp_rx_polling_receive_all( st_spi );
|
|
kdrv_ssp_set_tx_done_flag(st_spi);
|
|
|
|
// if( rx_all != 1)
|
|
// {
|
|
kdrv_ssp_clear_rx_buf_index( st_spi );
|
|
// }
|
|
|
|
for ( i = 0; i < rx_target_size; i++ )
|
|
{
|
|
kdrv_ssp_write_byte_new( st_spi->port_no , (uint8_t *)&dummy );
|
|
if( ( i % (SPI_MAX_FIFO/2) ) != 0 )
|
|
{
|
|
continue;
|
|
}
|
|
// while( ( inw(st_spi->port_no + SSP_REG_STS)& (0x3F<<12) ) != 0 );
|
|
// kdrv_ssp_rx_polling_receive_all(st_spi);
|
|
while(regSSP0_ctrl(st_spi->port_no)->st.bf.kdrv_ssp_sspstatus.TFVE > SPI_TX_FIFO_TH);
|
|
kdrv_ssp_rx_read_fifo_partial(st_spi);
|
|
}
|
|
|
|
while(regSSP0_ctrl(st_spi->port_no)->st.bf.kdrv_ssp_sspstatus.TFVE);
|
|
while(regSSP0_ctrl(st_spi->port_no)->st.bf.kdrv_ssp_sspstatus.BUSY);
|
|
kdrv_ssp_spi_CS_set(chip_select_pin, SPI_CS_HI);
|
|
kdrv_ssp_rx_polling_receive_all(st_spi);
|
|
}
|
|
|
|
|
|
|
|
enum e_spi kdrv_ssp_statemachine( kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *st_spi, enum e_spi espi_flow, ARM_SPI_SignalEvent_t cb )
|
|
{
|
|
st_spi->eflow = espi_flow;
|
|
|
|
switch( st_spi->eflow )
|
|
{
|
|
case e_spi_init_slave:
|
|
{
|
|
kdrv_ssp_spi_slave_initialize( handle, st_spi );
|
|
kdrv_ssp_spi_open( handle, st_spi, SPI_MODE_0, cb );
|
|
st_spi->eflow = e_spi_idle;
|
|
return e_spi_ret_init_done;
|
|
}
|
|
// break;
|
|
case e_spi_init_master:
|
|
{
|
|
kdrv_ssp_spi_master_initialize( handle, st_spi );
|
|
kdrv_ssp_spi_open( handle, st_spi, SPI_MODE_0, NULL );
|
|
st_spi->eflow = e_spi_idle;
|
|
return e_spi_ret_init_done;
|
|
}
|
|
// break;
|
|
case e_spi_enable:
|
|
{
|
|
st_spi->pre_size = 0;
|
|
kdrv_ssp_api_spi_enable(handle, st_spi);
|
|
st_spi->eflow = e_spi_idle;
|
|
return e_spi_ret_enable_done;
|
|
}
|
|
// break;
|
|
case e_spi_rx:
|
|
{
|
|
st_spi->eflow = e_spi_idle;
|
|
|
|
if( /*st_spi->pre_size == 0 ||*/ st_spi->pre_size != st_spi->Rx_buffer_index )
|
|
{
|
|
st_spi->pre_size = st_spi->Rx_buffer_index;
|
|
//delay_us(20);
|
|
kdrv_delay_us(10);
|
|
|
|
return e_spi_ret_rxbusy;
|
|
}
|
|
else
|
|
{
|
|
st_spi->pre_size = 0;
|
|
//no data to be updated
|
|
//read the remaining data in the FIFO
|
|
kdrv_ssp_rx_polling_receive_all( st_spi );
|
|
//for( i = 0; i< (st_spi->Rx_buffer_index) ; i++ ){
|
|
// *( st_spi->Rx_tempbuffer + st_spi->Rx_tempbuffer_index + i )= *( st_spi->Rx_buffer + i );
|
|
//}
|
|
//st_spi->Rx_tempbuffer_index = st_spi->Rx_tempbuffer_index + (st_spi->Rx_buffer_index);
|
|
return e_spi_ret_rxdone;
|
|
}
|
|
//return e_spi_ret_rxbusy;
|
|
}
|
|
// break;
|
|
case e_spi_txrx_reinit:
|
|
{
|
|
kdrv_ssp_clear_rxhw(handle);
|
|
kdrv_ssp_clear_txhw(handle);
|
|
kdrv_ssp_clear_rx_buf_index(st_spi);
|
|
kdrv_ssp_clear_tx_buf_index(st_spi);
|
|
kdrv_ssp_clear_tx_current_buf_index(st_spi);
|
|
kdrv_ssp_clear_tx_done_flag(st_spi);
|
|
return e_spi_ret_init_done;
|
|
}
|
|
// break;
|
|
case e_spi_rx_check:
|
|
{
|
|
st_spi->eflow = e_spi_idle;
|
|
|
|
//check packet reliability
|
|
if( kdrv_ssp_SPI_XOR_check( st_spi ) == 1 )
|
|
{
|
|
return e_spi_ret_rx_xor_OK; //data is correct
|
|
}
|
|
else
|
|
{
|
|
return e_spi_ret_rx_xor_error ; //data is in-correct
|
|
}
|
|
}
|
|
//break;
|
|
case e_spi_tx:
|
|
{
|
|
kdrv_ssp_api_spi_disable( handle, st_spi );
|
|
kdrv_ssp_clear_rxhw( handle );
|
|
kdrv_ssp_clear_txhw( handle );
|
|
kdrv_ssp_clear_tx_current_buf_index( st_spi );
|
|
kdrv_ssp_clear_tx_done_flag( st_spi );
|
|
|
|
//kdrv_ssp_write_buff( st_spi, temp_buffer, temp_buffer_index ); //for future use
|
|
kdrv_ssp_pre_write_to_fifo( st_spi, 16 );
|
|
kdrv_ssp_api_spi_enable(handle, st_spi);
|
|
|
|
st_spi->eflow = e_spi_idle;
|
|
return e_spi_ret_txbusy;
|
|
}
|
|
// break;
|
|
case e_spi_tx_status_check:
|
|
{
|
|
st_spi->eflow = e_spi_idle;
|
|
|
|
if(kdrv_ssp_tx_fifo_waiting_cnt(handle)==0)
|
|
{
|
|
#ifdef COM_BUS_RESPONSE_REQUEST_PIN
|
|
if (stCom_type.flags == KL520_COM_HAS_ADDITIONAL_IO)
|
|
{
|
|
kdrv_ssp_slave_request_inactive();
|
|
}
|
|
#endif
|
|
return e_spi_ret_txdone;
|
|
}
|
|
else
|
|
{
|
|
return e_spi_ret_txbusy;
|
|
}
|
|
}
|
|
// break;
|
|
case e_spi_master_tx_rx:
|
|
|
|
|
|
break;
|
|
|
|
case e_spi_disable:
|
|
{
|
|
kdrv_ssp_api_spi_disable( handle, st_spi );
|
|
st_spi->eflow = e_spi_idle;
|
|
return e_spi_ret_disableDone;
|
|
}
|
|
// break;
|
|
case e_spi_tx_xor:
|
|
kdrv_ssp_SPI_XOR_clc( st_spi );
|
|
|
|
return e_spi_ret_tx_xor_done;
|
|
case e_spi_idle:
|
|
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
|
|
return e_spi_ret_idle;
|
|
}
|
|
|
|
|
|
void kdrv_ssp_slave_request_init(void)
|
|
{
|
|
#ifdef COM_BUS_RESPONSE_REQUEST_PIN
|
|
uint32_t data;
|
|
//init GPIO as Output low
|
|
|
|
//Please modify gpio pin assignment as your real design
|
|
//LC_Data[14]
|
|
data = inw(SCU_EXTREG_PA_BASE + 0x174);
|
|
data &= 0xFFFFFFF8; //clear low 3bit
|
|
outw(SCU_EXTREG_PA_BASE + 0x174, data | 0x3);
|
|
|
|
kdrv_gpio_set_attribute( COM_BUS_RESPONSE_REQUEST_PIN , GPIO_DIR_OUTPUT );
|
|
kdrv_gpio_write_pin( COM_BUS_RESPONSE_REQUEST_PIN, 0 );
|
|
#endif
|
|
}
|
|
|
|
void kdrv_ssp_spi_loopback_test(bool en)
|
|
{
|
|
regSSP0_ctrl(driver_ssp_ctx.port_no)->st.bf.kdrv_ssp_sspcr0.LBM=en; //please set to 0 if not test in loop back mode
|
|
}
|
|
|
|
void kdrv_ssp_write_tx_buffer( struct st_ssp_spi *sspsw, uint8_t *src_ptr, uint32_t size )
|
|
{
|
|
int32_t i = 0;
|
|
sspsw->Tx_buffer_index = 0;
|
|
|
|
for(i = 0; i < size; i++ )
|
|
{
|
|
*(sspsw->Tx_buffer + sspsw->Tx_buffer_index) = *(src_ptr+i);
|
|
sspsw->Tx_buffer_index = sspsw->Tx_buffer_index+1;
|
|
}
|
|
}
|
|
|