/** * @file sdrv_spi.h * @brief SemiDrive SPI driver header file. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #ifndef SDRV_SPI_H #define SDRV_SPI_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include "reg.h" #include "sdrv_dma.h" #include "spi_reg.h" #define SPI_PIPE_LINE_SIZE_8B 3U #define SPI_PIPE_LINE_SIZE_4B 4U #define SPI_PIPE_LINE_SIZE_2B 5U #define SPI_PIPE_LINE_SIZE_OB 2U // 2 mst_idle 3 mst_start 7 mst_data_wait #define SPI_FSM_WAIT_DATA_STA 7U #define SPI_FSM_M_STR_STA 3U #define SPI_FSM_IDLE_STA 2U /** * @brief Spi sclk idle mode. */ enum spi_cpol { SCK_IDLE_LOW, SCK_IDLE_HIGH }; /** * @brief Spi sclk phase mode. */ enum spi_cpha { DATA_CPT_ON_FIRST_SCK_EDGE, DATA_CPT_ON_SECOND_SCK_EDGE, }; /** * @brief Spi cs mode. */ enum spi_cs_polarity { CS_ACTIVE_LOW, CS_ACTIVE_HIGH }; /** * @brief Spi hardware cs select . */ enum spi_cs_select { CS_SEL_SS0 = 0, CS_SEL_SS1, CS_SEL_SS2, CS_SEL_SS3 }; /** * @brief Spi Bus state flags. */ enum spi_state { SPI_STATE_UNINIT = 0x0, SPI_STATE_INITED = 0x1, SPI_STATE_BUSY_TX = 0x02, SPI_STATE_BUSY_RX = 0x04, SPI_STATE_IRQ_ACT = 0x08, SPI_STATE_DMA_TX = 0x10, SPI_STATE_DMA_RX = 0x20, SPI_STATE_IRQ_TX = 0x40, SPI_STATE_IRQ_RX = 0x80, SPI_STATE_IS_SLAVE = 0x100, SPI_STATE_CS_ACTIVEED = 0x200, SPI_STATE_IS_UNS_EN = 0x400, SPI_STATE_IS_RO_END = 0x800, SPI_STATE_DMA_TX_RD = 0x1000, SPI_STATE_DMA_RX_RD = 0x2000, }; /** * @brief Spi fifo state flags. */ enum fifo_state { SPI_RX_FIFO_READ = (0x01 << 0), SPI_TX_FIFO_WRITE = (0x01 << 1), SPI_TX_FIFO_UDR = (0x01 << 2), SPI_RX_FIFO_OVR = (0x01 << 3), SPI_TX_DMA_ERR = (0x01 << 4), SPI_RX_DMA_ERR = (0x01 << 5), SPI_TX_ONLY_DONE = (0x01 << 6), }; /** * @brief Spi irq type . */ enum irq_type { SPI_TRASPORT_FINISH = 0x01 << 0, SPI_RX_READ_REQ = 0x01 << 1, SPI_TX_WRITE_REQ = 0x01 << 2, SPI_CS_INVLD_REQ = 0x01 << 3, }; /** * @brief Spi bus idle/busy state . */ enum spi_bus_state { SPI_IDLE = 0, SPI_BUSY }; /** * @brief Spi transmit mode . */ enum spi_ops_type { OP_MODE_SYNC = 0, OP_MODE_IRQ, OP_MODE_DMA, }; /** * @brief Spi async transmit callback type . */ typedef enum { SPI_TRANS_DONE = 0, SPI_TRANS_FAIL, SPI_TRANS_PASS } spi_event_type; /** * @brief Spi transmit data direction type . */ enum data_dir { SPI_RX_DIR = 0x01, SPI_TX_DIR = 0x02 }; /** * @brief Spi async transmit callback type . */ typedef void (*spi_callback_t)(void *spi, spi_event_type Event); /** * @brief SPI device configuration. */ struct spi_device_config { /* sclk frea in hz */ uint32_t sclk_freq; /* Idle level */ enum spi_cpol cpol; /* Sampling phase */ enum spi_cpha cpha; /* cs active polarity */ enum spi_cs_polarity cs_pol; /* ss0-ss3 or GPIO_xx */ uint8_t cs_sel; /* deivce raw data width 4-32*/ uint8_t width; /* minimum interval between two transmissions in n*sclk */ uint8_t fream_delay; /* cs setup time in n*sclk */ uint8_t clk2cs_delay; /* cs hold time in n*sclk */ uint8_t clk2cs_end_delay; /* lsb or msb */ bool is_lsb_mode; /* Control the cs signal through IO or peripherals */ bool is_soft_cs; /* enable miso sampling delay half sclk on master mode */ bool is_tx_delay; }; /** * @brief Spi controller configuration . */ struct spi_common_config { /* motor rola mode or ti mode */ bool is_spi_mode; /* half mode */ bool is_half_mode; /* master or slave mode */ bool is_master; /* polling mode */ bool is_polling_mode; #if CONFIG_SPI_ENABLE_DMA /* rx dma channel id */ sdrv_dma_channel_id_e rx_ch_id; /* tx dma channel id */ sdrv_dma_channel_id_e tx_ch_id; /* dma handler */ sdrv_dma_t *dma_ins; #endif /* reg base */ uint32_t base; /* irq num */ uint32_t irq; /* root clk node */ const sdrv_ckgen_slice_node_t *clk; }; /** * @brief Spi transmition data ptr . */ union spi_data_ptr { /* data */ uint32_t val; uint8_t *u8_ptr; uint16_t *u16_ptr; uint32_t *u32_ptr; }; /** * @brief Spi dma context type . */ struct spi_dma_context { enum data_dir dir; void *bus; bool is_need_handle; }; /** * @brief Spi transmit context type . */ struct spi_transmit_cb { /* transmit_sche mode need this*/ uint32_t len; /* tansmit data width type */ uint8_t width_type; /* prxdata */ union spi_data_ptr prxdata; /* ptxdata */ union spi_data_ptr ptxdata; /* prxdata */ uint32_t rx_cur; /* ptxdata */ uint32_t tx_cur; /* remain of this item */ uint32_t cur_remian; /* once except of this item */ uint32_t expect_len; /* vector transmit need */ struct spi_transmit_cb *next; }; /** * @brief Spi bus module handler type . */ typedef struct sdrv_spi { /* get frame static config */ uint32_t base; /* get frame static config */ uint32_t irq; /* Max baudrate when divide by 0 */ uint32_t max_baudrate; /* Max baudrate when divide by 256 */ uint32_t min_baudrate; /* spi preinstance config */ const struct spi_common_config *com_config; /* default Config or slave mode cfg */ const struct spi_device_config *dev_config; /* */ spi_callback_t callback; /* */ struct spi_transmit_cb transmit_sche; /* status */ uint32_t state; /* cur cmd */ uint32_t cur_cmd; #if CONFIG_SPI_ENABLE_DMA /* dma rx channel */ sdrv_dma_channel_t rx_dma_chan; /* dma rx channel */ struct spi_dma_context rx_context; /* dma rx channel */ sdrv_dma_channel_t tx_dma_chan; /* dma rx channel */ struct spi_dma_context tx_context; /* dma error */ uint32_t dma_err; #endif } sdrv_spi_t; #define SPI_POL_VEL_ILLEGAL (~0xFu) #define SPI_START_DELAY_MAX 0xFFu #define SPI_END_DELAY_MAX 0xFFu #define SPI_FRAME_DELAY_MAX 0xFFu #define SPI_CLK_PRESSCALE_MAX 0xFFu #define SPI_FIFO_LEN 16u #define SPI_FRAME_SIZE_MAX 1024U #define SPI_SLAVE_IRQ_NICE_ADJUST (-1) /* slave irq nice val */ /** * @brief Spi transmit data width type only for internal . */ #define SPI_DATA_WIDTH_MIN 4U #define SPI_DATA_WIDTH_BYTE 8U #define SPI_DATA_WIDTH_HALF_WORD 16U #define SPI_DATA_WIDTH_WORD 32U #define SPI_DATA_WIDTH_MAX SPI_DATA_WIDTH_WORD #define SPI_INTERNAL_DIV_SHIFT (1u) #define SPI_CLK_PRESSCALE_MAX_SHIFT (8u) #define SPI_TIMMING_CFG(f, s, e) \ (FV_SPI_TIM_CTRL_START_DLY(s) | FV_SPI_TIM_CTRL_END_DLY(e) | \ FV_SPI_TIM_CTRL_FRM_DLY(f)) #define BUS_BUSY_MASK (SPI_STATE_BUSY_TX | SPI_STATE_BUSY_RX) #define BUS_BUSY_DMA_MASK (SPI_STATE_DMA_TX | SPI_STATE_DMA_RX) #define BUS_BUSY_IRQ_MASK (SPI_STATE_IRQ_TX | SPI_STATE_IRQ_RX) #define BUS_FIFO_STATE_MASK (SPI_RX_FIFO_READ | SPI_TX_FIFO_WRITE) #define BUS_BUSY_ASYNC_MASK (BUS_BUSY_DMA_MASK | BUS_BUSY_IRQ_MASK) #define BUS_BUSY_STATUS_MASK (BUS_BUSY_MASK | BUS_BUSY_ASYNC_MASK) #define BUS_FIFO_STATE_ERR_MASK \ (SPI_TX_FIFO_UDR | SPI_RX_FIFO_OVR | SPI_TX_DMA_ERR | SPI_RX_DMA_ERR) #define BUS_FIFO_EMPTYE_TIMEOUT(f_delay, s_delay, e_delay, baudrate) \ (((f_delay) + (s_delay) + (e_delay) + SPI_DATA_WIDTH_MAX) * 1000000 / \ (baudrate)) #define BUS_STATE_TX_MASK \ (SPI_STATE_DMA_TX | SPI_STATE_BUSY_TX | SPI_STATE_IRQ_TX) #define BUS_STATE_RX_MASK \ (SPI_STATE_DMA_RX | SPI_STATE_BUSY_RX | SPI_STATE_IRQ_RX) #define SPI_SATE_EXT_FLAGS \ (SPI_STATE_IS_UNS_EN | SPI_STATE_IS_RO_END | SPI_STATE_CS_ACTIVEED) #define SPI_GET_WIDTH_SHIFT(width_type) \ (((width_type) == SPI_DATA_WIDTH_WORD \ ? 2 \ : ((width_type) / SPI_DATA_WIDTH_BYTE) - 1)) #define SPI_GET_WIDTH_TYPE(width) \ (((width) > 16U) \ ? (SPI_DATA_WIDTH_WORD) \ : ((width) > 8U ? SPI_DATA_WIDTH_HALF_WORD : SPI_DATA_WIDTH_BYTE)) #define SPI_IS_VALID_LEN(bytes, width) \ (!((bytes) & ((0x1 << SPI_GET_WIDTH_SHIFT(SPI_GET_WIDTH_TYPE(width))) - 1))) /* (16 * 32 + 9 * delay * 1000000)/baudrate == us */ #define SPI_READ_FIFO_TIMEOUT_MAX(f_delay, s_delay, e_delay, baudrate) \ ((((f_delay) + (s_delay) + (e_delay)) * 9 + \ SPI_DATA_WIDTH_MAX * SPI_FIFO_LEN) * \ 1000000 / (baudrate)) /** * @brief spi status return code */ enum { SDRV_SPI_STATUS_MODE_ERROR = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 1), /* Spi configuration mode usage mismatch. */ SDRV_SPI_STATUS_GCMD_NO_SUPPORT = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 2), /* Spi IP version is not supported. */ SDRV_SPI_STATUS_GCMD_TIMEOUT_WRITE = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 3), /* Spi first Write CMD wait timeout. */ SDRV_SPI_STATUS_GCMD_TIMEOUT_FINISH = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 4), /* Spi first write CMD last transfer ended wait timeout. */ SDRV_SPI_STATUS_SOFT_CS_TIMEOUT = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_SPI, 5), /* Spi CLK idle level switching wait timeout. */ SDRV_SPI_STATUS_UCMD_TIMEOUT_WRITE = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 6), /* Spi Write CMD wait timeout(Not the first time). */ SDRV_SPI_STATUS_UCMD_TIMEOUT_FINISH = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 7), /* Spi last transfer ended wait timeout.(Not the first time) */ SDRV_SPI_STATUS_SYNC_TIMEOUT = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 8), /* Spi Synchronous transfer timeout. */ SDRV_SPI_STATUS_SOFT_CS_WAIT_TIMEOUT = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 9), /* Spi Synchronous transfer(Tx only) wait clk ended timeout. */ SDRV_SPI_STATUS_FAIL_DMA_SETUP = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 10), /* Spi dma configuration failed. */ SDRV_SPI_STATUS_FAIL_IRQ_SETUP = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 11), /* Spi irq configuration failed. */ SDRV_SPI_STATUS_PARAM_ILLEGAL = SDRV_ERROR_STATUS( SDRV_STATUS_GROUP_SPI, 12), /* Spi user params error.*/ }; /** * @brief Initialize the SPI module. * * @param[in] spi SPI bus * @param[in] cfg SPI device configuration. * * @note SPI device configuration memory must not be recycled during transfer. * @return 0 is ok, otherwise bus error occurred. */ int sdrv_spi_init(struct sdrv_spi *spi, struct spi_common_config *cfg); /** * @brief Deinitialize the SPI device. * * @param[in] bus SPI bus * * @return 0 is ok, otherwise bus error occurred. */ int sdrv_spi_deinit(struct sdrv_spi *bus); /** * @brief SPI device configuration. * * This function select and activate an external device. Data transfers are * performed according to this device configuration. * * @param[in] spi SPI bus * @param[in] cfg SPI device configuration. * * @note SPI device configuration memory must not be recycled during * transfer. * @return 0 is ok, and other values mean bus is busy. */ int sdrv_spi_config_device(struct sdrv_spi *spi, const struct spi_device_config *cfg); /** * @brief SPI sync transmit. * * @param[in] spi SPI bus. * @param[in] tx_buf Pointer to data to transmit, which must be aligned with the * corresponding data width, otherwise unaligned access will occur and cause an * exception. * @param[out] rx_buf Pointer to receive data storage, which must be aligned * with the corresponding data width, otherwise unaligned access will occur and * cause an exception. * @param[in] bytes The amount of data in bytes. * @param[in] timeout Timeout time >= total transmitted bytes / data-width*2. * @return 0 is ok, and other values for error. */ int sdrv_spi_sync_transmit(struct sdrv_spi *spi, void *tx_buf, void *rx_buf, uint32_t bytes, uint32_t timeout); /** * @brief Setup the async callback handler. * * @param[in] spi SPI bus * @param[in] cb The async callback handler. */ void sdrv_spi_attach_async_callback(struct sdrv_spi *spi, spi_callback_t cb); /** * @brief SPI async transmit in IRQ or DMA mode. * * @param[in] spi SPI bus * @param[in] tx_buf Pointer to data to transmit, which must be aligned with the * corresponding data width, otherwise unaligned access will occur and cause an * exception. * @param[out] rx_buf Pointer to receive data storage, which must be aligned * with the corresponding data width, otherwise unaligned access will occur and * cause an exception. * @param[in] bytes The amount of data in bytes. * @param[in] type OP_MODE_IRQ for IRQ Mode. OP_MODE_DMA for DMA Mode. * @return 0 is ok, and other values for error. */ int sdrv_spi_async_transmit(struct sdrv_spi *spi, void *tx_buf, void *rx_buf, uint32_t bytes, enum spi_ops_type type); /** * @brief Get SPI bus state * * @param[in] spi SPI bus * @return SPI_BUSY: spi bus is busy. SPI_IDLE: spi bus is idle. */ enum spi_bus_state sdrv_spi_get_status(struct sdrv_spi *spi); /** * @brief Get SPI bus polling * * @param spi SPI bus * @return None */ void sdrv_spi_polling(struct sdrv_spi *bus); /** * @brief Get slave transmit cnt * * @param[in] spi SPI bus * @return uint32: transmited bytes. */ uint32_t sdrv_spi_slave_get_transmit_len(struct sdrv_spi *bus); #ifdef __cplusplus } #endif #endif