1559 lines
43 KiB
C
1559 lines
43 KiB
C
|
|
/**
|
|||
|
|
* @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;
|
|||
|
|
}
|