Files
TAIXIN/sdk/driver/spi/hgspi_v3.c

1559 lines
43 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file hgspi_v3.c
* @author bxd
* @brief normal spi
* @version
* TXW81X
* @date 2023-08-02
*
* @copyright Copyright (c) 2023
*
*/
#include "typesdef.h"
#include "list.h"
#include "errno.h"
#include "dev.h"
#include "osal/irq.h"
#include "osal/string.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "dev/spi/hgspi_v3.h"
#include "hgspi_v3_hw.h"
/**********************************************************************************/
/* SPI LOW LAYER FUNCTION */
/**********************************************************************************/
static int32 hgspi_v3_switch_hal_work_mode(enum spi_work_mode work_mode) {
switch (work_mode) {
case (SPI_MASTER_MODE ):
return 0;
break;
case (SPI_SLAVE_MODE ):
return 1;
break;
case (SPI_SLAVE_FSM_MODE):
return 2;
break;
default:
return -1;
break;
}
}
static int32 hgspi_v3_switch_hal_wire_mode(enum spi_wire_mode wire_mode) {
switch (wire_mode) {
case (SPI_WIRE_NORMAL_MODE):
return 0;
break;
case (SPI_WIRE_SINGLE_MODE):
return 1;
break;
case (SPI_WIRE_DUAL_MODE ):
return 2;
break;
case (SPI_WIRE_QUAD_MODE ):
return 3;
break;
default:
return -1;
break;
}
}
static int32 hgspi_v3_switch_hal_clk_mode(enum spi_wire_mode clk_mode) {
switch (clk_mode) {
case (SPI_CPOL_0_CPHA_0):
return 0;
break;
case (SPI_CPOL_0_CPHA_1):
return 1;
break;
case (SPI_CPOL_1_CPHA_0):
return 2;
break;
case (SPI_CPOL_1_CPHA_1):
return 3;
break;
default:
return -1;
break;
}
}
static inline void hgspi_v3_disable(struct hgspi_v3_hw *p_spi)
{
p_spi->CON1 &= ~LL_SPI_CON1_SSP_EN;
}
static inline void hgspi_v3_enable(struct hgspi_v3_hw *p_spi)
{
p_spi->CON1 |= LL_SPI_CON1_SSP_EN;
}
static inline void hgspi_v3_set_dir_tx(struct hgspi_v3_hw *p_spi)
{
p_spi->CON1 |= LL_SPI_CON1_TX_EN;
}
static inline void hgspi_v3_set_dir_rx(struct hgspi_v3_hw *p_spi)
{
p_spi->CON1 &= ~LL_SPI_CON1_TX_EN;
}
/**
* @brief SPI module test whether spi is send over function
* @param p_spi : Select the initialized SPI module pointer
* @retval 1 : over
* 0 : not over
*/
static inline int32 hgspi_v3_get_tx_fifo_empty(struct hgspi_v3_hw *p_spi)
{
return ((p_spi->STA1 & LL_SPI_STA_BUF_EMPTY_PENDING) != 0);
}
/**
* @brief SPI module test whether spi is busy function
* @param p_spi : Select the initialized SPI module pointer
* @retval 1 : busy
* 0 : not busy
*/
static inline int32 hgspi_v3_get_busy(struct hgspi_v3_hw *p_spi)
{
return ((p_spi->STA1 & LL_SPI_STA_SSP_BUSY_PENDING) != 0);
}
/**
* @brief SPI module wait spi send over function
* @param p_spi : Select the initialized SPI module pointer
* @retval None
*/
static inline void hgspi_v3_wait_tx_done(struct hgspi_v3_hw *p_spi)
{
while (!hgspi_v3_get_tx_fifo_empty(p_spi));
while (hgspi_v3_get_busy(p_spi));
}
/**
* @brief SPI module test whether spi is ready to receive function
* @param p_spi : Select the initialized SPI module pointer
* @retval 1 : ready
* 0 : not ready
*/
static inline int32 hgspi_v3_get_rx_ready_sta(struct hgspi_v3_hw *p_spi)
{
return (!(p_spi->STA1 & LL_SPI_STA_BUF_EMPTY_PENDING));
}
/**
* @brief SPI module read data from spi receive fifo function
* @param p_spi : Select the initialized SPI module pointer
* @retval data received
*/
static inline int32 hgspi_v3_get_data(struct hgspi_v3_hw *p_spi)
{
return (int32_t)p_spi->CMD_DATA;
}
static inline void hgspi_v3_set_data(struct hgspi_v3_hw *p_spi, uint32 data)
{
p_spi->CMD_DATA = data;
}
/**
* @brief receive one char from spi in poll method, blocked function
* @param[in] p_spi : spi register structure pointer
* @retval data received by the spi
*/
static inline int32 hgspi_v3_poll_rcv_dat(struct hgspi_v3_hw *p_spi)
{
hgspi_v3_set_dir_rx(p_spi);
/** wait until spi is ready to receive */
while (!hgspi_v3_get_rx_ready_sta(p_spi)); /* blocked */
/** receive data */
return hgspi_v3_get_data(p_spi);
}
/**
* @brief Set spi mode
* @param p_spi : spi register structure pointer
* @param mode : TYPE_ENUM_LL_SPI_MODE
* @retval None
*/
static inline void hgspi_v3_set_mode(struct hgspi_v3_hw *p_spi, uint32 mode)
{
hgspi_v3_wait_tx_done(p_spi);
hgspi_v3_disable(p_spi);
p_spi->CON0 = (p_spi->CON0 &~ LL_SPI_CON0_SPI_MODE(0x3)) | (mode);
hgspi_v3_enable(p_spi);
}
/**
* @brief SPI module test whether spi is ready to send function
* @param p_spi : Select the initialized SPI module pointer
* @retval 1 : ready
* 0 : not ready
*/
static inline uint32 hgspi_v3_get_tx_ready_sta(struct hgspi_v3_hw *p_spi)
{
return (!(p_spi->STA1 & LL_SPI_STA_BUF_FULL_PENDING));
}
/**
* @brief send char by spi in poll method, blocked function
* @param[in] p_spi : spi register structure pointer
* @param[in] data data to be sent
*/
static inline void hgspi_v3_poll_send_dat(struct hgspi_v3_hw *p_spi, uint32 data)
{
hgspi_v3_set_dir_tx(p_spi);
/** wait until spi is ready to send */
while (!hgspi_v3_get_tx_ready_sta(p_spi)); /* blocked */
/** send char */
hgspi_v3_set_data(p_spi, data);
}
/**
* @brief Low layer SPI sets wire mode
* @param p_spi : The structure pointer of the SPI group is selected
* @param wire_mode: The wire mode to be set
* @retval None
*/
static int32 hgspi_v3_set_wire_mode(struct hgspi_v3_hw *p_spi, uint32 wire_mode)
{
hgspi_v3_wait_tx_done(p_spi);
hgspi_v3_disable(p_spi);
p_spi->CON0 = (p_spi->CON0 & (~ LL_SPI_CON0_WIRE_MODE(0x3))) | LL_SPI_CON0_WIRE_MODE(wire_mode);
hgspi_v3_enable(p_spi);
return RET_OK;
}
/**
* @brief Low layer SPI gets wire mode
* @param p_spi : The structure pointer of the SPI group (SPI0, SPI1) is selected
* @retval Return the spi wire mode
*/
static uint32 hgspi_v3_get_wire_mode(struct hgspi_v3_hw *p_spi)
{
return LL_SPI_CON0_WIRE_MODE_GET(p_spi->CON0);
}
static int32 hgspi_v3_set_frame_size(struct hgspi_v3_hw *p_spi, uint32 frame_size) {
if (frame_size < 0 || frame_size > 32) {
return -EINVAL;
}
hgspi_v3_disable(p_spi);
p_spi->CON0 = (p_spi->CON0 &~ LL_SPI_CON0_FRAME_SIZE(0x3F)) | LL_SPI_CON0_FRAME_SIZE(frame_size);
hgspi_v3_enable(p_spi);
return RET_OK;
}
//Understand it as a host(spi slave fsm mode)
static inline int32 hgspi_v3_spi_slave_fsm_get_rx_done_sta(struct hgspi_v3_hw *p_spi) {
return (p_spi->SLAVESTA & LL_SPI_SLAVE_STA_TX_READY_FLG) ? FALSE : TRUE;
}
//Understand it as a host(spi slave fsm mode)
static inline void hgspi_v3_spi_slave_fsm_set_rx_ready_sta(struct hgspi_v3_hw *p_spi, uint32 len) {
p_spi->SLAVESTA &= ~ LL_SPI_SLAVE_STA_TX_LEN(0xFF);
p_spi->SLAVESTA |= LL_SPI_SLAVE_STA_TX_LEN(len - 1) |
LL_SPI_SLAVE_STA_TX_READY_EN |
LL_SPI_SLAVE_STA_TX_READY_FLG;
}
//Understand it as a host(spi slave fsm mode)
static inline int32 hgspi_v3_spi_slave_fsm_get_tx_done_sta(struct hgspi_v3_hw *p_spi) {
return (p_spi->SLAVESTA & LL_SPI_SLAVE_STA_RX_READY_FLG) ? FALSE : TRUE;
}
//Understand it as a host(spi slave fsm mode)
static inline void hgspi_v3_spi_slave_fsm_set_tx_ready_sta(struct hgspi_v3_hw *p_spi, uint32 len) {
p_spi->SLAVESTA &= ~ LL_SPI_SLAVE_STA_RX_LEN(0xFF);
p_spi->SLAVESTA |= LL_SPI_SLAVE_STA_RX_LEN(len - 1) |
LL_SPI_SLAVE_STA_RX_READY_EN |
LL_SPI_SLAVE_STA_RX_READY_FLG;
}
static inline int32 hgspi_v3_spi_set_len_threshold(struct hgspi_v3 *p_spi, uint16 len_threshold) {
p_spi->len_threshold = len_threshold;
return RET_OK;
}
static inline void hgspi_v3_set_cs(struct hgspi_v3_hw *p_spi, uint32 value)
{
if (value) {
p_spi->CON0 |= LL_SPI_CON0_NSS_HIGH;
} else {
p_spi->CON0 &= ~LL_SPI_CON0_NSS_HIGH;
}
}
static inline int32 hgspi_v3_complete(struct hgspi_v3 *p_spi)
{
struct hgspi_v3 *dev = p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
/* spi tx */
if (hw->CON1 & LL_SPI_CON1_TX_EN) {
/* spi slave */
if (hw->CON1 & LL_SPI_CON1_MODE(1)) {
/* SPI slave use dma transfer, so dma done pending is 1, transfer has done */
/* SPI slave detect cs rising, so transfer has done when cs rising */
while ((!(hw->STA1 & LL_SPI_STA_NSS_POS_PENDING)) && (!(dev->spi_tx_done)));
hw->STA1 = LL_SPI_STA_NSS_POS_PENDING;
dev->spi_tx_done = 0;
}
/* spi master */
else if (!(hw->CON1 & LL_SPI_CON1_MODE(1))) {
while (!(dev->spi_tx_done));
dev->spi_tx_done = 0;
}
}
/* spi rx */
else {
/* spi slave */
if (hw->CON1 & LL_SPI_CON1_MODE(1)) {
/* SPI slave use dma transfer, so dma done pending is 1, transfer has done */
/* SPI slave detect cs rising, so transfer has done when cs rising */
while ((!(hw->STA1 & LL_SPI_STA_NSS_POS_PENDING)) && (!(dev->spi_rx_done)));
hw->STA1 = LL_SPI_STA_NSS_POS_PENDING;
dev->spi_rx_done = 0;
}
/* spi master */
else if (!(hw->CON1 & LL_SPI_CON1_MODE(1))) {
while (!(dev->spi_rx_done));
dev->spi_rx_done = 0;
}
}
return RET_OK;
}
static int32 hgspi_v3_cs(struct hgspi_v3 *dev, uint32 cs, uint32 value)
{
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hgspi_v3_set_cs(hw, value);
return RET_OK;
}
static int32 hgspi_v3_set_cfg_none_cs(struct hgspi_v3 *dev, uint32 enable) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (enable) {
hw->CON0 = (hw->CON0) &~ (LL_SPI_CON0_NSS_PIN_EN);
} else {
hw->CON0 |= (LL_SPI_CON0_NSS_PIN_EN);
}
return RET_OK;
}
static int32 hgspi_v3_read_dma_rx_cnt(struct hgspi_v3 *dev, uint32 *cnt_buf) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (!cnt_buf) {
return RET_ERR;
}
*cnt_buf = hw->RDMACNT;
return RET_OK;
}
static int32 hgspi_v3_kick_dma_rx(struct hgspi_v3 *dev, uint32 *rx_buf, uint32 len) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!rx_buf) || (!len)) {
return RET_ERR;
}
/*
*硬件要求:
*为防止内部8bit移位器残留bit影响后续正常接发
*软件清除buf_cnt
*/
hw->STA1 = LL_SPI_STA_CLR_BUF_CNT;
/*
硬件要求未达到DMA done的情况下重新kick DMA
需要先把DMA的EN关掉
*/
hw->CON1 &= ~ LL_SPI_CON1_DMA_EN;
hw->RDMACNT = 0;
hw->RSTADR = (uint32)rx_buf;
hw->RDMALEN = len;
hgspi_v3_set_dir_rx(hw);
hw->CON1 |= LL_SPI_CON1_DMA_EN;
return RET_OK;
}
static int32 hgspi_v3_kick_dma_tx(struct hgspi_v3 *dev, uint32 *tx_buf, uint32 len) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!tx_buf) || (!len)) {
return RET_ERR;
}
/*
*硬件要求:
*为防止内部8bit移位器残留bit影响后续正常接发
*软件清除buf_cnt
*/
hw->STA1 = LL_SPI_STA_CLR_BUF_CNT;
/*
硬件要求未达到DMA done的情况下重新kick DMA
需要先把DMA的EN关掉
*/
hw->CON1 &= ~ LL_SPI_CON1_DMA_EN;
hw->TDMACNT = 0;
hw->TSTADR = (uint32)tx_buf;
hw->TDMALEN = len;
hgspi_v3_set_dir_tx(hw);
hw->CON1 |= LL_SPI_CON1_DMA_EN;
return RET_OK;
}
static int32 hgspi_v3_set_timeout(struct hgspi_v3 *dev, uint32 time) {
dev->timeout = time;
return RET_OK;
}
static int32 hgspi_v3_set_pingpang(struct hgspi_v3 *dev,uint32 enable){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (enable) {
hw->CON1 |= LL_SPI_CON1_PING_PONG_EN(1);
} else {
hw->CON1 &= ~(LL_SPI_CON1_PING_PONG_EN(1));
}
return RET_OK;
}
static int32 hgspi_v3_set_pingpang_adr0(struct hgspi_v3 *dev,uint32 buf0){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->RSTADR = buf0;
return RET_OK;
}
static int32 hgspi_v3_set_pingpang_adr1(struct hgspi_v3 *dev,uint32 buf1){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->RSTADR1 = buf1;
return RET_OK;
}
static int32 hgspi_v3_set_len(struct hgspi_v3 *dev,uint32 len){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->RDMALEN = len;
return RET_OK;
}
static int32 hgspi_v3_set_line_len(struct hgspi_v3 *dev,uint32 len){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->LINE_LEN = len;
return RET_OK;
}
static int32 hgspi_v3_set_high_speed(struct hgspi_v3 *dev,uint32 cfg){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->CON0 &= ~(LL_SPI_CON0_SPI_HIGH_SPEED(3));
hw->CON0 |= (LL_SPI_CON0_SPI_HIGH_SPEED(cfg));
return RET_OK;
}
static int32 hgspi_v3_kick_dma(struct hgspi_v3 *dev){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->CON1 |= LL_SPI_CON1_DMA_EN;
return RET_OK;
}
static int32 hgspi_v3_rxtimeout_cfg(struct hgspi_v3 *dev,uint32 enable,uint32 timeout){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if(enable){
hw->RXTIMEOUTCON |= (hw->RXTIMEOUTCON &~ (0x1fffffff<<1)) | (timeout<<1);
hw->RXTIMEOUTCON |= BIT(0);
}else{
hw->RXTIMEOUTCON &= ~BIT(0);
}
return RET_OK;
}
static int32 hgspi_v3_set_vsync_timeout(struct hgspi_v3 *dev,uint32 timeout){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->VSYNC_TCON &= ~(0x1fffff<<8);
hw->VSYNC_TCON |= (timeout<<8);
return RET_OK;
}
static int32 hgspi_v3_set_hsync_timeout(struct hgspi_v3 *dev,uint32 timeout){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->HSYNC_TCON &= ~(0xffff<<8);
hw->HSYNC_TCON |= (timeout<<8);
return RET_OK;
}
static int32 hgspi_v3_set_vsync_head(struct hgspi_v3 *dev,uint32 head){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->VSYNC_TCON &= ~(0x3f<<1);
hw->VSYNC_TCON |= (head<<1);
return RET_OK;
}
static int32 hgspi_v3_set_hsync_head(struct hgspi_v3 *dev,uint32 head){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
hw->HSYNC_TCON &= ~(0x3f<<0);
hw->HSYNC_TCON |= (head<<0);
return RET_OK;
}
static int32 hgspi_v3_set_vsync_en(struct hgspi_v3 *dev,uint32 enable){
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (enable) {
hw->VSYNC_TCON |= BIT(0);
} else {
hw->VSYNC_TCON &= ~BIT(0);
}
return RET_OK;
}
static int32 hgspi_v3_set_lsb_first(struct hgspi_v3 *dev, uint32 enable) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (enable) {
hw->CON0 |= LL_SPI_CON0_LSB_FIRST;
} else {
hw->CON0 &= ~LL_SPI_CON0_LSB_FIRST;
}
return RET_OK;
}
static int32 hgspi_v3_set_slave_sw_reserved(struct hgspi_v3 *dev, uint32 enable) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (enable) {
hw->SLAVESTA |= LL_SPI_SLAVE_STA_SW_RESERVED;
} else {
hw->SLAVESTA &= ~LL_SPI_SLAVE_STA_SW_RESERVED;
}
return RET_OK;
}
static int32 hgspi_v3_get_dma_pending(struct hgspi_v3 *dev) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((hw->STA1 & LL_SPI_STA_DMA_PENDING))
return TRUE;
else
return FALSE;
}
static int32 hgspi_v3_clear_dma_pending(struct hgspi_v3 *dev, uint32 enable) {
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw*)dev->hw;
if(enable) {
hw->STA1 = LL_SPI_STA_DMA_PENDING;
}
return RET_OK;
}
/**********************************************************************************/
/* SPI ATTCH FUNCTION */
/**********************************************************************************/
static int32 hgspi_v3_open(struct spi_device *p_spi, uint32 clk_freq, uint32 work_mode,uint32 wire_mode, uint32 clk_mode) {
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
uint32 con0_reg = 0;
uint32 con1_reg = 0;
uint32 clk_div_cnt;
int32 work_mode_to_reg;
int32 wire_mode_to_reg;
int32 clk_mode_to_reg ;
if (dev->opened) {
if (!dev->dsleep) {
return -EBUSY;
}
}
/* hal enum */
work_mode_to_reg = hgspi_v3_switch_hal_work_mode(work_mode);
wire_mode_to_reg = hgspi_v3_switch_hal_wire_mode(wire_mode);
clk_mode_to_reg = hgspi_v3_switch_hal_clk_mode(clk_mode );
if (((-1) == work_mode_to_reg) || \
((-1) == wire_mode_to_reg) || \
((-1) == clk_mode_to_reg )) {
return -EINVAL;
}
/* pin config */
if(pin_func(p_spi->dev.dev_id, 1) != RET_OK) {
return RET_ERR;
}
/*
* open SPI clk
*/
if (SPI0_BASE == (uint32)hw) {
sysctrl_spi0_clk_open();
sysctrl_display_clk_open();
} else if (SPI1_BASE == (uint32)hw) {
sysctrl_spi1_clk_open();
sysctrl_display_clk_open();
} else if (SPI2_BASE == (uint32)hw) {
sysctrl_spi2_clk_open();
}
/* clear reg */
hw->CON0 = 0;
hw->CON1 = 0;
hw->TIMECON = 0;
hw->TDMALEN = 0;
hw->RDMALEN = 0;
hw->TSTADR = 0;
hw->RSTADR = 0;
hw->SLAVESTA = 0;
hgspi_v3_disable(hw);
con0_reg = LL_SPI_CON0_SPI_MODE(clk_mode_to_reg ) | //clk mode
LL_SPI_CON0_WIRE_MODE(wire_mode_to_reg) | //wire mode
((work_mode_to_reg == 2) ? (LL_SPI_CON0_SLAVE_STATE_EN):(0UL)) | //slave fsm mode
LL_SPI_CON0_FRAME_SIZE(8) | //frame size
LL_SPI_CON0_SSOE(1) | //nss io_oe enable
LL_SPI_CON0_NSS_PIN_EN;
con1_reg = LL_SPI_CON1_SPI_I2C_SEL(0x0) |
((work_mode_to_reg == 2) ? (LL_SPI_CON1_MODE(1)) : LL_SPI_CON1_MODE(work_mode_to_reg));
hw->CON0 = con0_reg ;
hw->CON1 = con1_reg ;
hw->STA1 = 0xFFFFFFFF;
/* only master mode need config clk */
if (work_mode_to_reg == 0) {
/* set spi clk */
int temp = 0;
if (SPI0_BASE == (uint32)hw) {
temp = HG_APB0_PT_SPI0;
} else if (SPI1_BASE == (uint32)hw) {
temp = HG_APB0_PT_SPI1;
} else if (SPI2_BASE == (uint32)hw) {
temp = HG_APB0_PT_SPI2;
}
clk_div_cnt = peripheral_clock_get(temp) / 2 / clk_freq - 1;
ASSERT((clk_div_cnt >= 0) && (clk_div_cnt <= 65535));
hw->TIMECON = (hw->TIMECON &~ (LL_SPI_TIMECON_BAUD(0xFFFF))) | LL_SPI_TIMECON_BAUD(clk_div_cnt);
}
if (!(hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN)) {
/* open dma done interrupt for write&read func */
hw->CON1 |= LL_SPI_CON1_DMA_IE_EN;
}
irq_enable(dev->irq_num);
/* set CS high */
hgspi_v3_set_cs(hw, 1);
/* enable spi */
hgspi_v3_enable(hw);
dev->opened = 1;
dev->dsleep = 0;
/* config default tx&rx len threshold, uint:byte */
dev->len_threshold = 16;
/* other config init */
dev->spi_irq_flag_rx_done = 0;
dev->spi_irq_flag_tx_done = 0;
dev->spi_tx_done = 0;
dev->spi_rx_done = 0;
dev->spi_tx_async = 0;
dev->spi_rx_async = 0;
dev->timeout = osWaitForever;
return RET_OK;
}
static int32 hgspi_v3_close(struct spi_device *p_spi) {
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if (!dev->opened) {
return RET_OK;
}
/*
* close SPI clk
*/
if (SPI0_BASE == (uint32)hw) {
sysctrl_spi0_clk_close();
} else if (SPI1_BASE == (uint32)hw) {
sysctrl_spi1_clk_close();
} else if (SPI2_BASE == (uint32)hw) {
sysctrl_spi2_clk_close();
}
irq_disable(dev->irq_num );
pin_func(p_spi->dev.dev_id, 0);
hgspi_v3_set_cs(hw, 1);
hgspi_v3_disable(hw );
dev->opened = 0;
dev->dsleep = 0;
/* Just to be sure: config again default tx&rx len threshold when close, uint:byte */
dev->len_threshold = 16;
/* other setting clear */
dev->spi_irq_flag_rx_done = 0;
dev->spi_irq_flag_tx_done = 0;
dev->spi_tx_done = 0;
dev->spi_rx_done = 0;
dev->spi_tx_async = 0;
dev->spi_rx_async = 0;
dev->timeout = osWaitForever;
return RET_OK;
}
static int32 hgspi_v3_write(struct spi_device *p_spi, const void *buf, uint32 size) {
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
uint32 frame_size, index, data;
uint32 num, addr;
if ((!dev->opened) || (dev->dsleep)) {
return RET_ERR;
}
/* if mode is slave fsm mode */
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
/* 发送异常退出会卡住下一次发送 */
//while (!hgspi_v3_spi_slave_fsm_get_tx_done_sta(hw));
hw->TDMACNT = 0;
/* 清掉BUF cnt对于slave fsm模式有影响因为不知道接收时刻写清除buf会影响可能正在接收的过程 */
//hw->STA = LL_SPI_STA_CLEAR_BUF_CNT;
hw->TDMALEN = size;
hw->TSTADR = (uint32)buf;
hgspi_v3_spi_slave_fsm_set_tx_ready_sta(hw, size/8);
return RET_OK;
}
os_mutex_lock(&dev->os_spi_lock, osWaitForever);
/* Clear the last cs rising pending */
hw->STA1 = LL_SPI_STA_NSS_POS_PENDING;
/* Clear the rx_dma cnt & tx_dma_cnt */
hw->TDMACNT = 0;
/* 清掉BUF cnt */
hw->STA1 = LL_SPI_STA_CLEAR_BUF_CNT;
/* clear the tx done pending */
dev->spi_tx_done = 0;
dev->spi_tx_async = 0;
hgspi_v3_set_dir_tx(hw);
/* len <= 5(default) use cpu tx dev->tx_len_threshold*/
if ((size <= dev->len_threshold) && (!__in_interrupt())) {
/* if mode == slave, use dma tx */
if (hw->CON1 & LL_SPI_CON1_MODE(1)) {
goto hgspi_v3_dma_tx;
}
addr = (uint32)buf;
frame_size = LL_SPI_CON0_GET_FRAME_SIZE(hw->CON0);
index = (frame_size > 8) + (frame_size > 16);
num = size >> index;
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 0);
while(num--) {
switch(index) {
case 0:
data = *(uint8 *)addr;
break;
case 1:
data = *(uint16 *)addr;
break;
default:
data = *(uint32 *)addr;
break;
}
addr += 1<<index;
while(!hgspi_v3_get_tx_ready_sta(hw));
hgspi_v3_set_data(hw, data);
}
/* Only required for the master mode */
if(!LL_SPI_CON1_GET_MODE(hw->CON1)) {
hgspi_v3_wait_tx_done(hw);
}
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 1);
/* cpu tx done irq handle */
if (dev->spi_irq_flag_tx_done) {
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_TX_DONE, dev->irq_data, (uint32)buf, size);
}
}
}
/* len > 5(default) use dma tx*/
else {
hgspi_v3_dma_tx:
while (hw->STA1 & LL_SPI_STA_SSP_BUSY_PENDING);
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 0);
dev->spi_tx_async = 1;
hw->TSTADR = (uint32)buf;
hw->TDMALEN = size;
hw->CON1 |= LL_SPI_CON1_DMA_EN;
#if 0
//using semaphore for waiting tx done
os_sema_down(&dev->os_spi_tx_done, osWaitForever);
#else
/* others: using semaphore to wait */
if (1) {
//using semaphore for waiting tx done
os_sema_down(&dev->os_spi_tx_done, dev->timeout);
///dev->irq_hdl(SPI_IRQ_FLAG_TX_DONE, dev->irq_data, buf, size);
}
/* 0: using while to wait */
else {
dev->spi_tx_async = 0;
hgspi_v3_complete(dev);
}
#endif
}
/* 防止timeout后突然来数据触发dma中断 */
/* 正常接收接收完成,写它没有事 */
hw->CON1 &= ~LL_SPI_CON1_DMA_EN;
os_mutex_unlock(&dev->os_spi_lock);
return RET_OK;
}
static int32 hgspi_v3_read(struct spi_device *p_spi, void *buf, uint32 size) {
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
uint32 frame_size, index, data;
uint32 num, addr;
if ((!dev->opened) || (dev->dsleep)) {
return RET_ERR;
}
/* if mode is slave fsm mode */
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
/* 接收异常退出会卡住下一次接收 */
//while (!hgspi_v3_spi_slave_fsm_get_rx_done_sta(hw));
hw->RDMACNT = 0;
/* 清掉BUF cnt对于slave fsm模式有影响因为不知道接收时刻写清除buf会影响可能正在接收的过程 */
//hw->STA = LL_SPI_STA_CLEAR_BUF_CNT;
hw->RDMALEN = size;
hw->RSTADR = (uint32)buf;
hgspi_v3_spi_slave_fsm_set_rx_ready_sta(hw, size/8);
return RET_OK;
}
os_mutex_lock(&dev->os_spi_lock, osWaitForever);
/* Clear the last cs rising pending */
hw->STA1 = LL_SPI_STA_NSS_POS_PENDING;
/* Clear the rx_dma cnt & tx_dma_cnt */
hw->RDMACNT = 0;
/* 清掉BUF cnt */
hw->STA1 = LL_SPI_STA_CLEAR_BUF_CNT;
/* clear the rx done pending */
dev->spi_rx_done = 0;
dev->spi_rx_async = 0;
hgspi_v3_set_dir_rx(hw);
/* len <= 5(default) use cpu tx dev->tx_len_threshold*/
if ((size <= dev->len_threshold) && (!__in_interrupt())) {
/* if mode == slave, use dma rx */
if (hw->CON1 & LL_SPI_CON1_MODE(1)) {
goto hgspi_v3_dma_rx;
}
addr = (uint32)buf;
frame_size = LL_SPI_CON0_GET_FRAME_SIZE(hw->CON0);
index = (frame_size > 8) + (frame_size > 16);
num = size >> index;
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 0);
/* Only required for the master mode */
if(!LL_SPI_CON1_GET_MODE(hw->CON1)) {
hw->RDMALEN = LL_SPI_DMA_RX_LEN(num);
hgspi_v3_set_data(hw, 0x00);
}
while(num--) {
while(!hgspi_v3_get_rx_ready_sta(hw));
data = hgspi_v3_get_data(hw);
switch(index) {
case 0:
*(uint8 *)addr = data;
break;
case 1:
*(uint16 *)addr = data;
break;
default:
*(uint32 *)addr = data;
break;
}
addr += 1<<index;
}
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 1);
/* cpu rx done irq handle */
if (dev->spi_irq_flag_rx_done) {
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_RX_DONE, dev->irq_data, (uint32)buf, size);
}
}
}
/* len > 5(default) use dma tx*/
else {
hgspi_v3_dma_rx:
while (hw->STA1 & LL_SPI_STA_SSP_BUSY_PENDING);
/* Note: "spi slave mode" set cs is invaild, so it is ok */
//hgspi_v3_set_cs(hw, 0);
dev->spi_rx_async = 1;
hw->RSTADR = (uint32)buf;
hw->RDMALEN = size;
hw->CON1 |= LL_SPI_CON1_DMA_EN;
#if 0
//using semaphore for waiting tx done
os_sema_down(&dev->os_spi_rx_done, osWaitForever);
#else
/* others: using semaphore to wait */
if (1) {
//using semaphore for waiting tx done
os_sema_down(&dev->os_spi_rx_done, dev->timeout);
//dev->irq_hdl(SPI_IRQ_FLAG_RX_DONE, dev->irq_data, buf, size);
}
/* 0: using while to wait */
else {
dev->spi_rx_async = 0;
hgspi_v3_complete(dev);
}
#endif
}
/* 防止timeout后突然来数据触发dma中断 */
/* 正常接收接收完成,写它没有事 */
hw->CON1 &= ~LL_SPI_CON1_DMA_EN;
os_mutex_unlock(&dev->os_spi_lock);
return RET_OK;
}
#ifdef CONFIG_SLEEP
static int32 hgspi_v3_suspend(struct dev_obj *obj)
{
struct hgspi_v3 *dev = (struct hgspi_v3 *)obj;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!dev->opened) || (dev->dsleep)) {
return RET_OK;
}
if(os_mutex_lock(&dev->os_spi_lock, osWaitForever)) {
return RET_ERR;
}
if (0 > os_mutex_lock(&dev->bp_suspend_lock, 10000)) {
return RET_ERR;
}
/*!
* Close the SPI
*/
hw->CON1 &= ~ BIT(0);
// pin_func(dev->dev.dev.dev_id, 0);
/*
* close irq
*/
irq_disable(dev->irq_num);
/*
* clear pending
*/
hw->STA1 = 0xFFFFFFFF;
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
/*
* save the reglist
*/
dev->bp_regs.con0 = hw->CON0 ;
dev->bp_regs.con1 = hw->CON1 ;
dev->bp_regs.timecon = hw->TIMECON ;
dev->bp_regs.tdmalen = hw->TDMALEN ;
dev->bp_regs.rdmalen = hw->RDMALEN ;
dev->bp_regs.tstadr = hw->TSTADR ;
dev->bp_regs.rstadr = hw->RSTADR ;
dev->bp_regs.slavesta = hw->SLAVESTA;
/*
* save the irq_hdl created by user
*/
dev->bp_irq_hdl = dev->irq_hdl;
dev->bp_irq_data = dev->irq_data;
/*
* close SPI clk
*/
if (SPI0_BASE == (uint32)hw) {
sysctrl_spi0_clk_close();
} else if (SPI1_BASE == (uint32)hw) {
sysctrl_spi1_clk_close();
} else if (SPI2_BASE == (uint32)hw) {
sysctrl_spi2_clk_close();
}
dev->dsleep = 1;
os_mutex_unlock(&dev->bp_suspend_lock);
return RET_OK;
}
static int32 hgspi_v3_resume(struct dev_obj *obj)
{
struct hgspi_v3 *dev = (struct hgspi_v3 *)obj;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!dev->opened) || (!dev->dsleep)) {
return RET_OK;
}
if (0 > os_mutex_lock(&dev->bp_resume_lock, 10000)) {
return RET_ERR;
}
/* pin config */
// if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
// return RET_ERR;
// }
/*
* recovery the SPI clk
*/
if (SPI0_BASE == (uint32)hw) {
sysctrl_spi0_clk_open();
sysctrl_display_clk_open();
} else if (SPI1_BASE == (uint32)hw) {
sysctrl_spi1_clk_open();
sysctrl_display_clk_open();
} else if (SPI2_BASE == (uint32)hw) {
sysctrl_spi2_clk_open();
}
/*
* recovery the reglist from sram
*/
hw->CON0 = dev->bp_regs.con0 ;
hw->CON1 = dev->bp_regs.con1 ;
hw->TIMECON = dev->bp_regs.timecon ;
hw->TDMALEN = dev->bp_regs.tdmalen ;
hw->RDMALEN = dev->bp_regs.rdmalen ;
hw->TSTADR = dev->bp_regs.tstadr ;
hw->RSTADR = dev->bp_regs.rstadr ;
hw->SLAVESTA = dev->bp_regs.slavesta;
/*
* recovery the irq handle and data
*/
dev->irq_hdl = dev->bp_irq_hdl;
dev->irq_data = dev->bp_irq_data;
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
/*!
* Open the SPI
*/
hw->CON1 |= BIT(0);
/*
* open irq
*/
irq_enable(dev->irq_num);
dev->dsleep = 0;
os_mutex_unlock(&dev->bp_resume_lock);
os_mutex_unlock(&dev->os_spi_lock);
return RET_OK;
}
#endif
static int32 hgspi_v3_ioctl(struct spi_device *p_spi, uint32 cmd, uint32 param1, uint32 param2)
{
int32 ret_val = RET_OK;
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!dev->opened) || (dev->dsleep)) {
return RET_ERR;
}
switch(cmd) {
case (SPI_SET_FRAME_SIZE ):
ret_val = hgspi_v3_set_frame_size(hw, param1);
break;
case (SPI_WIRE_MODE_SET ):
ret_val = hgspi_v3_set_wire_mode(hw , param1);
break;
case (SPI_WIRE_MODE_GET ):
ret_val = hgspi_v3_get_wire_mode(hw);
break;
case (SPI_SET_LEN_THRESHOLD):
ret_val = hgspi_v3_spi_set_len_threshold(dev, param1);
break;
case (SPI_SET_CS):
ret_val = hgspi_v3_cs(dev, param1, param2);
break;
case (SPI_CFG_SET_NONE_CS):
ret_val = hgspi_v3_set_cfg_none_cs(dev, param1);
break;
case (SPI_READ_DMA_RX_CNT):
ret_val = hgspi_v3_read_dma_rx_cnt(dev, (uint32 *)param1);
break;
case (SPI_KICK_DMA_RX):
ret_val = hgspi_v3_kick_dma_rx(dev, (uint32 *)param1, param2);
break;
case (SPI_KICK_DMA_TX):
ret_val = hgspi_v3_kick_dma_tx(dev, (uint32 *)param1, param2);
break;
case (SPI_SET_TIMEOUT):
ret_val = hgspi_v3_set_timeout(dev, param1);
break;
case (SPI_SET_LSB_FIRST):
ret_val = hgspi_v3_set_lsb_first(dev, param1);
break;
case (SPI_SET_SLAVE_SW_RESERVED):
ret_val = hgspi_v3_set_slave_sw_reserved(dev, param1);
break;
case (SPI_SENSOR_PINGPANG_EN):
ret_val = hgspi_v3_set_pingpang(dev, param1);
break;
case (SPI_SENSOR_SET_ADR0):
ret_val = hgspi_v3_set_pingpang_adr0(dev, param1);
break;
case (SPI_SENSOR_SET_ADR1):
ret_val = hgspi_v3_set_pingpang_adr1(dev, param1);
break;
case (SPI_SENSOR_BUF_LEN):
ret_val = hgspi_v3_set_len(dev, param1);
break;
case (SPI_SENSOR_VSYNC_TIMEOUT):
ret_val = hgspi_v3_set_vsync_timeout(dev, param1);
break;
case (SPI_SENSOR_VSYNC_HEAD_CNT):
ret_val = hgspi_v3_set_vsync_head(dev, param1);
break;
case (SPI_SENSOR_HSYNC_TIMEOUT):
ret_val = hgspi_v3_set_hsync_timeout(dev, param1);
break;
case (SPI_SENSOR_HSYNC_HEAD_CNT):
ret_val = hgspi_v3_set_hsync_head(dev, param1);
break;
case (SPI_SENSOR_VSYNC_EN):
ret_val = hgspi_v3_set_vsync_en(dev, param1);
break;
case (SPI_HIGH_SPEED_CFG):
ret_val = hgspi_v3_set_high_speed(dev, param1);
break;
case (SPI_KICK_DMA_EN):
ret_val = hgspi_v3_kick_dma(dev);
break;
case (SPI_RX_TIMEOUT_CFG):
ret_val = hgspi_v3_rxtimeout_cfg(dev,1,param2);
break;
case (SPI_GET_DMA_PENDING):
ret_val = hgspi_v3_get_dma_pending(dev);
break;
case (SPI_CLEAR_DMA_PENDING):
ret_val = hgspi_v3_clear_dma_pending(dev, param1);
break;
case (SPI_SENSOR_LINE_LEN_CFG):
ret_val = hgspi_v3_set_line_len(dev, param1);
break;
default:
ret_val = -ENOTSUPP;
break;
}
return ret_val;
}
/* interrupt handler */
static void hgspi_v3_irq_handler(void *data)
{
struct hgspi_v3 *dev = (struct hgspi_v3 *)data;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((hw->CON1 & LL_SPI_CON1_DMA_IE_EN) && (hw->STA1 & LL_SPI_STA_DMA_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_DMA_PENDING;
/* For spi write&read, Note: "spi slave mode" set cs is invaild */
//hgspi_v3_set_cs(hw, 1);
/* spi transfer done, recording for tx_sync & rx_sync */
if (!dev->spi_rx_async) {
dev->spi_rx_done = 1;
}
if (!dev->spi_tx_async) {
dev->spi_tx_done = 1;
}
//spi module async tx
if (dev->spi_tx_async) {
dev->spi_tx_async = 0;
os_sema_up(&dev->os_spi_tx_done);
}
//spi module async rx
if (dev->spi_rx_async){
dev->spi_rx_async = 0;
os_sema_up(&dev->os_spi_rx_done);
}
if (hw->CON1 & LL_SPI_CON1_TX_EN) {
if (dev->irq_hdl && dev->spi_irq_flag_tx_done) {
dev->irq_hdl(SPI_IRQ_FLAG_TX_DONE, dev->irq_data, BIT(29) | hw->TSTADR, hw->TDMACNT);
}
} else {
if (dev->irq_hdl && dev->spi_irq_flag_rx_done) {
dev->irq_hdl(SPI_IRQ_FLAG_RX_DONE, dev->irq_data, BIT(29) | hw->RSTADR, hw->RDMACNT);
}
}
}
if ((hw->CON1 & LL_SPI_CON1_BUF_OV_IE_EN) && (hw->STA1 & LL_SPI_STA_BUF_OV_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_BUF_OV_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_FIFO_OVERFLOW, dev->irq_data, 0, 0);
}
}
if ((hw->CON1 & LL_SPI_CON1_RX_TIMEOUT_IE(1)) && (hw->STA1 & LL_SPI_STA_RX_TIMEOUT_PEND)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_RX_TIMEOUT_PEND;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_RX_TIMEOUT, dev->irq_data, 0, 0);
}
}
if ((hw->CON0 & LL_SPI_CON0_NSS_POS_IE_EN) && (hw->STA1 & LL_SPI_STA_NSS_POS_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_NSS_POS_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_CS_RISING, dev->irq_data, 0, 0);
}
/* spi salve transfer done when detect cs rising */
if ((hw->CON1 & LL_SPI_CON1_MODE(1))) {
if (!dev->spi_tx_async) {
dev->spi_tx_done = 1;
}
if (!dev->spi_rx_async) {
dev->spi_rx_done = 1;
}
}
}
//// SLAVE FSM IRQ ////
if ((hw->CON0 & LL_SPI_CON0_SLAVE_WRDATA_IE_EN) && (hw->STA1 & LL_SPI_STA_SLAVE_WRDATA_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_SLAVE_WRDATA_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_RX_DONE, dev->irq_data, BIT(29) | hw->TSTADR, hw->TDMACNT);
}
}
if ((hw->CON0 & LL_SPI_CON0_SLAVE_RDDATA_IE_EN) && (hw->STA1 & LL_SPI_STA_SLAVE_RDDATA_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_SLAVE_RDDATA_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_TX_DONE, dev->irq_data, BIT(29) | hw->RSTADR, hw->RDMACNT);
}
}
if ((hw->CON0 & LL_SPI_CON0_SLAVE_RDSTATUS_IE_EN) && (hw->STA1 & LL_SPI_STA_SLAVE_RDSTATUS_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_SLAVE_RDSTATUS_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_SLAVE_FSM_READ_STATUS, dev->irq_data, 0, 0);
}
}
if ((hw->CON0 & LL_SPI_CON0_SLAVE_WRONG_CMD_IE) && (hw->STA1 & LL_SPI_STA_SLAVE_WRONG_CMD_PENDING)) {
/* clear interrupt flag */
hw->STA1 = LL_SPI_STA_SLAVE_WRONG_CMD_PENDING;
if (dev->irq_hdl) {
dev->irq_hdl(SPI_IRQ_FLAG_SLAVE_FSM_WRONG_CMD, dev->irq_data, 0, 0);
}
}
}
static int32 hgspi_v3_request_irq(struct spi_device *p_spi, uint32 irq_flag, spi_irq_hdl irqhdl, uint32 irq_data)
{
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!dev->opened) || (dev->dsleep)) {
return RET_ERR;
}
dev->irq_hdl = irqhdl;
dev->irq_data = irq_data;
request_irq(dev->irq_num, hgspi_v3_irq_handler, dev);
if (irq_flag & SPI_IRQ_FLAG_TX_DONE) {
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
hw->CON0 |= LL_SPI_CON0_SLAVE_RDDATA_IE_EN;
} else {
dev->spi_irq_flag_tx_done = 1;
hw->CON1 |= LL_SPI_CON1_DMA_IE_EN;
}
}
if (irq_flag & SPI_IRQ_FLAG_RX_DONE) {
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
hw->CON0 |= LL_SPI_CON0_SLAVE_WRDATA_IE_EN;
} else {
dev->spi_irq_flag_rx_done = 1;
hw->CON1 |= LL_SPI_CON1_DMA_IE_EN;
}
}
if (irq_flag & SPI_IRQ_FLAG_RX_TIMEOUT) {
hw->CON1 |= LL_SPI_CON1_RX_TIMEOUT_IE(1);
}
if (irq_flag & SPI_IRQ_FLAG_CS_RISING) {
hw->CON1 |= LL_SPI_CON0_NSS_POS_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_FIFO_OVERFLOW) {
hw->CON1 |= LL_SPI_CON1_BUF_OV_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_SLAVE_FSM_READ_STATUS) {
hw->CON0 |= LL_SPI_CON0_SLAVE_RDSTATUS_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_SLAVE_FSM_WRONG_CMD) {
hw->CON0 |= LL_SPI_CON0_SLAVE_WRONG_CMD_IE;
}
irq_enable(dev->irq_num);
return RET_OK;
}
static int32 hgspi_v3_release_irq(struct spi_device *p_spi, uint32 irq_flag)
{
struct hgspi_v3 *dev = (struct hgspi_v3 *)p_spi;
struct hgspi_v3_hw *hw = (struct hgspi_v3_hw *)dev->hw;
if ((!dev->opened) || (dev->dsleep)) {
return RET_ERR;
}
if (irq_flag & SPI_IRQ_FLAG_TX_DONE) {
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
hw->CON0 &= ~LL_SPI_CON0_SLAVE_RDDATA_IE_EN;
} else {
dev->spi_irq_flag_tx_done = 0;
hw->CON1 &= ~ LL_SPI_CON1_DMA_IE_EN;
}
}
if (irq_flag & SPI_IRQ_FLAG_RX_DONE) {
if (hw->CON0 & LL_SPI_CON0_SLAVE_STATE_EN) {
hw->CON0 &= ~LL_SPI_CON0_SLAVE_WRDATA_IE_EN;
} else {
dev->spi_irq_flag_rx_done = 0;
hw->CON1 &= ~ LL_SPI_CON1_DMA_IE_EN;
}
}
if (irq_flag & SPI_IRQ_FLAG_CS_RISING) {
hw->CON1 &= ~ LL_SPI_CON0_NSS_POS_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_FIFO_OVERFLOW) {
hw->CON1 &= ~ LL_SPI_CON1_BUF_OV_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_SLAVE_FSM_READ_STATUS) {
hw->CON0 &= ~ LL_SPI_CON0_SLAVE_RDSTATUS_IE_EN;
}
if (irq_flag & SPI_IRQ_FLAG_SLAVE_FSM_WRONG_CMD) {
hw->CON0 &= ~ LL_SPI_CON0_SLAVE_WRONG_CMD_IE;
}
return RET_OK;
}
static const struct spi_hal_ops spi_v3_ops = {
.open = hgspi_v3_open,
.close = hgspi_v3_close,
.ioctl = hgspi_v3_ioctl,
.read = hgspi_v3_read,
.write = hgspi_v3_write,
.request_irq = hgspi_v3_request_irq,
.release_irq = hgspi_v3_release_irq,
#ifdef CONFIG_SLEEP
.ops.suspend = hgspi_v3_suspend,
.ops.resume = hgspi_v3_resume,
#endif
};
int32 hgspi_v3_attach(uint32 dev_id, struct hgspi_v3 *p_spi)
{
p_spi->opened = 0;
p_spi->dsleep = 0;
p_spi->irq_hdl = NULL;
p_spi->irq_data = 0;
p_spi->timeout = osWaitForever;
p_spi->spi_tx_done = 0;
p_spi->spi_tx_done = 0;
p_spi->spi_tx_async = 0;
p_spi->spi_rx_async = 0;
p_spi->spi_irq_flag_tx_done = 0;
p_spi->spi_irq_flag_rx_done = 0;
p_spi->dev.dev.ops = (const struct devobj_ops *)&spi_v3_ops;
#ifdef CONFIG_SLEEP
os_mutex_init(&p_spi->bp_suspend_lock);
os_mutex_init(&p_spi->bp_resume_lock);
#endif
os_sema_init(&p_spi->os_spi_tx_done, 0);
os_sema_init(&p_spi->os_spi_rx_done, 0);
//os_mutex_init(&p_spi->os_spi_tx_lock);
//os_mutex_init(&p_spi->os_spi_rx_lock);
os_mutex_init(&p_spi->os_spi_lock);
request_irq(p_spi->irq_num, hgspi_v3_irq_handler, p_spi);
dev_register(dev_id, (struct dev_obj *)p_spi);
return RET_OK;
}