/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "plat_addr_map.h" #include "cmsis.h" #include "hal_cmu.h" #include "hal_dma.h" #include "hal_location.h" #include "hal_spi.h" #include "hal_trace.h" #include "reg_spi.h" #include "string.h" // TODO: // 1) Add transfer timeout control #ifdef SPI_ROM_ONLY #define SPI_ASSERT(c, ...) ASSERT_NODUMP(c) #else #define SPI_ASSERT(c, ...) ASSERT(c, ##__VA_ARGS__) #endif enum HAL_SPI_ID_T { HAL_SPI_ID_INTERNAL, #ifdef CHIP_HAS_SPI HAL_SPI_ID_0, #endif #ifdef CHIP_HAS_SPILCD HAL_SPI_ID_SLCD, #endif #ifdef CHIP_HAS_SPIPHY HAL_SPI_ID_PHY, #endif #ifdef CHIP_HAS_SPIDPD HAL_SPI_ID_DPD, #endif HAL_SPI_ID_QTY }; enum HAL_SPI_CS_T { HAL_SPI_CS_0, #if (CHIP_SPI_VER >= 2) HAL_SPI_CS_1, HAL_SPI_CS_2, #if (CHIP_SPI_VER >= 3) HAL_SPI_CS_3, #if (CHIP_SPI_VER >= 4) //HAL_SPI_CS_4, #endif #endif #endif HAL_SPI_CS_QTY }; enum HAL_SPI_XFER_TYPE_T { HAL_SPI_XFER_TYPE_SEND, HAL_SPI_XFER_TYPE_RECV, HAL_SPI_XFER_TYPE_QTY }; struct HAL_SPI_MOD_NAME_T { enum HAL_CMU_MOD_ID_T mod; enum HAL_CMU_MOD_ID_T apb; }; static struct SPI_T * const spi[HAL_SPI_ID_QTY] = { (struct SPI_T *)ISPI_BASE, #ifdef CHIP_HAS_SPI (struct SPI_T *)SPI_BASE, #endif #ifdef CHIP_HAS_SPILCD (struct SPI_T *)SPILCD_BASE, #endif #ifdef CHIP_HAS_SPIPHY (struct SPI_T *)SPIPHY_BASE, #endif #ifdef CHIP_HAS_SPIDPD (struct SPI_T *)SPIDPD_BASE, #endif }; static const struct HAL_SPI_MOD_NAME_T spi_mod[HAL_SPI_ID_QTY] = { { .mod = HAL_CMU_MOD_O_SPI_ITN, .apb = HAL_CMU_MOD_P_SPI_ITN, }, #ifdef CHIP_HAS_SPI { .mod = HAL_CMU_MOD_O_SPI, .apb = HAL_CMU_MOD_P_SPI, }, #endif #ifdef CHIP_HAS_SPILCD { .mod = HAL_CMU_MOD_O_SLCD, .apb = HAL_CMU_MOD_P_SLCD, }, #endif #ifdef CHIP_HAS_SPIPHY { .mod = HAL_CMU_MOD_O_SPI_PHY, .apb = HAL_CMU_MOD_P_SPI_PHY, }, #endif #ifdef CHIP_HAS_SPIDPD { .mod = HAL_CMU_MOD_O_SPI_DPD, .apb = HAL_CMU_MOD_P_SPI_DPD, }, #endif }; #ifndef SPI_ROM_ONLY #ifdef CHIP_HAS_SPI static struct HAL_SPI_CTRL_T spi0_ctrl[HAL_SPI_CS_QTY]; #if (CHIP_SPI_VER >= 2) static enum HAL_SPI_CS_T spi0_cs = HAL_SPI_CS_0; #else static const enum HAL_SPI_CS_T spi0_cs = HAL_SPI_CS_0; #endif #endif #ifdef CHIP_HAS_SPILCD static struct HAL_SPI_CTRL_T spilcd_ctrl[HAL_SPI_CS_QTY]; #if (CHIP_SPI_VER >= 2) static enum HAL_SPI_CS_T spilcd_cs = HAL_SPI_CS_0; #else static const enum HAL_SPI_CS_T spilcd_cs = HAL_SPI_CS_0; #endif #endif #ifdef CHIP_HAS_SPIDPD static struct HAL_SPI_CTRL_T spidpd_ctrl; #endif static uint8_t BOOT_BSS_LOC spi_cs_map[HAL_SPI_ID_QTY]; STATIC_ASSERT(sizeof(spi_cs_map[0]) * 8 >= HAL_SPI_CS_QTY, "spi_cs_map size too small"); static bool BOOT_BSS_LOC in_use[HAL_SPI_ID_QTY] = { false, }; static HAL_SPI_DMA_HANDLER_T BOOT_BSS_LOC spi_txdma_handler[HAL_SPI_ID_QTY]; static HAL_SPI_DMA_HANDLER_T BOOT_BSS_LOC spi_rxdma_handler[HAL_SPI_ID_QTY]; static uint8_t BOOT_BSS_LOC spi_txdma_chan[HAL_SPI_ID_QTY]; static uint8_t BOOT_BSS_LOC spi_rxdma_chan[HAL_SPI_ID_QTY]; static enum HAL_SPI_MOD_CLK_SEL_T clk_sel[HAL_SPI_ID_QTY]; static bool BOOT_BSS_LOC spi_init_done = false; static int hal_spi_activate_cs_id(enum HAL_SPI_ID_T id, uint32_t cs); #endif //static const char *invalid_id = "Invalid SPI ID: %d"; static inline uint8_t get_frame_bytes(enum HAL_SPI_ID_T id) { uint8_t bits, cnt; bits = GET_BITFIELD(spi[id]->SSPCR0, SPI_SSPCR0_DSS) + 1; if (bits <= 8) { cnt = 1; } else if (bits <= 16) { cnt = 2; } else { cnt = 4; } return cnt; } static inline void copy_frame_from_bytes(uint32_t *val, const uint8_t *data, uint8_t cnt) { #ifdef UNALIGNED_ACCESS if (cnt == 1) { *val = *(const uint8_t *)data; } else if (cnt == 2) { *val = *(const uint16_t *)data; } else { *val = *(const uint32_t *)data; } #else if (cnt == 1) { *val = data[0]; } else if (cnt == 2) { *val = data[0] | (data[1] << 8); } else { *val = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } #endif } static inline void copy_bytes_from_frame(uint8_t *data, uint32_t val, uint8_t cnt) { #ifdef UNALIGNED_ACCESS if (cnt == 1) { *(uint8_t *)data = (uint8_t)val; } else if (cnt == 2) { *(uint16_t *)data = (uint16_t)val; } else { *(uint32_t *)data = (uint32_t)val; } #else data[0] = (uint8_t)val; if (cnt == 1) { return; } else if (cnt == 2) { data[1] = (uint8_t)(val >> 8); } else { data[1] = (uint8_t)(val >> 8); data[2] = (uint8_t)(val >> 16); data[3] = (uint8_t)(val >> 24); } #endif } int hal_spi_init_ctrl(const struct HAL_SPI_CFG_T *cfg, struct HAL_SPI_CTRL_T *ctrl) { uint32_t div; uint16_t cpsdvsr, scr; uint32_t mod_clk; #ifdef SPI_ROM_ONLY // Assume default crystal -- Never access global versatile data to ensure reentrance mod_clk = HAL_CMU_DEFAULT_CRYSTAL_FREQ; #else // !SPI_ROM_ONLY mod_clk = 0; #ifdef PERIPH_PLL_FREQ if (PERIPH_PLL_FREQ / 2 > 2 * hal_cmu_get_crystal_freq()) { // Init to OSC_X2 mod_clk = 2 * hal_cmu_get_crystal_freq(); if (cfg->rate * 2 > mod_clk) { mod_clk = PERIPH_PLL_FREQ / 2; ctrl->clk_sel = HAL_SPI_MOD_CLK_SEL_PLL; } else { mod_clk = 0; } } #endif if (mod_clk == 0) { // Init to OSC mod_clk = hal_cmu_get_crystal_freq(); if (cfg->rate * 2 > mod_clk) { mod_clk *= 2; ctrl->clk_sel = HAL_SPI_MOD_CLK_SEL_OSC_X2; } else { ctrl->clk_sel = HAL_SPI_MOD_CLK_SEL_OSC; } } #endif // !SPI_ROM_ONLY SPI_ASSERT(cfg->rate <= mod_clk / (MIN_CPSDVSR * (1 + MIN_SCR)), "SPI rate too large: %u", cfg->rate); SPI_ASSERT(cfg->rate >= mod_clk / (MAX_CPSDVSR * (1 + MAX_SCR)), "SPI rate too small: %u", cfg->rate); SPI_ASSERT(cfg->tx_bits <= MAX_DATA_BITS && cfg->tx_bits >= MIN_DATA_BITS, "Invalid SPI TX bits: %d", cfg->tx_bits); SPI_ASSERT(cfg->rx_bits <= MAX_DATA_BITS && cfg->rx_bits >= MIN_DATA_BITS, "Invalid SPI RX bits: %d", cfg->rx_bits); SPI_ASSERT(cfg->rx_frame_bits <= MAX_DATA_BITS && (cfg->rx_frame_bits == 0 || cfg->rx_frame_bits > cfg->rx_bits), "Invalid SPI RX FRAME bits: %d", cfg->rx_frame_bits); SPI_ASSERT(cfg->cs < HAL_SPI_CS_QTY, "SPI cs bad: %d", cfg->cs); div = (mod_clk + cfg->rate - 1) / cfg->rate; cpsdvsr = (div + MAX_SCR) / (MAX_SCR + 1); if (cpsdvsr < 2) { cpsdvsr = 2; } else { if (cpsdvsr & 0x1) { cpsdvsr += 1; } if (cpsdvsr > MAX_CPSDVSR) { cpsdvsr = MAX_CPSDVSR; } } scr = (div + cpsdvsr - 1) / cpsdvsr; if (scr > 0) { scr -= 1; } if (scr > MAX_SCR) { scr = MAX_SCR; } ctrl->sspcr0_tx = SPI_SSPCR0_SCR(scr) | (cfg->clk_delay_half ? SPI_SSPCR0_SPH : 0) | (cfg->clk_polarity ? SPI_SSPCR0_SPO : 0) | SPI_SSPCR0_FRF(0) | // Only support Motorola SPI frame format SPI_SSPCR0_DSS(cfg->tx_bits - 1); ctrl->sspcr1 = (cfg->rx_sep_line ? SPI_RX_SEL_EN : 0) | SPI_SLAVE_ID(cfg->cs) | SPI_SSPCR1_SOD | (cfg->slave ? SPI_SSPCR1_MS : 0) | SPI_SSPCR1_SSE; ctrl->sspcpsr = SPI_SSPCPSR_CPSDVSR(cpsdvsr); ctrl->sspdmacr = (cfg->dma_tx ? SPI_SSPDMACR_TXDMAE : 0) | (cfg->dma_rx ? SPI_SSPDMACR_RXDMAE : 0); ctrl->ssprxcr_tx = 0; if (cfg->rx_frame_bits > 0) { ctrl->sspcr0_rx = SET_BITFIELD(ctrl->sspcr0_tx, SPI_SSPCR0_DSS, cfg->rx_frame_bits - 1); ctrl->ssprxcr_rx = SPI_SSPRXCR_EN | SPI_SSPRXCR_OEN_POLARITY | SPI_SSPRXCR_RXBITS(cfg->rx_bits - 1); } else { ctrl->sspcr0_rx = SET_BITFIELD(ctrl->sspcr0_tx, SPI_SSPCR0_DSS, cfg->rx_bits - 1); ctrl->ssprxcr_rx = 0; } return 0; } static void NOINLINE POSSIBLY_UNUSED hal_spi_set_xfer_type_id(enum HAL_SPI_ID_T id, const struct HAL_SPI_CTRL_T *ctrl, enum HAL_SPI_XFER_TYPE_T type) { uint32_t sspcr0; uint32_t ssprxcr; if (type == HAL_SPI_XFER_TYPE_SEND) { sspcr0 = ctrl->sspcr0_tx; ssprxcr = ctrl->ssprxcr_tx; } else { sspcr0 = ctrl->sspcr0_rx; ssprxcr = ctrl->ssprxcr_rx; } spi[id]->SSPCR0 = sspcr0; spi[id]->SSPRXCR = ssprxcr; } static void NOINLINE hal_spi_enable_id(enum HAL_SPI_ID_T id, const struct HAL_SPI_CTRL_T *ctrl, enum HAL_SPI_XFER_TYPE_T type) { hal_spi_set_xfer_type_id(id, ctrl, type); spi[id]->SSPCR1 = ctrl->sspcr1; spi[id]->SSPCPSR = ctrl->sspcpsr; spi[id]->SSPDMACR = ctrl->sspdmacr; #ifdef SPI_ROM_ONLY if (id == HAL_SPI_ID_INTERNAL) { hal_cmu_ispi_set_freq(HAL_CMU_PERIPH_FREQ_26M); #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { hal_cmu_spi_set_freq(HAL_CMU_PERIPH_FREQ_26M); #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { hal_cmu_slcd_set_freq(HAL_CMU_PERIPH_FREQ_26M); #endif } #else // !SPI_ROM_ONLY if (clk_sel[id] != ctrl->clk_sel) { clk_sel[id] = ctrl->clk_sel; if (ctrl->clk_sel == HAL_SPI_MOD_CLK_SEL_PLL) { #ifdef PERIPH_PLL_FREQ if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { hal_cmu_spi_set_div(2); #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { hal_cmu_slcd_set_div(2); #endif } // ISPI cannot use PLL clock #endif } else { enum HAL_CMU_PERIPH_FREQ_T periph_freq; if (ctrl->clk_sel == HAL_SPI_MOD_CLK_SEL_OSC_X2) { periph_freq = HAL_CMU_PERIPH_FREQ_52M; } else { periph_freq = HAL_CMU_PERIPH_FREQ_26M; } if (id == HAL_SPI_ID_INTERNAL) { hal_cmu_ispi_set_freq(periph_freq); #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { hal_cmu_spi_set_freq(periph_freq); #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { hal_cmu_slcd_set_freq(periph_freq); #endif } } } #endif // !SPI_ROM_ONLY } static void hal_spi_disable_id(enum HAL_SPI_ID_T id) { spi[id]->SSPCR1 &= ~SPI_SSPCR1_SSE; } static void POSSIBLY_UNUSED hal_spi_get_ctrl_id(enum HAL_SPI_ID_T id, struct HAL_SPI_CTRL_T *ctrl) { ctrl->sspcr0_tx = spi[id]->SSPCR0; ctrl->sspcr1 = spi[id]->SSPCR1; ctrl->sspcpsr = spi[id]->SSPCPSR; ctrl->sspdmacr = spi[id]->SSPDMACR; ctrl->ssprxcr_tx = spi[id]->SSPRXCR; } static int NOINLINE hal_spi_open_id(enum HAL_SPI_ID_T id, const struct HAL_SPI_CFG_T *cfg, struct HAL_SPI_CTRL_T *ctrl) { int ret; struct HAL_SPI_CTRL_T ctrl_regs; bool cfg_clk = true; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); if (ctrl == NULL) { ctrl = &ctrl_regs; } ret = hal_spi_init_ctrl(cfg, ctrl); if (ret) { return ret; } #ifndef SPI_ROM_ONLY if (!spi_init_done) { spi_init_done = true; for (int i = HAL_SPI_ID_INTERNAL; i < HAL_SPI_ID_QTY; i++) { spi_txdma_chan[i] = HAL_DMA_CHAN_NONE; spi_rxdma_chan[i] = HAL_DMA_CHAN_NONE; } } if (spi_cs_map[id]) { cfg_clk = false; } spi_cs_map[id] |= (1 << cfg->cs); #endif if (cfg_clk) { hal_cmu_clock_enable(spi_mod[id].mod); hal_cmu_clock_enable(spi_mod[id].apb); hal_cmu_reset_clear(spi_mod[id].mod); hal_cmu_reset_clear(spi_mod[id].apb); } hal_spi_enable_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); return 0; } static int POSSIBLY_UNUSED hal_spi_close_id(enum HAL_SPI_ID_T id, uint32_t cs) { int ret = 0; bool cfg_clk = true; #ifndef SPI_ROM_ONLY if (spi_cs_map[id] & (1 << cs)) { spi_cs_map[id] &= ~(1 << cs); #if (CHIP_SPI_VER >= 2) if (spi_cs_map[id]) { cfg_clk = false; } #endif } else { ret = 1; cfg_clk = false; } #endif if (cfg_clk) { hal_spi_disable_id(id); hal_cmu_reset_set(spi_mod[id].apb); hal_cmu_reset_set(spi_mod[id].mod); hal_cmu_clock_disable(spi_mod[id].apb); hal_cmu_clock_disable(spi_mod[id].mod); } return ret; } static void POSSIBLY_UNUSED hal_spi_set_cs_id(enum HAL_SPI_ID_T id, uint32_t cs) { spi[id]->SSPCR1 = SET_BITFIELD(spi[id]->SSPCR1, SPI_SLAVE_ID, cs); } static bool hal_spi_busy_id(enum HAL_SPI_ID_T id) { return ((spi[id]->SSPCR1 & SPI_SSPCR1_SSE) && (spi[id]->SSPSR & SPI_SSPSR_BSY)); } static void hal_spi_enable_slave_output_id(enum HAL_SPI_ID_T id) { if (spi[id]->SSPCR1 & SPI_SSPCR1_MS) { spi[id]->SSPCR1 &= ~SPI_SSPCR1_SOD; } } static void hal_spi_disable_slave_output_id(enum HAL_SPI_ID_T id) { if (spi[id]->SSPCR1 & SPI_SSPCR1_MS) { spi[id]->SSPCR1 |= SPI_SSPCR1_SOD; } } static int hal_spi_send_id(enum HAL_SPI_ID_T id, const void *data, uint32_t len) { uint8_t cnt; uint32_t sent, value; int ret; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); SPI_ASSERT((spi[id]->SSPDMACR & SPI_SSPDMACR_TXDMAE) == 0, "TX-DMA configured on SPI %d", id); cnt = get_frame_bytes(id); if (len == 0 || (len & (cnt - 1)) != 0) { return -1; } sent = 0; hal_spi_enable_slave_output_id(id); while (sent < len) { if ((spi[id]->SSPCR1 & SPI_SSPCR1_SSE) == 0) { break; } if (spi[id]->SSPSR & SPI_SSPSR_TNF) { value = 0; copy_frame_from_bytes(&value, (uint8_t *)data + sent, cnt); spi[id]->SSPDR = value; sent += cnt; } } if (sent >= len) { ret = 0; } else { ret = 1; } while (hal_spi_busy_id(id)); hal_spi_disable_slave_output_id(id); return ret; } static int hal_spi_recv_id(enum HAL_SPI_ID_T id, const void *cmd, void *data, uint32_t len) { uint8_t cnt; uint32_t sent, recv, value; int ret; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); SPI_ASSERT((spi[id]->SSPDMACR & (SPI_SSPDMACR_TXDMAE | SPI_SSPDMACR_RXDMAE)) == 0, "RX/TX-DMA configured on SPI %d", id); cnt = get_frame_bytes(id); if (len == 0 || (len & (cnt - 1)) != 0) { return -1; } // Rx transaction should start from idle state if (spi[id]->SSPSR & SPI_SSPSR_BSY) { return -11; } sent = 0; recv = 0; // Flush the RX FIFO by reset or CPU read while (spi[id]->SSPSR & SPI_SSPSR_RNE) { spi[id]->SSPDR; } spi[id]->SSPICR = ~0UL; hal_spi_enable_slave_output_id(id); while (recv < len || sent < len) { if ((spi[id]->SSPCR1 & SPI_SSPCR1_SSE) == 0) { break; } if (sent < len && (spi[id]->SSPSR & SPI_SSPSR_TNF)) { value = 0; copy_frame_from_bytes(&value, (uint8_t *)cmd + sent, cnt); spi[id]->SSPDR = value; sent += cnt; } if (recv < len && (spi[id]->SSPSR & SPI_SSPSR_RNE)) { value = spi[id]->SSPDR; copy_bytes_from_frame((uint8_t *)data + recv, value, cnt); recv += cnt; } } if (recv >= len && sent >= len) { ret = 0; } else { ret = 1; } while (hal_spi_busy_id(id)); hal_spi_disable_slave_output_id(id); return ret; } #ifdef SPI_ROM_ONLY //------------------------------------------------------------ // ISPI ROM functions //------------------------------------------------------------ int hal_ispi_rom_open(const struct HAL_SPI_CFG_T *cfg) { SPI_ASSERT(cfg->tx_bits == cfg->rx_bits && cfg->rx_frame_bits == 0, "ISPI_ROM: Bad bits cfg"); return hal_spi_open_id(HAL_SPI_ID_INTERNAL, cfg, NULL); } void hal_ispi_rom_activate_cs(uint32_t cs) { SPI_ASSERT(cs < HAL_SPI_CS_QTY, "ISPI_ROM: SPI cs bad: %d", cs); hal_spi_set_cs_id(HAL_SPI_ID_INTERNAL, cs); } int hal_ispi_rom_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_INTERNAL); } int hal_ispi_rom_send(const void *data, uint32_t len) { int ret; ret = hal_spi_send_id(HAL_SPI_ID_INTERNAL, data, len); return ret; } int hal_ispi_rom_recv(const void *cmd, void *data, uint32_t len) { int ret; ret = hal_spi_recv_id(HAL_SPI_ID_INTERNAL, cmd, data, len); return ret; } #ifdef CHIP_HAS_SPIPHY //------------------------------------------------------------ // SPI PHY ROM functions //------------------------------------------------------------ int hal_spiphy_rom_open(const struct HAL_SPI_CFG_T *cfg) { SPI_ASSERT(cfg->tx_bits == cfg->rx_bits && cfg->rx_frame_bits == 0, "SPIPHY_ROM: Bad bits cfg"); return hal_spi_open_id(HAL_SPI_ID_PHY, cfg, NULL); } int hal_spiphy_rom_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_PHY); } int hal_spiphy_rom_send(const void *data, uint32_t len) { int ret; ret = hal_spi_send_id(HAL_SPI_ID_PHY, data, len); return ret; } int hal_spiphy_rom_recv(const void *cmd, void *data, uint32_t len) { int ret; ret = hal_spi_recv_id(HAL_SPI_ID_PHY, cmd, data, len); return ret; } #endif #else // !SPI_ROM_ONLY static int hal_spi_activate_cs_id(enum HAL_SPI_ID_T id, uint32_t cs) { struct HAL_SPI_CTRL_T *ctrl = NULL; SPI_ASSERT(cs < HAL_SPI_CS_QTY, "SPI cs bad: %d", cs); SPI_ASSERT(spi_cs_map[id] & (1 << cs), "SPI cs not opened: %d", cs); #if (CHIP_SPI_VER >= 2) if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { spi0_cs = cs; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { spilcd_cs = cs; #endif } #endif if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { ctrl = &spi0_ctrl[spi0_cs]; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { ctrl = &spilcd_ctrl[spilcd_cs]; #endif } if (ctrl) { hal_spi_enable_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); } return 0; } static int POSSIBLY_UNUSED hal_spi_enable_and_send_id(enum HAL_SPI_ID_T id, const struct HAL_SPI_CTRL_T *ctrl, const void *data, uint32_t len) { int ret; struct HAL_SPI_CTRL_T saved; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); if (set_bool_flag(&in_use[id])) { return -31; } hal_spi_get_ctrl_id(id, &saved); hal_spi_enable_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); ret = hal_spi_send_id(id, data, len); hal_spi_enable_id(id, &saved, HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[id]); return ret; } static int POSSIBLY_UNUSED hal_spi_enable_and_recv_id(enum HAL_SPI_ID_T id, const struct HAL_SPI_CTRL_T *ctrl, const void *cmd, void *data, uint32_t len) { int ret; struct HAL_SPI_CTRL_T saved; if (set_bool_flag(&in_use[id])) { return -31; } hal_spi_get_ctrl_id(id, &saved); hal_spi_enable_id(id, ctrl, HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_recv_id(id, cmd, data, len); hal_spi_enable_id(id, &saved, HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[id]); return ret; } static void hal_spi_txdma_handler(uint8_t chan, uint32_t remains, uint32_t error, struct HAL_DMA_DESC_T *lli) { enum HAL_SPI_ID_T id; uint32_t lock; lock = int_lock(); for (id = HAL_SPI_ID_INTERNAL; id < HAL_SPI_ID_QTY; id++) { if (spi_txdma_chan[id] == chan) { spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; break; } } int_unlock(lock); if (id >= HAL_SPI_ID_QTY) { return; } hal_gpdma_free_chan(chan); clear_bool_flag(&in_use[id]); if (spi_txdma_handler[id]) { spi_txdma_handler[id](error); } } static int hal_spi_dma_send_id(enum HAL_SPI_ID_T id, const void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { uint8_t cnt; enum HAL_DMA_RET_T ret; struct HAL_DMA_CH_CFG_T dma_cfg; enum HAL_DMA_WDITH_T dma_width; uint32_t lock; enum HAL_DMA_PERIPH_T dst_periph; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); SPI_ASSERT((spi[id]->SSPDMACR & SPI_SSPDMACR_TXDMAE), "TX-DMA not configured on SPI %d", id); spi_txdma_handler[id] = handler; cnt = get_frame_bytes(id); if ((len & (cnt - 1)) != 0) { return -1; } if (((uint32_t)data & (cnt - 1)) != 0) { return -2; } // Tx transaction should start from idle state for SPI mode 1 and 3 (SPH=1) if ((spi[id]->SSPCR0 & SPI_SSPCR0_SPH) && (spi[id]->SSPSR & SPI_SSPSR_BSY)) { return -11; } if (id == HAL_SPI_ID_INTERNAL) { dst_periph = HAL_GPDMA_ISPI_TX; #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { dst_periph = HAL_GPDMA_SPI_TX; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { dst_periph = HAL_GPDMA_SPILCD_TX; #endif } else { return -12; } lock = int_lock(); if (spi_txdma_chan[id] != HAL_DMA_CHAN_NONE) { int_unlock(lock); return -3; } spi_txdma_chan[id] = hal_gpdma_get_chan(dst_periph, HAL_DMA_HIGH_PRIO); if (spi_txdma_chan[id] == HAL_DMA_CHAN_NONE) { int_unlock(lock); return -4; } int_unlock(lock); if (cnt == 1) { dma_width = HAL_DMA_WIDTH_BYTE; } else if (cnt == 2) { dma_width = HAL_DMA_WIDTH_HALFWORD; } else { dma_width = HAL_DMA_WIDTH_WORD; } memset(&dma_cfg, 0, sizeof(dma_cfg)); dma_cfg.ch = spi_txdma_chan[id]; dma_cfg.dst = 0; // useless dma_cfg.dst_bsize = HAL_DMA_BSIZE_4; dma_cfg.dst_periph = dst_periph; dma_cfg.dst_width = dma_width; dma_cfg.handler = handler ? hal_spi_txdma_handler : NULL; dma_cfg.src = (uint32_t)data; dma_cfg.src_bsize = HAL_DMA_BSIZE_16; //dma_cfg.src_periph = HAL_GPDMA_PERIPH_QTY; // useless dma_cfg.src_tsize = len / cnt; dma_cfg.src_width = dma_width; dma_cfg.try_burst = 0; dma_cfg.type = HAL_DMA_FLOW_M2P_DMA; hal_spi_enable_slave_output_id(id); ret = hal_gpdma_start(&dma_cfg); if (ret != HAL_DMA_OK) { hal_spi_disable_slave_output_id(id); return -5; } if (handler == NULL) { while ((spi[id]->SSPCR1 & SPI_SSPCR1_SSE) && hal_gpdma_chan_busy(spi_txdma_chan[id])); hal_gpdma_free_chan(spi_txdma_chan[id]); spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; while (hal_spi_busy_id(id)); hal_spi_disable_slave_output_id(id); } return 0; } void hal_spi_stop_dma_send_id(enum HAL_SPI_ID_T id) { uint32_t lock; uint8_t tx_chan; lock = int_lock(); tx_chan = spi_txdma_chan[id]; spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; int_unlock(lock); if (tx_chan != HAL_DMA_CHAN_NONE) { hal_gpdma_cancel(tx_chan); hal_gpdma_free_chan(tx_chan); } clear_bool_flag(&in_use[id]); } static void hal_spi_rxdma_handler(uint8_t chan, uint32_t remains, uint32_t error, struct HAL_DMA_DESC_T *lli) { enum HAL_SPI_ID_T id; uint32_t lock; uint8_t tx_chan = HAL_DMA_CHAN_NONE; struct HAL_SPI_CTRL_T *ctrl = NULL; lock = int_lock(); for (id = HAL_SPI_ID_INTERNAL; id < HAL_SPI_ID_QTY; id++) { if (spi_rxdma_chan[id] == chan) { tx_chan = spi_txdma_chan[id]; spi_rxdma_chan[id] = HAL_DMA_CHAN_NONE; spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; break; } } int_unlock(lock); if (id >= HAL_SPI_ID_QTY) { return; } hal_gpdma_free_chan(chan); hal_gpdma_cancel(tx_chan); hal_gpdma_free_chan(tx_chan); if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { ctrl = &spi0_ctrl[spi0_cs]; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { ctrl = &spilcd_ctrl[spilcd_cs]; #endif } if (ctrl) { hal_spi_set_xfer_type_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); } clear_bool_flag(&in_use[id]); if (spi_rxdma_handler[id]) { spi_rxdma_handler[id](error); } } static int hal_spi_dma_recv_id(enum HAL_SPI_ID_T id, const void *cmd, void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { uint8_t cnt; enum HAL_DMA_RET_T ret; struct HAL_DMA_CH_CFG_T dma_cfg; enum HAL_DMA_WDITH_T dma_width; uint32_t lock; int result; enum HAL_DMA_PERIPH_T dst_periph, src_periph; struct HAL_SPI_CTRL_T *ctrl = NULL; //SPI_ASSERT(id < HAL_SPI_ID_QTY, invalid_id, id); SPI_ASSERT((spi[id]->SSPDMACR & (SPI_SSPDMACR_TXDMAE | SPI_SSPDMACR_RXDMAE)) == (SPI_SSPDMACR_TXDMAE | SPI_SSPDMACR_RXDMAE), "RX/TX-DMA not configured on SPI %d", id); spi_rxdma_handler[id] = handler; result = 0; cnt = get_frame_bytes(id); if ((len & (cnt - 1)) != 0) { return -1; } if (((uint32_t)data & (cnt - 1)) != 0) { return -2; } // Rx transaction should start from idle state if (spi[id]->SSPSR & SPI_SSPSR_BSY) { return -11; } if (id == HAL_SPI_ID_INTERNAL) { src_periph = HAL_GPDMA_ISPI_RX; dst_periph = HAL_GPDMA_ISPI_TX; #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { src_periph = HAL_GPDMA_SPI_RX; dst_periph = HAL_GPDMA_SPI_TX; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { src_periph = HAL_GPDMA_SPILCD_RX; dst_periph = HAL_GPDMA_SPILCD_TX; #endif } else { return -12; } lock = int_lock(); if (spi_txdma_chan[id] != HAL_DMA_CHAN_NONE || spi_rxdma_chan[id] != HAL_DMA_CHAN_NONE) { int_unlock(lock); return -3; } spi_txdma_chan[id] = hal_gpdma_get_chan(dst_periph, HAL_DMA_HIGH_PRIO); if (spi_txdma_chan[id] == HAL_DMA_CHAN_NONE) { int_unlock(lock); return -4; } spi_rxdma_chan[id] = hal_gpdma_get_chan(src_periph, HAL_DMA_HIGH_PRIO); if (spi_rxdma_chan[id] == HAL_DMA_CHAN_NONE) { hal_gpdma_free_chan(spi_txdma_chan[id]); spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; int_unlock(lock); return -5; } int_unlock(lock); if (cnt == 1) { dma_width = HAL_DMA_WIDTH_BYTE; } else if (cnt == 2) { dma_width = HAL_DMA_WIDTH_HALFWORD; } else { dma_width = HAL_DMA_WIDTH_WORD; } memset(&dma_cfg, 0, sizeof(dma_cfg)); dma_cfg.ch = spi_rxdma_chan[id]; dma_cfg.dst = (uint32_t)data; dma_cfg.dst_bsize = HAL_DMA_BSIZE_16; //dma_cfg.dst_periph = HAL_GPDMA_PERIPH_QTY; // useless dma_cfg.dst_width = dma_width; dma_cfg.handler = handler ? hal_spi_rxdma_handler : NULL; dma_cfg.src = 0; // useless dma_cfg.src_periph = src_periph; dma_cfg.src_bsize = HAL_DMA_BSIZE_4; dma_cfg.src_tsize = len / cnt; dma_cfg.src_width = dma_width; dma_cfg.try_burst = 0; dma_cfg.type = HAL_DMA_FLOW_P2M_DMA; // Flush the RX FIFO by reset or DMA read (CPU read is forbidden when DMA is enabled) if (spi[id]->SSPSR & SPI_SSPSR_RNE) { // Reset SPI MODULE might cause the increment of the FIFO pointer hal_cmu_reset_pulse(spi_mod[id].mod); // Reset SPI APB will reset the FIFO pointer hal_cmu_reset_pulse(spi_mod[id].apb); if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { ctrl = &spi0_ctrl[spi0_cs]; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { ctrl = &spilcd_ctrl[spilcd_cs]; #endif } if (ctrl) { // hal_spi_set_xfer_type_id() is not enough, for all the registers have been reset by APB reset hal_spi_enable_id(id, ctrl, HAL_SPI_XFER_TYPE_RECV); } } spi[id]->SSPICR = ~0UL; ret = hal_gpdma_start(&dma_cfg); if (ret != HAL_DMA_OK) { result = -8; goto _exit; } dma_cfg.ch = spi_txdma_chan[id]; dma_cfg.dst = 0; // useless dma_cfg.dst_bsize = HAL_DMA_BSIZE_4; dma_cfg.dst_periph = dst_periph; dma_cfg.dst_width = dma_width; dma_cfg.handler = NULL; dma_cfg.src = (uint32_t)cmd; dma_cfg.src_bsize = HAL_DMA_BSIZE_16; //dma_cfg.src_periph = HAL_GPDMA_PERIPH_QTY; // useless dma_cfg.src_tsize = len / cnt; dma_cfg.src_width = dma_width; dma_cfg.try_burst = 0; dma_cfg.type = HAL_DMA_FLOW_M2P_DMA; hal_spi_enable_slave_output_id(id); ret = hal_gpdma_start(&dma_cfg); if (ret != HAL_DMA_OK) { result = -9; goto _exit; } if (handler == NULL) { while ((spi[id]->SSPCR1 & SPI_SSPCR1_SSE) && hal_gpdma_chan_busy(spi_rxdma_chan[id])); } _exit: if (result || handler == NULL) { hal_gpdma_cancel(spi_txdma_chan[id]); hal_gpdma_free_chan(spi_txdma_chan[id]); spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; while (hal_spi_busy_id(id)); hal_spi_disable_slave_output_id(id); hal_gpdma_cancel(spi_rxdma_chan[id]); hal_gpdma_free_chan(spi_rxdma_chan[id]); spi_rxdma_chan[id] = HAL_DMA_CHAN_NONE; if (ctrl) { hal_spi_set_xfer_type_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); } } return 0; } void hal_spi_stop_dma_recv_id(enum HAL_SPI_ID_T id) { uint32_t lock; uint8_t rx_chan, tx_chan; struct HAL_SPI_CTRL_T *ctrl = NULL; lock = int_lock(); rx_chan = spi_rxdma_chan[id]; spi_rxdma_chan[id] = HAL_DMA_CHAN_NONE; tx_chan = spi_txdma_chan[id]; spi_txdma_chan[id] = HAL_DMA_CHAN_NONE; int_unlock(lock); if (rx_chan == HAL_DMA_CHAN_NONE && tx_chan == HAL_DMA_CHAN_NONE) { return; } if (rx_chan != HAL_DMA_CHAN_NONE) { hal_gpdma_cancel(rx_chan); hal_gpdma_free_chan(rx_chan); } if (tx_chan != HAL_DMA_CHAN_NONE) { hal_gpdma_cancel(tx_chan); hal_gpdma_free_chan(tx_chan); } if (0) { #ifdef CHIP_HAS_SPI } else if (id == HAL_SPI_ID_0) { ctrl = &spi0_ctrl[spi0_cs]; #endif #ifdef CHIP_HAS_SPILCD } else if (id == HAL_SPI_ID_SLCD) { ctrl = &spilcd_ctrl[spilcd_cs]; #endif } if (ctrl) { hal_spi_set_xfer_type_id(id, ctrl, HAL_SPI_XFER_TYPE_SEND); } clear_bool_flag(&in_use[id]); } //------------------------------------------------------------ // ISPI functions //------------------------------------------------------------ int hal_ispi_open(const struct HAL_SPI_CFG_T *cfg) { SPI_ASSERT(cfg->tx_bits == cfg->rx_bits && cfg->rx_frame_bits == 0, "ISPI: Bad bits cfg"); return hal_spi_open_id(HAL_SPI_ID_INTERNAL, cfg, NULL); } int hal_ispi_close(uint32_t cs) { return hal_spi_close_id(HAL_SPI_ID_INTERNAL, cs); } void hal_ispi_activate_cs(uint32_t cs) { SPI_ASSERT(cs < HAL_SPI_CS_QTY, "ISPI: SPI cs bad: %d", cs); hal_spi_set_cs_id(HAL_SPI_ID_INTERNAL, cs); } int hal_ispi_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_INTERNAL); } int hal_ispi_send(const void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_INTERNAL])) { return -31; } ret = hal_spi_send_id(HAL_SPI_ID_INTERNAL, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_INTERNAL]); return ret; } int hal_ispi_recv(const void *cmd, void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_INTERNAL])) { return -31; } ret = hal_spi_recv_id(HAL_SPI_ID_INTERNAL, cmd, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_INTERNAL]); return ret; } int hal_ispi_dma_send(const void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_INTERNAL])) { return -31; } ret = hal_spi_dma_send_id(HAL_SPI_ID_INTERNAL, data, len, handler); if (ret || handler == NULL) { clear_bool_flag(&in_use[HAL_SPI_ID_INTERNAL]); } return ret; } int hal_ispi_dma_recv(const void *cmd, void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_INTERNAL])) { return -31; } ret = hal_spi_dma_recv_id(HAL_SPI_ID_INTERNAL, cmd, data, len, handler); if (ret || handler == NULL) { clear_bool_flag(&in_use[HAL_SPI_ID_INTERNAL]); } return ret; } void hal_ispi_stop_dma_send(void) { hal_spi_stop_dma_send_id(HAL_SPI_ID_INTERNAL); } void hal_ispi_stop_dma_recv(void) { hal_spi_stop_dma_recv_id(HAL_SPI_ID_INTERNAL); } #ifdef CHIP_HAS_SPI //------------------------------------------------------------ // SPI peripheral functions //------------------------------------------------------------ int hal_spi_open(const struct HAL_SPI_CFG_T *cfg) { int ret; uint32_t lock; if (cfg->cs >= HAL_SPI_CS_QTY) { return -1; } lock = int_lock(); ret = hal_spi_open_id(HAL_SPI_ID_0, cfg, &spi0_ctrl[cfg->cs]); #if (CHIP_SPI_VER >= 2) if (ret == 0) { spi0_cs = cfg->cs; } #endif int_unlock(lock); return ret; } int hal_spi_close(uint32_t cs) { int ret; uint32_t lock; lock = int_lock(); ret = hal_spi_close_id(HAL_SPI_ID_0, cs); #if (CHIP_SPI_VER >= 2) if (ret == 0 && spi0_cs == cs) { uint32_t lowest_cs; lowest_cs = __CLZ(__RBIT(spi_cs_map[HAL_SPI_ID_0])); if (lowest_cs < HAL_SPI_CS_QTY) { hal_spi_activate_cs_id(HAL_SPI_ID_0, lowest_cs); } else { lowest_cs = HAL_SPI_CS_0; } spi0_cs = lowest_cs; } #endif int_unlock(lock); return ret; } int hal_spi_activate_cs(uint32_t cs) { return hal_spi_activate_cs_id(HAL_SPI_ID_0, cs); } int hal_spi_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_0); } int hal_spi_send(const void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_0])) { return -31; } ret = hal_spi_send_id(HAL_SPI_ID_0, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_0]); return ret; } int hal_spi_recv(const void *cmd, void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_0])) { return -31; } hal_spi_set_xfer_type_id(HAL_SPI_ID_0, &spi0_ctrl[spi0_cs], HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_recv_id(HAL_SPI_ID_0, cmd, data, len); hal_spi_set_xfer_type_id(HAL_SPI_ID_0, &spi0_ctrl[spi0_cs], HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[HAL_SPI_ID_0]); return ret; } int hal_spi_dma_send(const void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_0])) { return -31; } ret = hal_spi_dma_send_id(HAL_SPI_ID_0, data, len, handler); if (ret || handler == NULL) { clear_bool_flag(&in_use[HAL_SPI_ID_0]); } return ret; } int hal_spi_dma_recv(const void *cmd, void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_0])) { return -31; } hal_spi_set_xfer_type_id(HAL_SPI_ID_0, &spi0_ctrl[spi0_cs], HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_dma_recv_id(HAL_SPI_ID_0, cmd, data, len, handler); if (ret || handler == NULL) { hal_spi_set_xfer_type_id(HAL_SPI_ID_0, &spi0_ctrl[spi0_cs], HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[HAL_SPI_ID_0]); } return ret; } void hal_spi_stop_dma_send(void) { hal_spi_stop_dma_send_id(HAL_SPI_ID_0); } void hal_spi_stop_dma_recv(void) { hal_spi_stop_dma_recv_id(HAL_SPI_ID_0); } int hal_spi_enable_and_send(const struct HAL_SPI_CTRL_T *ctrl, const void *data, uint32_t len) { return hal_spi_enable_and_send_id(HAL_SPI_ID_0, ctrl, data, len); } int hal_spi_enable_and_recv(const struct HAL_SPI_CTRL_T *ctrl, const void *cmd, void *data, uint32_t len) { return hal_spi_enable_and_recv_id(HAL_SPI_ID_0, ctrl, cmd, data, len); } #endif // CHIP_HAS_SPI #ifdef CHIP_HAS_SPILCD //------------------------------------------------------------ // SPI LCD functions //------------------------------------------------------------ int hal_spilcd_open(const struct HAL_SPI_CFG_T *cfg) { int ret; uint32_t lock; if (cfg->cs >= HAL_SPI_CS_QTY) { return -1; } lock = int_lock(); ret = hal_spi_open_id(HAL_SPI_ID_SLCD, cfg, &spilcd_ctrl[cfg->cs]); #if (CHIP_SPI_VER >= 2) if (ret == 0) { spilcd_cs = cfg->cs; } #endif int_unlock(lock); return ret; } int hal_spilcd_close(uint32_t cs) { int ret; uint32_t lock; lock = int_lock(); ret = hal_spi_close_id(HAL_SPI_ID_SLCD, cs); #if (CHIP_SPI_VER >= 2) if (ret == 0 && spilcd_cs == cs) { uint32_t lowest_cs; lowest_cs = __CLZ(__RBIT(spi_cs_map[HAL_SPI_ID_SLCD])); if (lowest_cs < HAL_SPI_CS_QTY) { hal_spi_activate_cs_id(HAL_SPI_ID_SLCD, lowest_cs); } else { lowest_cs = HAL_SPI_CS_0; } spilcd_cs = lowest_cs; } #endif int_unlock(lock); return ret; } int hal_spilcd_activate_cs(uint32_t cs) { return hal_spi_activate_cs_id(HAL_SPI_ID_SLCD, cs); } int hal_spilcd_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_SLCD); } int hal_spilcd_send(const void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } ret = hal_spi_send_id(HAL_SPI_ID_SLCD, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); return ret; } int hal_spilcd_recv(const void *cmd, void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } hal_spi_set_xfer_type_id(HAL_SPI_ID_SLCD, &spilcd_ctrl[spilcd_cs], HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_recv_id(HAL_SPI_ID_SLCD, cmd, data, len); hal_spi_set_xfer_type_id(HAL_SPI_ID_SLCD, &spilcd_ctrl[spilcd_cs], HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); return ret; } int hal_spilcd_dma_send(const void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } ret = hal_spi_dma_send_id(HAL_SPI_ID_SLCD, data, len, handler); if (ret || handler == NULL) { clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); } return ret; } int hal_spilcd_dma_recv(const void *cmd, void *data, uint32_t len, HAL_SPI_DMA_HANDLER_T handler) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } hal_spi_set_xfer_type_id(HAL_SPI_ID_SLCD, &spilcd_ctrl[spilcd_cs], HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_dma_recv_id(HAL_SPI_ID_SLCD, cmd, data, len, handler); if (ret || handler == NULL) { hal_spi_set_xfer_type_id(HAL_SPI_ID_SLCD, &spilcd_ctrl[spilcd_cs], HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); } return ret; } void hal_spilcd_stop_dma_send(void) { hal_spi_stop_dma_send_id(HAL_SPI_ID_SLCD); } void hal_spilcd_stop_dma_recv(void) { hal_spi_stop_dma_recv_id(HAL_SPI_ID_SLCD); } int hal_spilcd_set_data_mode(void) { if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } spi[HAL_SPI_ID_SLCD]->SSPCR1 |= SPI_LCD_DC_DATA; clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); return 0; } int hal_spilcd_set_cmd_mode(void) { if (set_bool_flag(&in_use[HAL_SPI_ID_SLCD])) { return -31; } spi[HAL_SPI_ID_SLCD]->SSPCR1 &= ~SPI_LCD_DC_DATA; clear_bool_flag(&in_use[HAL_SPI_ID_SLCD]); return 0; } int hal_spilcd_enable_and_send(const struct HAL_SPI_CTRL_T *ctrl, const void *data, uint32_t len) { return hal_spi_enable_and_send_id(HAL_SPI_ID_SLCD, ctrl, data, len); } int hal_spilcd_enable_and_recv(const struct HAL_SPI_CTRL_T *ctrl, const void *cmd, void *data, uint32_t len) { return hal_spi_enable_and_recv_id(HAL_SPI_ID_SLCD, ctrl, cmd, data, len); } #endif // CHIP_HAS_SPILCD #ifdef CHIP_HAS_SPIPHY //------------------------------------------------------------ // SPI PHY functions //------------------------------------------------------------ int hal_spiphy_open(const struct HAL_SPI_CFG_T *cfg) { SPI_ASSERT(cfg->tx_bits == cfg->rx_bits && cfg->rx_frame_bits == 0, "SPIPHY: Bad bits cfg"); return hal_spi_open_id(HAL_SPI_ID_PHY, cfg, NULL); } int hal_spiphy_close(uint32_t cs) { return hal_spi_close_id(HAL_SPI_ID_PHY, cs); } void hal_spiphy_activate_cs(uint32_t cs) { SPI_ASSERT(cs < HAL_SPI_CS_QTY, "SPIPHY: SPI cs bad: %d", cs); hal_spi_set_cs_id(HAL_SPI_ID_PHY, cs); } int hal_spiphy_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_PHY); } int hal_spiphy_send(const void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_PHY])) { return -31; } ret = hal_spi_send_id(HAL_SPI_ID_PHY, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_PHY]); return ret; } int hal_spiphy_recv(const void *cmd, void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_PHY])) { return -31; } ret = hal_spi_recv_id(HAL_SPI_ID_PHY, cmd, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_PHY]); return ret; } #endif // CHIP_HAS_SPIPHY #ifdef CHIP_HAS_SPIDPD //------------------------------------------------------------ // SPI DPD functions //------------------------------------------------------------ int hal_spidpd_open(const struct HAL_SPI_CFG_T *cfg) { SPI_ASSERT(cfg->rx_frame_bits == 0, "SPIDPD: Bad bits cfg"); return hal_spi_open_id(HAL_SPI_ID_DPD, cfg, &spidpd_ctrl); } int hal_spidpd_close(uint32_t cs) { return hal_spi_close_id(HAL_SPI_ID_DPD, cs); } void hal_spidpd_activate_cs(uint32_t cs) { SPI_ASSERT(cs < HAL_SPI_CS_QTY, "SPIDPD: SPI cs bad: %d", cs); hal_spi_set_cs_id(HAL_SPI_ID_DPD, cs); } int hal_spidpd_busy(void) { return hal_spi_busy_id(HAL_SPI_ID_DPD); } int hal_spidpd_send(const void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_DPD])) { return -31; } ret = hal_spi_send_id(HAL_SPI_ID_DPD, data, len); clear_bool_flag(&in_use[HAL_SPI_ID_DPD]); return ret; } int hal_spidpd_recv(const void *cmd, void *data, uint32_t len) { int ret; if (set_bool_flag(&in_use[HAL_SPI_ID_DPD])) { return -31; } hal_spi_set_xfer_type_id(HAL_SPI_ID_DPD, &spidpd_ctrl, HAL_SPI_XFER_TYPE_RECV); ret = hal_spi_recv_id(HAL_SPI_ID_DPD, cmd, data, len); hal_spi_set_xfer_type_id(HAL_SPI_ID_DPD, &spidpd_ctrl, HAL_SPI_XFER_TYPE_SEND); clear_bool_flag(&in_use[HAL_SPI_ID_DPD]); return ret; } #endif // CHIP_HAS_SPIDPD #endif // !SPI_ROM_ONLY