text: /*
   * Copyright (c) 2016, Freescale Semiconductor, Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted provided that the following conditions are met:
   *
   * o Redistributions of source code must retain the above copyright notice, this list
   *   of conditions and the following disclaimer.
   *
   * o Redistributions in binary form must reproduce the above copyright notice, this
   *   list of conditions and the following disclaimer in the documentation and/or
   *   other materials provided with the distribution.
   *
   * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
   *   contributors may be used to endorse or promote products derived from this
   *   software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include "fsl_spi.h"
  #include "fsl_flexcomm.h"
  
  /*******************************************************************************
   * Definitons
   ******************************************************************************/
  /* Note:  FIFOCFG[SIZE] has always value 1 = 8 items depth */
  #define SPI_FIFO_DEPTH(base) ((((base)->FIFOCFG & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3)
  
  /* Convert transfer count to transfer bytes. dataWidth is a
   * range <0,15>. Range <8,15> represents 2B transfer */
  #define SPI_COUNT_TO_BYTES(dataWidth, count) ((count) << ((dataWidth) >> 3U))
  #define SPI_BYTES_TO_COUNT(dataWidth, bytes) ((bytes) >> ((dataWidth) >> 3U))
  
  /*******************************************************************************
   * Variables
   ******************************************************************************/
  /*! @brief internal SPI config array */
  static spi_config_t g_configs[FSL_FEATURE_SOC_SPI_COUNT] = {(spi_data_width_t)0};
  
  /*! @brief IRQ name array */
  static const IRQn_Type s_spiIRQ[] = SPI_IRQS;
  
  /*******************************************************************************
   * Code
   ******************************************************************************/
  
  void *SPI_GetConfig(SPI_Type *base)
  {
      int32_t instance;
      instance = FLEXCOMM_GetInstance(base);
      if (instance < 0)
      {
          return NULL;
      }
      return &g_configs[instance];
  }
  
  void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
  {
      assert(NULL != config);
  
      config->enableLoopback = false;
      config->enableMaster = true;
      config->polarity = kSPI_ClockPolarityActiveHigh;
      config->phase = kSPI_ClockPhaseFirstEdge;
      config->direction = kSPI_MsbFirst;
      config->baudRate_Bps = 500000U;
      config->dataWidth = kSPI_Data8Bits;
      config->sselNum = kSPI_Ssel0;
      config->txWatermark = kSPI_TxFifo0;
      config->rxWatermark = kSPI_RxFifo1;
  }
  
  status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz)
  {
      int32_t result = 0, instance = 0;
      uint32_t tmp;
  
      /* assert params */
      assert(!((NULL == base) || (NULL == config) || (0 == srcClock_Hz)));
      if ((NULL == base) || (NULL == config) || (0 == srcClock_Hz))
      {
          return kStatus_InvalidArgument;
      }
  
      /* initialize flexcomm to SPI mode */
      result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
      assert(kStatus_Success == result);
      if (kStatus_Success != result)
      {
          return result;
      }
  
      /* set divider */
      result = SPI_MasterSetBaud(base, config->baudRate_Bps, srcClock_Hz);
      if (kStatus_Success != result)
      {
          return result;
      }
      /* get instance number */
      instance = FLEXCOMM_GetInstance(base);
      assert(instance >= 0);
  
      /* store configuration */
      g_configs[instance].dataWidth = config->dataWidth;
      g_configs[instance].sselNum = config->sselNum;
      /* enable FIFOs */
      base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
      base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
      /* trigger level - empty txFIFO, one item in rxFIFO */
      tmp = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
      tmp |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
      /* enable generating interrupts for FIFOTRIG levels */
      tmp |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
      /* set FIFOTRIG */
      base->FIFOTRIG = tmp;
      /* configure SPI mode */
      tmp = base->CFG;
      tmp &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK | SPI_CFG_LOOP_MASK);
      /* phase */
      tmp |= SPI_CFG_CPHA(config->phase);
      /* polarity */
      tmp |= SPI_CFG_CPOL(config->polarity);
      /* direction */
      tmp |= SPI_CFG_LSBF(config->direction);
      /* master mode */
      tmp |= SPI_CFG_MASTER(1);
      /* loopback */
      tmp |= SPI_CFG_LOOP(config->enableLoopback);
      base->CFG = tmp;
      SPI_Enable(base, config->enableMaster);
      return kStatus_Success;
  }
  
  void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config)
  {
      assert(NULL != config);
  
      config->enableSlave = true;
      config->polarity = kSPI_ClockPolarityActiveHigh;
      config->phase = kSPI_ClockPhaseFirstEdge;
      config->direction = kSPI_MsbFirst;
      config->dataWidth = kSPI_Data8Bits;
      config->txWatermark = kSPI_TxFifo0;
      config->rxWatermark = kSPI_RxFifo1;
  }
  
  status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config)
  {
      int32_t result = 0, instance;
      uint32_t tmp;
  
      /* assert params */
      assert(!((NULL == base) || (NULL == config)));
      if ((NULL == base) || (NULL == config))
      {
          return kStatus_InvalidArgument;
      }
      /* configure flexcomm to SPI, enable clock gate */
      result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
      assert(kStatus_Success == result);
      if (kStatus_Success != result)
      {
          return result;
      }
  
      instance = FLEXCOMM_GetInstance(base);
  
      /* store configuration */
      g_configs[instance].dataWidth = config->dataWidth;
      /* empty and enable FIFOs */
      base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
      base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
      /* trigger level - empty txFIFO, one item in rxFIFO */
      tmp = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
      tmp |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
      /* enable generating interrupts for FIFOTRIG levels */
      tmp |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
      /* set FIFOTRIG */
      base->FIFOTRIG = tmp;
      /* configure SPI mode */
      tmp = base->CFG;
      tmp &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK);
      /* phase */
      tmp |= SPI_CFG_CPHA(config->phase);
      /* polarity */
      tmp |= SPI_CFG_CPOL(config->polarity);
      /* direction */
      tmp |= SPI_CFG_LSBF(config->direction);
      base->CFG = tmp;
      SPI_Enable(base, config->enableSlave);
      return kStatus_Success;
  }
  
  void SPI_Deinit(SPI_Type *base)
  {
      /* Assert arguments */
      assert(NULL != base);
      /* Disable interrupts, disable dma requests, disable peripheral */
      base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXERR_MASK | SPI_FIFOINTENCLR_RXERR_MASK | SPI_FIFOINTENCLR_TXLVL_MASK |
                           SPI_FIFOINTENCLR_RXLVL_MASK;
      base->FIFOCFG &= ~(SPI_FIFOCFG_DMATX_MASK | SPI_FIFOCFG_DMARX_MASK);
      base->CFG &= ~(SPI_CFG_ENABLE_MASK);
  }
  
  void SPI_EnableTxDMA(SPI_Type *base, bool enable)
  {
      if (enable)
      {
          base->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
      }
      else
      {
          base->FIFOCFG &= ~SPI_FIFOCFG_DMATX_MASK;
      }
  }
  
  void SPI_EnableRxDMA(SPI_Type *base, bool enable)
  {
      if (enable)
      {
          base->FIFOCFG |= SPI_FIFOCFG_DMARX_MASK;
      }
      else
      {
          base->FIFOCFG &= ~SPI_FIFOCFG_DMARX_MASK;
      }
  }
  
  status_t SPI_MasterSetBaud(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
  {
      uint32_t tmp;
  
      /* assert params */
      assert(!((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz)));
      if ((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz))
      {
          return kStatus_InvalidArgument;
      }
  
      /* calculate baudrate */
      tmp = (srcClock_Hz / baudrate_Bps) - 1;
      if (tmp > 0xFFFF)
      {
          return kStatus_SPI_BaudrateNotSupport;
      }
      base->DIV &= ~SPI_DIV_DIVVAL_MASK;
      base->DIV |= SPI_DIV_DIVVAL(tmp);
      return kStatus_Success;
  }
  
  void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags)
  {
      uint32_t control = 0;
      int32_t instance;
  
      /* check params */
      assert(NULL != base);
      /* get and check instance */
      instance = FLEXCOMM_GetInstance(base);
      assert(!(instance < 0));
      if (instance < 0)
      {
          return;
      }
  
      /* set data width */
      control |= SPI_FIFOWR_LEN(g_configs[instance].dataWidth);
      /* set sssel */
      control |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL(g_configs[instance].sselNum)));
      /* mask configFlags */
      control |= (configFlags & SPI_FIFOWR_FLAGS_MASK);
      /* control should not affect lower 16 bits */
      assert(!(control & 0xFFFF));
      base->FIFOWR = data | control;
  }
  
  status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
                                          spi_master_handle_t *handle,
                                          spi_master_callback_t callback,
                                          void *userData)
  {
      int32_t instance = 0;
  
      /* check 'base' */
      assert(!(NULL == base));
      if (NULL == base)
      {
          return kStatus_InvalidArgument;
      }
      /* check 'handle' */
      assert(!(NULL == handle));
      if (NULL == handle)
      {
          return kStatus_InvalidArgument;
      }
      /* get flexcomm instance by 'base' param */
      instance = FLEXCOMM_GetInstance(base);
      assert(!(instance < 0));
      if (instance < 0)
      {
          return kStatus_InvalidArgument;
      }
  
      memset(handle, 0, sizeof(*handle));
      /* Initialize the handle */
      if (base->CFG & SPI_CFG_MASTER_MASK)
      {
          FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)SPI_MasterTransferHandleIRQ, handle);
      }
      else
      {
          FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)SPI_SlaveTransferHandleIRQ, handle);
      }
  
      handle->dataWidth = g_configs[instance].dataWidth;
      /* in slave mode, the sselNum is not important */
      handle->sselNum = g_configs[instance].sselNum;
      handle->txWatermark = (spi_txfifo_watermark_t)SPI_FIFOTRIG_TXLVL_GET(base);
      handle->rxWatermark = (spi_rxfifo_watermark_t)SPI_FIFOTRIG_RXLVL_GET(base);
      handle->callback = callback;
      handle->userData = userData;
  
      /* Enable SPI NVIC */
      EnableIRQ(s_spiIRQ[instance]);
  
      return kStatus_Success;
  }
  
  status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer)
  {
      int32_t instance;
      uint32_t tx_ctrl = 0, last_ctrl = 0;
      uint32_t tmp32, rxRemainingBytes, txRemainingBytes, dataWidth;
      uint32_t toReceiveCount = 0;
      uint8_t *txData, *rxData;
      uint32_t fifoDepth;
  
      /* check params */
      assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
      if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
      {
          return kStatus_InvalidArgument;
      }
  
      fifoDepth = SPI_FIFO_DEPTH(base);
      txData = xfer->txData;
      rxData = xfer->rxData;
      txRemainingBytes = txData ? xfer->dataSize : 0;
      rxRemainingBytes = rxData ? xfer->dataSize : 0;
  
      instance = FLEXCOMM_GetInstance(base);
      assert(instance >= 0);
      dataWidth = g_configs[instance].dataWidth;
  
      /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
      assert(!((dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1)));
      if ((dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1))
      {
          return kStatus_InvalidArgument;
      }
  
      /* clear tx/rx errors and empty FIFOs */
      base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
      base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
      /* select slave to talk with */
      tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL(g_configs[instance].sselNum)));
      /* set width of data - range asserted at entry */
      tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
      /* end of transfer */
      last_ctrl |= (xfer->configFlags & (uint32_t)kSPI_FrameAssert) ? (uint32_t)kSPI_FrameAssert : 0;
      /* delay end of transfer */
      last_ctrl |= (xfer->configFlags & (uint32_t)kSPI_FrameDelay) ? (uint32_t)kSPI_FrameDelay : 0;
      /* last index of loop */
      while (txRemainingBytes || rxRemainingBytes || toReceiveCount)
      {
          /* if rxFIFO is not empty */
          if (base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK)
          {
              tmp32 = base->FIFORD;
              /* rxBuffer is not empty */
              if (rxRemainingBytes)
              {
                  *(rxData++) = tmp32;
                  rxRemainingBytes--;
                  /* read 16 bits at once */
                  if (dataWidth > 8)
                  {
                      *(rxData++) = tmp32 >> 8;
                      rxRemainingBytes--;
                  }
              }
              /* decrease number of data expected to receive */
              toReceiveCount -= 1;
          }
          /* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
          if ((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) && (toReceiveCount < fifoDepth) &&
              ((txRemainingBytes) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1))))
          {
              /* txBuffer is not empty */
              if (txRemainingBytes)
              {
                  tmp32 = *(txData++);
                  txRemainingBytes--;
                  /* write 16 bit at once */
                  if (dataWidth > 8)
                  {
                      tmp32 |= ((uint32_t)(*(txData++))) << 8U;
                      txRemainingBytes--;
                  }
                  if (!txRemainingBytes)
                  {
                      tx_ctrl |= last_ctrl;
                  }
              }
              else
              {
                  tmp32 = SPI_DUMMYDATA;
                  /* last transfer */
                  if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1))
                  {
                      tx_ctrl |= last_ctrl;
                  }
              }
              /* send data */
              tmp32 = tx_ctrl | tmp32;
              base->FIFOWR = tmp32;
              toReceiveCount += 1;
          }
      }
      /* wait if TX FIFO of previous transfer is not empty */
      while (!(base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
      {
      }
      return kStatus_Success;
  }
  
  status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
  {
      /* check params */
      assert(
          !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
      if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
      {
          return kStatus_InvalidArgument;
      }
  
      /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
      assert(!((handle->dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1)));
      if ((handle->dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1))
      {
          return kStatus_InvalidArgument;
      }
  
      /* Check if SPI is busy */
      if (handle->state == kStatus_SPI_Busy)
      {
          return kStatus_SPI_Busy;
      }
  
      /* Set the handle information */
      handle->txData = xfer->txData;
      handle->rxData = xfer->rxData;
      /* set count */
      handle->txRemainingBytes = xfer->txData ? xfer->dataSize : 0;
      handle->rxRemainingBytes = xfer->rxData ? xfer->dataSize : 0;
      handle->totalByteCount = xfer->dataSize;
      /* other options */
      handle->toReceiveCount = 0;
      handle->configFlags = xfer->configFlags;
      /* Set the SPI state to busy */
      handle->state = kStatus_SPI_Busy;
      /* clear FIFOs when transfer starts */
      base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
      base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
      /* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
      base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
      return kStatus_Success;
  }
  
  status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
  {
      assert(NULL != handle);
  
      if (!count)
      {
          return kStatus_InvalidArgument;
      }
  
      /* Catch when there is not an active transfer. */
      if (handle->state != kStatus_SPI_Busy)
      {
          *count = 0;
          return kStatus_NoTransferInProgress;
      }
  
      *count = handle->totalByteCount - handle->rxRemainingBytes;
      return kStatus_Success;
  }
  
  void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
  {
      assert(NULL != handle);
  
      /* Disable interrupt requests*/
      base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
      /* Empty FIFOs */
      base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
  
      handle->state = kStatus_SPI_Idle;
      handle->txRemainingBytes = 0;
      handle->rxRemainingBytes = 0;
  }
  
  static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
  {
      uint32_t tx_ctrl = 0, last_ctrl = 0, tmp32;
      bool loopContinue;
      uint32_t fifoDepth;
  
      /* check params */
      assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
  
      fifoDepth = SPI_FIFO_DEPTH(base);
      /* select slave to talk with */
      tx_ctrl |= (SPI_DEASSERT_ALL & SPI_ASSERTNUM_SSEL(handle->sselNum));
      /* set width of data */
      tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
      /* end of transfer */
      last_ctrl |= (handle->configFlags & (uint32_t)kSPI_FrameAssert) ? (uint32_t)kSPI_FrameAssert : 0;
      /* delay end of transfer */
      last_ctrl |= (handle->configFlags & (uint32_t)kSPI_FrameDelay) ? (uint32_t)kSPI_FrameDelay : 0;
      do
      {
          loopContinue = false;
  
          /* rxFIFO is not empty */
          if (base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK)
          {
              tmp32 = base->FIFORD;
              /* rxBuffer is not empty */
              if (handle->rxRemainingBytes)
              {
                  /* low byte must go first */
                  *(handle->rxData++) = tmp32;
                  handle->rxRemainingBytes--;
                  /* read 16 bits at once */
                  if (handle->dataWidth > kSPI_Data8Bits)
                  {
                      *(handle->rxData++) = tmp32 >> 8;
                      handle->rxRemainingBytes--;
                  }
              }
              /* decrease number of data expected to receive */
              handle->toReceiveCount -= 1;
              loopContinue = true;
          }
  
          /* - txFIFO is not full
           * - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
           * - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
           */
          if ((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) && (handle->toReceiveCount < fifoDepth) &&
              ((handle->txRemainingBytes) ||
               (handle->rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, handle->toReceiveCount + 1))))
          {
              /* txBuffer is not empty */
              if (handle->txRemainingBytes)
              {
                  /* low byte must go first */
                  tmp32 = *(handle->txData++);
                  handle->txRemainingBytes--;
                  /* write 16 bit at once */
                  if (handle->dataWidth > kSPI_Data8Bits)
                  {
                      tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
                      handle->txRemainingBytes--;
                  }
                  /* last transfer */
                  if (!handle->txRemainingBytes)
                  {
                      tx_ctrl |= last_ctrl;
                  }
              }
              else
              {
                  tmp32 = SPI_DUMMYDATA;
                  /* last transfer */
                  if (handle->rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, handle->toReceiveCount + 1))
                  {
                      tx_ctrl |= last_ctrl;
                  }
              }
              /* send data */
              tmp32 = tx_ctrl | tmp32;
              base->FIFOWR = tmp32;
              /* increase number of expected data to receive */
              handle->toReceiveCount += 1;
              loopContinue = true;
          }
      } while (loopContinue);
  }
  
  void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
  {
      assert((NULL != base) && (NULL != handle));
  
      /* IRQ behaviour:
       * - first interrupt is triggered by empty txFIFO. The transfer function
       *   then tries empty rxFIFO and fill txFIFO interleaved that results to
       *   strategy to process as many items as possible.
       * - the next IRQs can be:
       *      rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
       *      txIRQ from empty txFIFO which requires to refill txFIFO.
       * - last interrupt is triggered by empty txFIFO. The last state is
       *   known by empty rxBuffer and txBuffer. If there is nothing to receive
       *   or send - both operations have been finished and interrupts can be
       *   disabled.
       */
  
      /* Data to send or read or expected to receive */
      if ((handle->txRemainingBytes) || (handle->rxRemainingBytes) || (handle->toReceiveCount))
      {
          /* Transmit or receive data */
          SPI_TransferHandleIRQInternal(base, handle);
          /* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
           * enable txIRQ to confirm when txFIFO becomes empty */
          if ((!handle->txRemainingBytes) && (!handle->rxRemainingBytes) && (!handle->toReceiveCount))
          {
              base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
              base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
          }
          else
          {
              uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
              /* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
               * disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
              if ((!handle->txRemainingBytes) && (rxRemainingCount <= handle->toReceiveCount))
              {
                  base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
              }
              /* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
               * Cannot clear rxFIFO, txFIFO might be still active */
              if (rxRemainingCount == 0)
              {
                  if ((handle->txRemainingBytes == 0) && (handle->toReceiveCount != 0) &&
                      (handle->toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1))
                  {
                      base->FIFOTRIG =
                          (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(handle->toReceiveCount - 1);
                  }
              }
              /* Expected to receive less data than rxLevel value, we have to update rxLevel */
              else
              {
                  if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1))
                  {
                      base->FIFOTRIG =
                          (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1);
                  }
              }
          }
      }
      else
      {
          /* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
          base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
          base->FIFOTRIG = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
                           SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
          /* set idle state and call user callback */
          handle->state = kStatus_SPI_Idle;
          if (handle->callback)
          {
              (handle->callback)(base, handle, handle->state, handle->userData);
          }
      }
  }
  