/****************************************************************************** * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. * ******************************************************************************/ #include <stdio.h> #include <stddef.h> #include <stdint.h> #include <string.h> #include "mxc_device.h" #include "mxc_assert.h" #include "mxc_lock.h" #include "mxc_sys.h" #include "mxc_delay.h" #include "mxc_spi.h" #include "spi_reva.h" #include "dma_reva.h" /* **** Definitions **** */ typedef struct { mxc_spi_reva_req_t *req; int started; unsigned last_size; unsigned ssDeassert; unsigned defaultTXData; int channelTx; int channelRx; int mtMode; int mtFirstTrans; bool txrx_req; uint8_t req_done; uint8_t async; unsigned drv_ssel; } spi_req_reva_state_t; static spi_req_reva_state_t states[MXC_SPI_INSTANCES]; static uint32_t MXC_SPI_RevA_MasterTransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva_req_t *req); static uint32_t MXC_SPI_RevA_TransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva_req_t *req); static uint32_t MXC_SPI_RevA_SlaveTransHandler(mxc_spi_reva_req_t *req); static void MXC_SPI_RevA_SwapByte(uint8_t *arr, size_t length); static int MXC_SPI_RevA_TransSetup(mxc_spi_reva_req_t *req); int MXC_SPI_RevA_Init(mxc_spi_reva_regs_t *spi, int masterMode, int quadModeUsed, int numSlaves, unsigned ssPolarity, unsigned int hz, unsigned int drv_ssel) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); states[spi_num].req = NULL; states[spi_num].last_size = 0; states[spi_num].ssDeassert = 1; states[spi_num].defaultTXData = 0; states[spi_num].mtMode = 0; states[spi_num].mtFirstTrans = 0; states[spi_num].channelTx = E_NO_DEVICE; states[spi_num].channelRx = E_NO_DEVICE; states[spi_num].drv_ssel = drv_ssel; spi->ctrl0 = (MXC_F_SPI_REVA_CTRL0_EN); spi->sstime = ((0x1 << MXC_F_SPI_REVA_SSTIME_PRE_POS) | (0x1 << MXC_F_SPI_REVA_SSTIME_POST_POS) | (0x1 << MXC_F_SPI_REVA_SSTIME_INACT_POS)); //set master if (masterMode) { spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_MST_MODE; } else { spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_MST_MODE); } MXC_SPI_SetFrequency((mxc_spi_regs_t *)spi, hz); if (ssPolarity > (MXC_F_SPI_REVA_CTRL2_SS_POL >> MXC_F_SPI_REVA_CTRL2_SS_POL_POS)) { return E_BAD_PARAM; } //set slave select polarity spi->ctrl2 |= (ssPolarity << MXC_F_SPI_REVA_CTRL2_SS_POL_POS); // Clear the interrupts spi->intfl = spi->intfl; // Driver will drive SS pin? if (states[spi_num].drv_ssel) { if (numSlaves == 1) { spi->ctrl0 |= MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS0; } else if (numSlaves == 2) { spi->ctrl0 |= (MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS0 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS1); } else if (numSlaves == 3) { spi->ctrl0 |= (MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS0 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS1 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS2); } else if (numSlaves == 4) { spi->ctrl0 |= (MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS0 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS1 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS2 | MXC_S_SPI_REVA_CTRL0_SS_ACTIVE_SS3); } } //set quad mode if (quadModeUsed) { spi->ctrl2 |= MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_QUAD; } return E_NO_ERROR; } int MXC_SPI_RevA_Shutdown(mxc_spi_reva_regs_t *spi) { int spi_num; mxc_spi_reva_req_t *temp_req; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); //disable and clear interrupts spi->inten = 0; spi->intfl = spi->intfl; // Disable SPI and FIFOS spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); spi->dma &= ~(MXC_F_SPI_REVA_DMA_TX_FIFO_EN | MXC_F_SPI_REVA_DMA_RX_FIFO_EN); //call all of the pending callbacks for this spi spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); if (states[spi_num].req != NULL) { //save the request temp_req = states[spi_num].req; MXC_FreeLock((uint32_t *)(uint32_t *)&states[spi_num].req); // Callback if not NULL if (states[spi_num].req->completeCB != NULL) { states[spi_num].req->completeCB(temp_req, E_SHUTDOWN); } } // Clear registers spi->ctrl0 = 0; spi->ctrl1 = 0; spi->ctrl2 = 0; spi->sstime = 0; // release any acquired DMA channels if (states[spi_num].channelTx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelTx); states[spi_num].channelTx = E_NO_DEVICE; } if (states[spi_num].channelRx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelRx); states[spi_num].channelRx = E_NO_DEVICE; } return E_NO_ERROR; } int MXC_SPI_RevA_ReadyForSleep(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); if (spi->stat & MXC_F_SPI_REVA_STAT_BUSY || (spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) || (spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL)) { return E_BUSY; } else { return E_NO_ERROR; } } int MXC_SPI_RevA_SetFrequency(mxc_spi_reva_regs_t *spi, unsigned int hz) { int hi_clk, lo_clk, scale; uint32_t freq_div; // Check if frequency is too high if (hz > PeripheralClock) { return E_BAD_PARAM; } // Set the clock high and low freq_div = MXC_SPI_GetPeripheralClock((mxc_spi_regs_t *)spi); freq_div = (freq_div / hz); hi_clk = freq_div / 2; lo_clk = freq_div / 2; scale = 0; if (freq_div % 2) { hi_clk += 1; } while (hi_clk >= 16 && scale < 8) { hi_clk /= 2; lo_clk /= 2; scale++; } if (scale == 8) { lo_clk = 15; hi_clk = 15; } MXC_SETFIELD(spi->clkctrl, MXC_F_SPI_REVA_CLKCTRL_LO, (lo_clk << MXC_F_SPI_REVA_CLKCTRL_LO_POS)); MXC_SETFIELD(spi->clkctrl, MXC_F_SPI_REVA_CLKCTRL_HI, (hi_clk << MXC_F_SPI_REVA_CLKCTRL_HI_POS)); MXC_SETFIELD(spi->clkctrl, MXC_F_SPI_REVA_CLKCTRL_CLKDIV, (scale << MXC_F_SPI_REVA_CLKCTRL_CLKDIV_POS)); return E_NO_ERROR; } unsigned int MXC_SPI_RevA_GetFrequency(mxc_spi_reva_regs_t *spi) { if (MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) < 0) { return E_BAD_PARAM; } unsigned scale, lo_clk, hi_clk; scale = (spi->clkctrl & MXC_F_SPI_REVA_CLKCTRL_CLKDIV) >> MXC_F_SPI_REVA_CLKCTRL_CLKDIV_POS; hi_clk = (spi->clkctrl & MXC_F_SPI_REVA_CLKCTRL_HI) >> MXC_F_SPI_REVA_CLKCTRL_HI_POS; lo_clk = (spi->clkctrl & MXC_F_SPI_REVA_CLKCTRL_LO) >> MXC_F_SPI_REVA_CLKCTRL_LO_POS; return (PeripheralClock / (1 << scale)) / (lo_clk + hi_clk); } int MXC_SPI_RevA_SetDataSize(mxc_spi_reva_regs_t *spi, int dataSize) { int spi_num; // HW has problem with these two character sizes if (dataSize == 1 || dataSize > 16) { return E_BAD_PARAM; } spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); // Setup the character size if (!(spi->stat & MXC_F_SPI_REVA_STAT_BUSY) && states[spi_num].ssDeassert == 1) { //disable spi to change transfer size spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); // set bit size states[spi_num].last_size = dataSize; if (dataSize < 16) { MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, dataSize << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); } else { MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, 0 << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); //may not be neccessary } //enable spi to change transfer size spi->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); } else { return E_BAD_STATE; } return E_NO_ERROR; } int MXC_SPI_RevA_GetDataSize(mxc_spi_reva_regs_t *spi) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; if (!(spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_NUMBITS)) { return 16; } return (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_NUMBITS) >> MXC_F_SPI_REVA_CTRL2_NUMBITS_POS; } int MXC_SPI_RevA_SetMTMode(mxc_spi_reva_regs_t *spi, int mtMode) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); if ((mtMode != 0) && (mtMode != 1)) { return E_BAD_PARAM; } if (states[spi_num].mtMode == 1) { if (mtMode == 0) { // exiting MT Mode: release any acquired DMA channels if (states[spi_num].channelTx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelTx); states[spi_num].channelTx = E_NO_DEVICE; } if (states[spi_num].channelRx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelRx); states[spi_num].channelRx = E_NO_DEVICE; } } } else if (mtMode == 1) { // entering MT Mode: set first transaction states[spi_num].mtFirstTrans = 1; } states[spi_num].mtMode = mtMode; return E_NO_ERROR; } int MXC_SPI_RevA_GetMTMode(mxc_spi_reva_regs_t *spi) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); return states[spi_num].mtMode; } int MXC_SPI_RevA_SetSlave(mxc_spi_reva_regs_t *spi, int ssIdx) { int spi_num; // HW has problem with these two character sizes if (ssIdx >= MXC_SPI_SS_INSTANCES) { return E_BAD_PARAM; } //check if in master mode if (!(spi->ctrl0 & MXC_F_SPI_REVA_CTRL0_MST_MODE)) { return E_BAD_STATE; } spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; if (states[spi_num].drv_ssel) { // Setup the slave select // Activate chosen SS pin spi->ctrl0 |= (1 << ssIdx) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS; // Deactivate all unchosen pins spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_ACTIVE | ((1 << ssIdx) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS); } return E_NO_ERROR; } int MXC_SPI_RevA_GetSlave(mxc_spi_reva_regs_t *spi) { int spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; return ((spi->ctrl0 & MXC_F_SPI_REVA_CTRL0_SS_ACTIVE) >> MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS) >> 1; } int MXC_SPI_RevA_SetWidth(mxc_spi_reva_regs_t *spi, mxc_spi_reva_width_t spiWidth) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; spi->ctrl2 &= ~(MXC_F_SPI_REVA_CTRL2_THREE_WIRE | MXC_F_SPI_REVA_CTRL2_DATA_WIDTH); switch (spiWidth) { case SPI_REVA_WIDTH_3WIRE: spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_THREE_WIRE; break; case SPI_REVA_WIDTH_STANDARD: spi->ctrl2 |= MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_MONO; break; case SPI_REVA_WIDTH_DUAL: spi->ctrl2 |= MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_DUAL; break; case SPI_REVA_WIDTH_QUAD: spi->ctrl2 |= MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_QUAD; break; } return E_NO_ERROR; } mxc_spi_reva_width_t MXC_SPI_RevA_GetWidth(mxc_spi_reva_regs_t *spi) { if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_THREE_WIRE) { return SPI_REVA_WIDTH_3WIRE; } if (spi->ctrl2 & MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_DUAL) { return SPI_REVA_WIDTH_DUAL; } if (spi->ctrl2 & MXC_S_SPI_REVA_CTRL2_DATA_WIDTH_QUAD) { return SPI_REVA_WIDTH_QUAD; } return SPI_REVA_WIDTH_STANDARD; } int MXC_SPI_RevA_SetMode(mxc_spi_reva_regs_t *spi, mxc_spi_reva_mode_t spiMode) { int spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; switch (spiMode) { case SPI_REVA_MODE_0: spi->ctrl2 &= ~MXC_F_SPI_REVA_CTRL2_CLKPHA; spi->ctrl2 &= ~MXC_F_SPI_REVA_CTRL2_CLKPOL; break; case SPI_REVA_MODE_1: spi->ctrl2 &= ~MXC_F_SPI_REVA_CTRL2_CLKPHA; spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_CLKPOL; break; case SPI_REVA_MODE_2: spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_CLKPHA; spi->ctrl2 &= ~MXC_F_SPI_REVA_CTRL2_CLKPOL; break; case SPI_REVA_MODE_3: spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_CLKPHA; spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_CLKPOL; break; default: break; } return E_NO_ERROR; } mxc_spi_reva_mode_t MXC_SPI_RevA_GetMode(mxc_spi_reva_regs_t *spi) { int spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_CLKPHA) { if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_CLKPOL) { return SPI_REVA_MODE_3; } else { return SPI_REVA_MODE_2; } } else { if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_CLKPOL) { return SPI_REVA_MODE_1; } } return SPI_REVA_MODE_0; } int MXC_SPI_RevA_StartTransmission(mxc_spi_reva_regs_t *spi) { int spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); (void)spi_num; if (MXC_SPI_GetActive((mxc_spi_regs_t *)spi) == E_BUSY) { return E_BUSY; } spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; return E_NO_ERROR; } int MXC_SPI_RevA_GetActive(mxc_spi_reva_regs_t *spi) { if (spi->stat & MXC_F_SPI_REVA_STAT_BUSY) { return E_BUSY; } return E_NO_ERROR; } int MXC_SPI_RevA_AbortTransmission(mxc_spi_reva_regs_t *spi) { int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); // Disable interrupts, clear the flags spi->inten = 0; spi->intfl = spi->intfl; // Reset the SPI17Y to cancel the on ongoing transaction spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); spi->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); // Unlock this SPI mxc_spi_reva_req_t *temp = states[spi_num].req; MXC_FreeLock((uint32_t *)&states[spi_num].req); // Callback if not NULL if (temp->completeCB != NULL) { temp->completeCB(states[spi_num].req, E_ABORT); } // release any acquired DMA channels if (states[spi_num].channelTx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelTx); states[spi_num].channelTx = E_NO_DEVICE; } if (states[spi_num].channelRx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[spi_num].channelRx); states[spi_num].channelRx = E_NO_DEVICE; } if (states[spi_num].mtMode == 1) { states[spi_num].mtFirstTrans = 1; } return E_NO_ERROR; } unsigned int MXC_SPI_RevA_ReadRXFIFO(mxc_spi_reva_regs_t *spi, unsigned char *bytes, unsigned int len) { unsigned rx_avail, bits; MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); if (!bytes || !len) { return 0; } rx_avail = MXC_SPI_GetRXFIFOAvailable((mxc_spi_regs_t *)spi); bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)spi); if (len > rx_avail) { len = rx_avail; } if (bits > 8) { len &= ~(unsigned)0x1; } unsigned cnt = 0; if (bits <= 8 || len >= 2) { // Read from the FIFO while (len) { if (len > 3) { memcpy((uint8_t *)(&bytes[cnt]), (void *)(&spi->fifo32), 4); len -= 4; cnt += 4; } else if (len > 1) { memcpy((uint8_t *)(&bytes[cnt]), (void *)(&spi->fifo16[0]), 2); len -= 2; cnt += 2; } else { ((uint8_t *)bytes)[cnt++] = spi->fifo8[0]; len -= 1; } // Don't read less than 2 bytes if we are using greater than 8 bit characters if (len == 1 && bits > 8) { break; } } } return cnt; } unsigned int MXC_SPI_RevA_GetRXFIFOAvailable(mxc_spi_reva_regs_t *spi) { return (spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL) >> MXC_F_SPI_REVA_DMA_RX_LVL_POS; } unsigned int MXC_SPI_RevA_WriteTXFIFO(mxc_spi_reva_regs_t *spi, unsigned char *bytes, unsigned int len) { unsigned tx_avail, bits; MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); if (!bytes || !len) { return 0; } tx_avail = MXC_SPI_GetTXFIFOAvailable((mxc_spi_regs_t *)spi); bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)spi); if (len > tx_avail) { len = tx_avail; } if (bits > 8) { len &= ~(unsigned)0x1; } unsigned cnt = 0; while (len) { if (len > 3) { memcpy((void *)(&spi->fifo32), (uint8_t *)(&bytes[cnt]), 4); len -= 4; cnt += 4; } else if (len > 1) { memcpy((void *)(&spi->fifo16[0]), (uint8_t *)(&bytes[cnt]), 2); len -= 2; cnt += 2; } else if (bits <= 8) { spi->fifo8[0] = ((uint8_t *)bytes)[cnt++]; len--; } } return cnt; } unsigned int MXC_SPI_RevA_GetTXFIFOAvailable(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); return MXC_SPI_FIFO_DEPTH - ((spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) >> MXC_F_SPI_REVA_DMA_TX_LVL_POS); } void MXC_SPI_RevA_ClearRXFIFO(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); spi->dma |= MXC_F_SPI_REVA_DMA_RX_FLUSH; } void MXC_SPI_RevA_ClearTXFIFO(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); spi->dma |= MXC_F_SPI_REVA_DMA_TX_FLUSH; } int MXC_SPI_RevA_SetRXThreshold(mxc_spi_reva_regs_t *spi, unsigned int numBytes) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); if (numBytes > 32) { return E_BAD_PARAM; } MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, numBytes << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS); return E_NO_ERROR; } unsigned int MXC_SPI_RevA_GetRXThreshold(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); return (spi->dma & MXC_F_SPI_REVA_DMA_RX_THD_VAL) >> MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS; } int MXC_SPI_RevA_SetTXThreshold(mxc_spi_reva_regs_t *spi, unsigned int numBytes) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); if (numBytes > 32) { return E_BAD_PARAM; } MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, numBytes << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS); return E_NO_ERROR; } unsigned int MXC_SPI_RevA_GetTXThreshold(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); return (spi->dma & MXC_F_SPI_REVA_DMA_TX_THD_VAL) >> MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS; } unsigned int MXC_SPI_RevA_GetFlags(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); return spi->intfl; } void MXC_SPI_RevA_ClearFlags(mxc_spi_reva_regs_t *spi) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); spi->intfl = spi->intfl; } void MXC_SPI_RevA_EnableInt(mxc_spi_reva_regs_t *spi, unsigned int intEn) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); spi->inten |= intEn; } void MXC_SPI_RevA_DisableInt(mxc_spi_reva_regs_t *spi, unsigned int intDis) { MXC_ASSERT(MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) >= 0); spi->inten &= ~(intDis); } int MXC_SPI_RevA_TransSetup(mxc_spi_reva_req_t *req) { int spi_num; uint8_t bits; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)(req->spi)); MXC_ASSERT(spi_num >= 0); MXC_ASSERT(req->ssIdx < MXC_SPI_SS_INSTANCES); if ((!req) || ((req->txData == NULL) && (req->rxData == NULL))) { return E_BAD_PARAM; } // Setup the number of characters to transact if (req->txLen > (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)) { return E_BAD_PARAM; } bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)req->spi); req->txCnt = 0; req->rxCnt = 0; states[spi_num].req = req; states[spi_num].started = 0; states[spi_num].req_done = 0; // HW requires disabling/renabling SPI block at end of each transaction (when SS is inactive). if (states[spi_num].ssDeassert == 1) { (req->spi)->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); } //if master if ((req->spi)->ctrl0 & MXC_F_SPI_REVA_CTRL0_MST_MODE) { // Setup the slave select MXC_SPI_SetSlave((mxc_spi_regs_t *)req->spi, req->ssIdx); } if (req->rxData != NULL && req->rxLen > 0) { MXC_SETFIELD((req->spi)->ctrl1, MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR, req->rxLen << MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS); (req->spi)->dma |= MXC_F_SPI_REVA_DMA_RX_FIFO_EN; } else { (req->spi)->ctrl1 &= ~(MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR); (req->spi)->dma &= ~(MXC_F_SPI_REVA_DMA_RX_FIFO_EN); } // Must use TXFIFO and NUM in full duplex//start editing here if ((mxc_spi_reva_width_t)MXC_SPI_GetWidth((mxc_spi_regs_t *)req->spi) == SPI_REVA_WIDTH_STANDARD && !(((req->spi)->ctrl2 & MXC_F_SPI_REVA_CTRL2_THREE_WIRE) >> MXC_F_SPI_REVA_CTRL2_THREE_WIRE_POS)) { if (req->txData == NULL) { // Must have something to send, so we'll use the rx_data buffer initialized to 0. //SPI_SetDefaultTXData(spi, 0); memset(req->rxData, states[spi_num].defaultTXData, (bits > 8 ? req->rxLen << 1 : req->rxLen)); req->txData = req->rxData; req->txLen = req->rxLen; } } if (req->txData != NULL && req->txLen > 0) { MXC_SETFIELD((req->spi)->ctrl1, MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR, req->txLen << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); (req->spi)->dma |= MXC_F_SPI_REVA_DMA_TX_FIFO_EN; } else { (req->spi)->ctrl1 &= ~(MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR); (req->spi)->dma &= ~(MXC_F_SPI_REVA_DMA_TX_FIFO_EN); } if ((req->txData != NULL && req->txLen) && (req->rxData != NULL && req->rxLen)) { states[spi_num].txrx_req = true; } else { states[spi_num].txrx_req = false; } (req->spi)->dma |= (MXC_F_SPI_REVA_DMA_TX_FLUSH | MXC_F_SPI_REVA_DMA_RX_FLUSH); (req->spi)->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); states[spi_num].ssDeassert = req->ssDeassert; // Clear master done flag (req->spi)->intfl = MXC_F_SPI_REVA_INTFL_MST_DONE; return E_NO_ERROR; } uint32_t MXC_SPI_RevA_MasterTransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva_req_t *req) { uint32_t retval; int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); // Leave slave select asserted at the end of the transaction if (states[spi_num].drv_ssel) { if (!req->ssDeassert) { spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_SS_CTRL; } } retval = MXC_SPI_RevA_TransHandler(spi, req); if (!states[spi_num].started) { MXC_SPI_StartTransmission((mxc_spi_regs_t *)spi); states[spi_num].started = 1; } // Deassert slave select at the end of the transaction if (states[spi_num].drv_ssel) { if (req->ssDeassert) { spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_CTRL; } } return retval; } uint32_t MXC_SPI_RevA_SlaveTransHandler(mxc_spi_reva_req_t *req) { return MXC_SPI_RevA_TransHandler(req->spi, req); } uint32_t MXC_SPI_RevA_TransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva_req_t *req) { int remain, spi_num; uint32_t int_en = 0; uint32_t tx_length = 0, rx_length = 0; uint8_t bits; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)req->spi); //MXC_F_SPI_REVA_CTRL2_NUMBITS data bits // Read/write 2x number of bytes if larger character size if (bits > 8) { tx_length = req->txLen * 2; rx_length = req->rxLen * 2; } else { tx_length = req->txLen; rx_length = req->rxLen; } if (req->txData != NULL) { req->txCnt += MXC_SPI_WriteTXFIFO((mxc_spi_regs_t *)spi, &(req->txData[req->txCnt]), tx_length - req->txCnt); } remain = tx_length - req->txCnt; // Set the TX interrupts // Write the FIFO //starting here if (remain) { if (remain > MXC_SPI_FIFO_DEPTH) { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)spi, MXC_SPI_FIFO_DEPTH); } else { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)spi, remain); } int_en |= MXC_F_SPI_REVA_INTEN_TX_THD; } // Break out if we've transmitted all the bytes and not receiving if ((req->rxData == NULL) && (req->txCnt == tx_length)) { spi->inten = 0; int_en = 0; MXC_FreeLock((uint32_t *)&states[spi_num].req); // Callback if not NULL if (states[spi_num].async && req->completeCB != NULL) { req->completeCB(req, E_NO_ERROR); } } // Read the RX FIFO if (req->rxData != NULL) { req->rxCnt += MXC_SPI_ReadRXFIFO((mxc_spi_regs_t *)spi, &(req->rxData[req->rxCnt]), rx_length - req->rxCnt); remain = rx_length - req->rxCnt; if (remain) { if (remain > MXC_SPI_FIFO_DEPTH) { MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)spi, 2); } else { MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)spi, remain - 1); } int_en |= MXC_F_SPI_REVA_INTEN_RX_THD; } // Break out if we've received all the bytes and we're not transmitting if ((req->txData == NULL) && (req->rxCnt == rx_length)) { spi->inten = 0; int_en = 0; MXC_FreeLock((uint32_t *)&states[spi_num].req); // Callback if not NULL if (states[spi_num].async && req->completeCB != NULL) { req->completeCB(req, E_NO_ERROR); } } } // Break out once we've transmitted and received all of the data if ((req->rxCnt == rx_length) && (req->txCnt == tx_length)) { spi->inten = 0; int_en = 0; MXC_FreeLock((uint32_t *)&states[spi_num].req); // Callback if not NULL if (states[spi_num].async && req->completeCB != NULL) { req->completeCB(req, E_NO_ERROR); } } return int_en; } int MXC_SPI_RevA_MasterTransaction(mxc_spi_reva_req_t *req) { int error; if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } states[MXC_SPI_GET_IDX((mxc_spi_regs_t *)req->spi)].async = 0; //call master transHandler while (MXC_SPI_RevA_MasterTransHandler(req->spi, req) != 0) {} while (!((req->spi)->intfl & MXC_F_SPI_REVA_INTFL_MST_DONE)) {} return E_NO_ERROR; } int MXC_SPI_RevA_MasterTransactionAsync(mxc_spi_reva_req_t *req) { int error; if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } states[MXC_SPI_GET_IDX((mxc_spi_regs_t *)req->spi)].async = 1; MXC_SPI_EnableInt((mxc_spi_regs_t *)req->spi, MXC_SPI_RevA_MasterTransHandler(req->spi, req)); return E_NO_ERROR; } int MXC_SPI_RevA_MasterTransactionDMA(mxc_spi_reva_req_t *req, int reqselTx, int reqselRx, mxc_dma_regs_t *dma) { int spi_num; uint8_t error, bits; mxc_dma_config_t config; mxc_dma_srcdst_t srcdst; mxc_dma_adv_config_t advConfig = { 0, 0, 0, 0, 0, 0 }; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)(req->spi)); MXC_ASSERT(spi_num >= 0); if (req->txData == NULL && req->rxData == NULL) { return E_BAD_PARAM; } if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } // for non-MT mode do this setup every time, for MT mode only first time if ((states[spi_num].mtMode == 0) || ((states[spi_num].mtMode == 1) && (states[spi_num].mtFirstTrans == 1))) { #if TARGET_NUM == 32665 MXC_DMA_Init(dma); states[spi_num].channelTx = MXC_DMA_AcquireChannel(dma); states[spi_num].channelRx = MXC_DMA_AcquireChannel(dma); #else MXC_DMA_Init(); states[spi_num].channelTx = MXC_DMA_AcquireChannel(); states[spi_num].channelRx = MXC_DMA_AcquireChannel(); #endif if ((states[spi_num].channelTx < 0) || (states[spi_num].channelRx < 0)) { states[spi_num].channelTx = E_NO_DEVICE; states[spi_num].channelRx = E_NO_DEVICE; return E_NO_DEVICE; } states[spi_num].mtFirstTrans = 0; MXC_DMA_SetCallback(states[spi_num].channelTx, MXC_SPI_RevA_DMACallback); MXC_DMA_SetCallback(states[spi_num].channelRx, MXC_SPI_RevA_DMACallback); MXC_DMA_EnableInt(states[spi_num].channelTx); MXC_DMA_EnableInt(states[spi_num].channelRx); // Configure SS for per-transaction or always on if (req->ssDeassert) { req->spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_CTRL; } else { req->spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_SS_CTRL; } } bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)req->spi); MXC_SPI_RevA_TransHandler(req->spi, req); if (bits <= 8) { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)req->spi, 1); //set threshold to 1 byte MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)req->spi, 0); //set threshold to 0 bytes } else { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)req->spi, 2); MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)req->spi, 0); } //tx if (req->txData != NULL) { config.reqsel = reqselTx; config.ch = states[spi_num].channelTx; advConfig.ch = states[spi_num].channelTx; advConfig.burst_size = 2; if (bits <= 8) { config.srcwd = MXC_DMA_WIDTH_BYTE; config.dstwd = MXC_DMA_WIDTH_BYTE; } else { config.srcwd = MXC_DMA_WIDTH_HALFWORD; config.dstwd = MXC_DMA_WIDTH_HALFWORD; } config.srcinc_en = 1; config.dstinc_en = 0; srcdst.ch = states[spi_num].channelTx; srcdst.source = &(req->txData[req->txCnt]); if (bits > 8) { srcdst.len = (req->txLen * 2) - req->txCnt; } else { srcdst.len = (req->txLen) - req->txCnt; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_Start(states[spi_num].channelTx); MXC_DMA_SetChannelInterruptEn(states[spi_num].channelTx, false, true); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; if (bits > 8) { MXC_DMA_AdvConfigChannel(advConfig); //MXC_SETFIELD (MXC_DMA->ch[channel].ctrl, MXC_F_DMA_CTRL_BURST_SIZE, 1 << MXC_F_DMA_CTRL_BURST_SIZE_POS); } } if (req->rxData != NULL) { config.reqsel = reqselRx; config.ch = states[spi_num].channelRx; config.srcinc_en = 0; config.dstinc_en = 1; advConfig.ch = states[spi_num].channelRx; advConfig.burst_size = 1; if (bits <= 8) { config.srcwd = MXC_DMA_WIDTH_BYTE; config.dstwd = MXC_DMA_WIDTH_BYTE; } else { config.srcwd = MXC_DMA_WIDTH_HALFWORD; config.dstwd = MXC_DMA_WIDTH_HALFWORD; } srcdst.ch = states[spi_num].channelRx; srcdst.dest = req->rxData; if (bits <= 8) { srcdst.len = req->rxLen; } else { srcdst.len = req->rxLen * 2; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_Start(states[spi_num].channelRx); MXC_DMA_SetChannelInterruptEn(states[spi_num].channelRx, false, true); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; if (bits > 8) { MXC_DMA_AdvConfigChannel(advConfig); //MXC_SETFIELD (MXC_DMA->ch[channel].ctrl, MXC_F_DMA_CTRL_BURST_SIZE, 0 << MXC_F_DMA_CTRL_BURST_SIZE_POS); } } (req->spi)->dma |= (MXC_F_SPI_REVA_DMA_DMA_TX_EN | MXC_F_SPI_REVA_DMA_DMA_RX_EN); if (!states[spi_num].started) { MXC_SPI_StartTransmission((mxc_spi_regs_t *)req->spi); states[spi_num].started = 1; } return E_NO_ERROR; } int MXC_SPI_RevA_SlaveTransaction(mxc_spi_reva_req_t *req) { int error; if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } states[MXC_SPI_GET_IDX((mxc_spi_regs_t *)req->spi)].async = 0; while (MXC_SPI_RevA_SlaveTransHandler(req) != 0) {} return E_NO_ERROR; } int MXC_SPI_RevA_SlaveTransactionAsync(mxc_spi_reva_req_t *req) { int error; if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } states[MXC_SPI_GET_IDX((mxc_spi_regs_t *)req->spi)].async = 1; MXC_SPI_EnableInt((mxc_spi_regs_t *)req->spi, MXC_SPI_RevA_SlaveTransHandler(req)); return E_NO_ERROR; } int MXC_SPI_RevA_SlaveTransactionDMA(mxc_spi_reva_req_t *req, int reqselTx, int reqselRx, mxc_dma_regs_t *dma) { int spi_num; uint8_t error, bits; mxc_dma_config_t config; mxc_dma_srcdst_t srcdst; mxc_dma_adv_config_t advConfig = { 0, 0, 0, 0, 0, 0 }; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)(req->spi)); MXC_ASSERT(spi_num >= 0); if (req->txData == NULL && req->rxData == NULL) { return E_BAD_PARAM; } if ((error = MXC_SPI_RevA_TransSetup(req)) != E_NO_ERROR) { return error; } // for non-MT mode do this setup every time, for MT mode only first time if ((states[spi_num].mtMode == 0) || ((states[spi_num].mtMode == 1) && (states[spi_num].mtFirstTrans == 1))) { #if TARGET_NUM == 32665 MXC_DMA_Init(dma); states[spi_num].channelTx = MXC_DMA_AcquireChannel(dma); states[spi_num].channelRx = MXC_DMA_AcquireChannel(dma); #else MXC_DMA_Init(); states[spi_num].channelTx = MXC_DMA_AcquireChannel(); states[spi_num].channelRx = MXC_DMA_AcquireChannel(); #endif if ((states[spi_num].channelTx < 0) || (states[spi_num].channelRx < 0)) { states[spi_num].channelTx = E_NO_DEVICE; states[spi_num].channelRx = E_NO_DEVICE; return E_NO_DEVICE; } states[spi_num].mtFirstTrans = 0; MXC_DMA_SetCallback(states[spi_num].channelTx, MXC_SPI_RevA_DMACallback); MXC_DMA_SetCallback(states[spi_num].channelRx, MXC_SPI_RevA_DMACallback); MXC_DMA_EnableInt(states[spi_num].channelTx); MXC_DMA_EnableInt(states[spi_num].channelRx); } bits = MXC_SPI_GetDataSize((mxc_spi_regs_t *)req->spi); MXC_SPI_RevA_TransHandler(req->spi, req); if (bits <= 8) { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)req->spi, 1); MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)req->spi, 0); } else { MXC_SPI_SetTXThreshold((mxc_spi_regs_t *)req->spi, 2); MXC_SPI_SetRXThreshold((mxc_spi_regs_t *)req->spi, 0); } //tx if (req->txData != NULL) { config.reqsel = reqselTx; config.ch = states[spi_num].channelTx; advConfig.ch = states[spi_num].channelTx; advConfig.burst_size = 2; if (bits <= 8) { config.srcwd = MXC_DMA_WIDTH_BYTE; config.dstwd = MXC_DMA_WIDTH_BYTE; } else { config.srcwd = MXC_DMA_WIDTH_HALFWORD; config.dstwd = MXC_DMA_WIDTH_HALFWORD; } config.srcinc_en = 1; config.dstinc_en = 0; srcdst.ch = states[spi_num].channelTx; srcdst.source = &(req->txData[req->txCnt]); if (bits > 8) { srcdst.len = (req->txLen * 2) - req->txCnt; } else { srcdst.len = (req->txLen) - req->txCnt; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_Start(states[spi_num].channelTx); MXC_DMA_SetChannelInterruptEn(states[spi_num].channelTx, false, true); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; if (bits > 8) { MXC_DMA_AdvConfigChannel(advConfig); //MXC_SETFIELD (MXC_DMA->ch[channel].ctrl, MXC_F_DMA_CTRL_BURST_SIZE, 1 << MXC_F_DMA_CTRL_BURST_SIZE_POS); } } if (req->rxData != NULL) { config.reqsel = reqselRx; config.ch = states[spi_num].channelRx; config.srcinc_en = 0; config.dstinc_en = 1; advConfig.ch = states[spi_num].channelRx; advConfig.burst_size = 1; if (bits <= 8) { config.srcwd = MXC_DMA_WIDTH_BYTE; config.dstwd = MXC_DMA_WIDTH_BYTE; } else { config.srcwd = MXC_DMA_WIDTH_HALFWORD; config.dstwd = MXC_DMA_WIDTH_HALFWORD; } srcdst.ch = states[spi_num].channelRx; srcdst.dest = req->rxData; if (bits <= 8) { srcdst.len = req->rxLen; } else { srcdst.len = req->rxLen * 2; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_Start(states[spi_num].channelRx); MXC_DMA_SetChannelInterruptEn(states[spi_num].channelRx, false, true); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; if (bits > 8) { MXC_DMA_AdvConfigChannel(advConfig); //MXC_SETFIELD (MXC_DMA->ch[channel].ctrl, MXC_F_DMA_CTRL_BURST_SIZE, 0 << MXC_F_DMA_CTRL_BURST_SIZE_POS); } } (req->spi)->dma |= (MXC_F_SPI_REVA_DMA_DMA_TX_EN | MXC_F_SPI_REVA_DMA_DMA_RX_EN); return E_NO_ERROR; } void MXC_SPI_RevA_DMACallback(int ch, int error) { mxc_spi_reva_req_t *temp_req; for (int i = 0; i < MXC_SPI_INSTANCES; i++) { if (states[i].req != NULL) { if (states[i].channelTx == ch) { states[i].req_done++; } else if (states[i].channelRx == ch) { states[i].req_done++; //save the request temp_req = states[i].req; if (MXC_SPI_GetDataSize((mxc_spi_regs_t *)temp_req->spi) > 8) { MXC_SPI_RevA_SwapByte(temp_req->rxData, temp_req->rxLen); } } if (!states[i].txrx_req || (states[i].txrx_req && states[i].req_done == 2)) { //save the request temp_req = states[i].req; MXC_FreeLock((uint32_t *)&states[i].req); // Callback if not NULL if (temp_req->completeCB != NULL) { temp_req->completeCB(temp_req, E_NO_ERROR); } if (states[i].mtMode == 0) { // release any acquired DMA channels if (states[i].channelTx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[i].channelTx); states[i].channelTx = E_NO_DEVICE; } if (states[i].channelRx >= 0) { MXC_DMA_RevA_ReleaseChannel(states[i].channelRx); states[i].channelRx = E_NO_DEVICE; } } break; } } } } int MXC_SPI_RevA_SetDefaultTXData(mxc_spi_reva_regs_t *spi, unsigned int defaultTXData) { int spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); MXC_ASSERT(spi_num >= 0); states[spi_num].defaultTXData = defaultTXData; return E_NO_ERROR; } void MXC_SPI_RevA_AbortAsync(mxc_spi_reva_regs_t *spi) { MXC_SPI_AbortTransmission((mxc_spi_regs_t *)spi); } void MXC_SPI_RevA_AsyncHandler(mxc_spi_reva_regs_t *spi) { int spi_num; unsigned rx_avail; uint32_t flags; // Clear the interrupt flags spi->inten = 0; flags = spi->intfl; spi->intfl = flags; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); // Figure out if this SPI has an active request if ((states[spi_num].req != NULL) && (flags)) { if ((spi->ctrl0 & MXC_F_SPI_REVA_CTRL0_MST_MODE) >> MXC_F_SPI_REVA_CTRL0_MST_MODE_POS) { do { spi->inten = MXC_SPI_RevA_MasterTransHandler(spi, states[spi_num].req); rx_avail = MXC_SPI_RevA_GetRXFIFOAvailable(spi); } while (rx_avail > MXC_SPI_RevA_GetRXThreshold(spi)); } else { do { spi->inten = MXC_SPI_RevA_SlaveTransHandler(states[spi_num].req); rx_avail = MXC_SPI_RevA_GetRXFIFOAvailable(spi); } while (rx_avail > MXC_SPI_RevA_GetRXThreshold(spi)); } } } //call in DMA IRQHANDLER with rxData for transmissions with bits > 8 void MXC_SPI_RevA_SwapByte(uint8_t *arr, size_t length) { MXC_ASSERT(arr != NULL); for (size_t i = 0; i < (length * 2); i += 2) { uint8_t tmp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = tmp; } }