/**
*   @file    Lpspi_Ip.c
*   
*
*   @brief   LPSPI low-level driver implementations.
*   @details LPSPI low-level driver implementations.
*
*   @addtogroup LPSPI_DRIVER Lpspi Driver
*   @{
*/
/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : LPSPI
*   Dependencies         : 
*
*   Autosar Version      : 4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 0.9.0
*   Build Version        : S32K3_RTD_0_9_0__ASR_REL_4_4_REV_0000_20210326
*
*   (c) Copyright 2020 - 2021 NXP Semiconductors
*   All Rights Reserved.
*
*   NXP Confidential. This software is owned or controlled by NXP and may only be
*   used strictly in accordance with the applicable license terms. By expressly
*   accepting such terms or by downloading, installing, activating and/or otherwise
*   using the software, you are agreeing that you have read, and that you agree to
*   comply with and are bound by, such license terms. If you do not agree to be
*   bound by the applicable license terms, then you may not retain, install,
*   activate or otherwise use the software.
==================================================================================================*/

#ifdef __cplusplus
extern "C"
{
#endif

/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "Mcal.h"
#include "Lpspi_Ip.h"
#include "Lpspi_Ip_Cfg.h"
#include "OsIf.h"
#if (LPSPI_IP_DMA_USED == STD_ON)
    #include "Dma_Ip.h"
#endif
#if (STD_ON == LPSPI_IP_ENABLE_USER_MODE_SUPPORT)
   #define USER_MODE_REG_PROT_ENABLED   (LPSPI_IP_ENABLE_USER_MODE_SUPPORT)
   #include "RegLockMacros.h"
#endif
#include "SchM_Spi.h"
#if (STD_ON == LPSPI_IP_DEV_ERROR_DETECT)
    #include "Devassert.h"
#endif

/*==================================================================================================
*                                       SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define LPSPI_IP_VENDOR_ID_C                      43
#define LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C       4
#define LPSPI_IP_AR_RELEASE_MINOR_VERSION_C       4
#define LPSPI_IP_AR_RELEASE_REVISION_VERSION_C    0
#define LPSPI_IP_SW_MAJOR_VERSION_C               0
#define LPSPI_IP_SW_MINOR_VERSION_C               9
#define LPSPI_IP_SW_PATCH_VERSION_C               0
/*==================================================================================================
*                                     FILE VERSION CHECKS
==================================================================================================*/
#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
    /* Check if current file and Mcal header file are of the same Autosar version */
    #if ((LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C != MCAL_AR_RELEASE_MAJOR_VERSION) || \
         (LPSPI_IP_AR_RELEASE_MINOR_VERSION_C != MCAL_AR_RELEASE_MINOR_VERSION))
    #error "AutoSar Version Numbers of Lpspi_Ip.c and Mcal.h are different"
    #endif

    #if (LPSPI_IP_DMA_USED == STD_ON)
        /* Check if current file and Dma_Ip header file are of the same Autosar version */
        #if ((DMA_IP_AR_RELEASE_MAJOR_VERSION != LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C) || \
             (DMA_IP_AR_RELEASE_MINOR_VERSION != LPSPI_IP_AR_RELEASE_MINOR_VERSION_C))
        #error "AutoSar Version Numbers of Lpspi_Ip.c and Dma_Ip.h are different"
        #endif
    #endif
    
    #if (STD_ON == LPSPI_IP_ENABLE_USER_MODE_SUPPORT)
        #if ((LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C != REGLOCKMACROS_AR_RELEASE_MAJOR_VERSION) || \
             (LPSPI_IP_AR_RELEASE_MINOR_VERSION_C != REGLOCKMACROS_AR_RELEASE_MINOR_VERSION))
        #error "AutoSar Version Numbers of Lpspi_Ip.c and RegLockMacros.h are different"
        #endif
    #endif
    
    /* Check if the current file and SchM_Spi.h header file are of the same version */
    #if ((LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C != SCHM_SPI_AR_RELEASE_MAJOR_VERSION) || \
         (LPSPI_IP_AR_RELEASE_MINOR_VERSION_C != SCHM_SPI_AR_RELEASE_MINOR_VERSION) \
        )
        #error "AutoSar Version Numbers of Lpspi_Ip.c and SchM_Spi.h are different"
    #endif
#endif

/* Check if Lpspi_Ip.h and Lpspi_Ip.c are of the same vendor */
#if (LPSPI_IP_VENDOR_ID != LPSPI_IP_VENDOR_ID_C)
    #error "Lpspi_Ip.h and Lpspi_Ip.c have different vendor ids"
#endif
/* Check if Lpspi_Ip.h file and Lpspi_Ip.c file are of the same Autosar version */
#if ((LPSPI_IP_AR_RELEASE_MAJOR_VERSION != LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C) || \
     (LPSPI_IP_AR_RELEASE_MINOR_VERSION != LPSPI_IP_AR_RELEASE_MINOR_VERSION_C) || \
     (LPSPI_IP_AR_RELEASE_REVISION_VERSION != LPSPI_IP_AR_RELEASE_REVISION_VERSION_C))
#error "AutoSar Version Numbers of Lpspi_Ip.h and Lpspi_Ip.c are different"
#endif
#if ((LPSPI_IP_SW_MAJOR_VERSION != LPSPI_IP_SW_MAJOR_VERSION_C) || \
     (LPSPI_IP_SW_MINOR_VERSION != LPSPI_IP_SW_MINOR_VERSION_C) || \
     (LPSPI_IP_SW_PATCH_VERSION != LPSPI_IP_SW_PATCH_VERSION_C))
#error "Software Version Numbers of Lpspi_Ip.h and Lpspi_Ip.c are different"
#endif

/* Check if Lpspi_Ip_Cfg.h and Lpspi_Ip.c are of the same vendor */
#if (LPSPI_IP_VENDOR_ID_CFG != LPSPI_IP_VENDOR_ID_C)
    #error "Lpspi_Ip_Cfg.h and Lpspi_Ip.c have different vendor ids"
#endif
/* Check if Lpspi_Ip_Cfg.h file and Lpspi_Ip.c file are of the same Autosar version */
#if ((LPSPI_IP_AR_RELEASE_MAJOR_VERSION_CFG != LPSPI_IP_AR_RELEASE_MAJOR_VERSION_C) || \
     (LPSPI_IP_AR_RELEASE_MINOR_VERSION_CFG != LPSPI_IP_AR_RELEASE_MINOR_VERSION_C) || \
     (LPSPI_IP_AR_RELEASE_REVISION_VERSION_CFG != LPSPI_IP_AR_RELEASE_REVISION_VERSION_C))
#error "AutoSar Version Numbers of Lpspi_Ip_Cfg.h and Lpspi_Ip.c are different"
#endif
#if ((LPSPI_IP_SW_MAJOR_VERSION_CFG != LPSPI_IP_SW_MAJOR_VERSION_C) || \
     (LPSPI_IP_SW_MINOR_VERSION_CFG != LPSPI_IP_SW_MINOR_VERSION_C) || \
     (LPSPI_IP_SW_PATCH_VERSION_CFG != LPSPI_IP_SW_PATCH_VERSION_C))
#error "Software Version Numbers of Lpspi_Ip_Cfg.h and Lpspi_Ip.c are different"
#endif
/*==================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/
/*==================================================================================================
*                                       LOCAL MACROS
==================================================================================================*/
#if (LPSPI_IP_DMA_USED == STD_ON)
    /* the maximum of Major loop when Minor loop Channel Linking Disabled */
    #define LPSPI_IP_DMA_MAX_ITER_CNT ((uint32)0x7FFFu)
#endif
/*==================================================================================================
*                                       LOCAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
*                                       LOCAL VARIABLES
==================================================================================================*/
/*==================================================================================================
*                                      GLOBAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
                                    GLOBAL VARIABLES
==================================================================================================*/
#if (LPSPI_IP_DMA_USED == STD_ON)
    #define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED_NO_CACHEABLE
#else
    #define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Spi_MemMap.h"

Lpspi_Ip_StateStructureType Lpspi_Ip_StateStructure[LPSPI_IP_NUMBER_OF_INSTANCES];

#if (LPSPI_IP_DMA_USED == STD_ON)
    #define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED_NO_CACHEABLE
#else
    #define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Spi_MemMap.h"

#if (LPSPI_IP_DMA_USED == STD_ON)
    #define SPI_START_SEC_VAR_NO_INIT_32_NO_CACHEABLE
    #include "Spi_MemMap.h"
uint32 Spi_u32DiscardData;
    #define SPI_STOP_SEC_VAR_NO_INIT_32_NO_CACHEABLE
    #include "Spi_MemMap.h"
#endif

#define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

Lpspi_Ip_StateStructureType* Lpspi_Ip_StateStructureArray[LPSPI_INSTANCE_COUNT];

#define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

#define SPI_START_SEC_CONST_UNSPECIFIED
#include "Spi_MemMap.h"

static LPSPI_Type* const Lpspi_Ip_Bases[LPSPI_INSTANCE_COUNT] = LPSPI_BASE_PTRS;

#define SPI_STOP_SEC_CONST_UNSPECIFIED
#include "Spi_MemMap.h"
/*==================================================================================================
*                                  LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define SPI_START_SEC_CODE
#include "Spi_MemMap.h"

static void Lpspi_Ip_ReadData(uint8 u8Instance, uint8 numberOfReads);
static void Lpspi_Ip_PushData(uint8 u8Instance, uint8 numberOfWrites);
static Lpspi_Ip_StatusType Lpspi_Ip_PushDataProcess(uint8 u8Instance);
static void Lpspi_Ip_TransferProcess(uint8 u8Instance);
static void Lpspi_TransmitTxInit(uint8 u8Instance,
                                      uint8* pu8TxBuffer,
                                      uint16 numberOfFrames
                                     );
static void Lpspi_TransmitRxInit(uint8 u8Instance,
                                      uint8* pu8RxBuffer,
                                      uint16 numberOfFrames
                                     );
#if (LPSPI_IP_DMA_USED == STD_ON)
static void Lpspi_Ip_TxDmaConfig(uint8 u8Instance);
static void Lpspi_Ip_RxDmaConfig(uint8 u8Instance);
static void Lpspi_Ip_TxDmaContinueTransfer(uint8 u8Instance);
static void Lpspi_Ip_RxDmaContinueTransfer(uint8 u8Instance);
#if (LPSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
static void Lpspi_Ip_DmaFastConfig(uint8 u8Instance, const Lpspi_Ip_FastTransferType *pFastTransferCfg, uint8 u8NumberOfTransfer);
static void Lpspi_Ip_RxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint8 u8DisHwReq);
static void Lpspi_Ip_RxDmaTcdSGInit(uint8 u8Instance);
static void Lpspi_Ip_TxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint8 u8DisHwReq);
static void Lpspi_Ip_TxDmaTcdSGInit(uint8 u8Instance);
static void Lpspi_Ip_CmdTxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint32 u32CmdAdd, uint8 u8DisHwReq);
#endif
#endif
#if (STD_ON == LPSPI_IP_ENABLE_USER_MODE_SUPPORT)
static void Lpspi_Ip_SetUserAccess(uint8 u8Instance);
static void Lpspi_Ip_SetUserAccessAllowed(uint8 u8Instance);
#endif /* LPSPI_IP_ENABLE_USER_MODE_SUPPORT */
/*==================================================================================================
*                                      LOCAL FUNCTIONS
==================================================================================================*/
/**
* @brief   This function will read data from RX FIFO.
* @details This function will read data from RX FIFO.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @param[in]     numberOfReads      Number of data can be read from RX FIFO.
* @return void
*/
static void Lpspi_Ip_ReadData(uint8 u8Instance, uint8 numberOfReads)
{
    const LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 data;
    uint8 i;

    for (i=0; i < numberOfReads; i++)
    {
        data = base->RDR;
        if(NULL_PTR != state->pu8RxBuffer)
        {
            if (state->u8FrameSize < 9u)
            {
                *((uint8*)(state->pu8RxBuffer) + state->rxIndex) = (uint8)data;
            }
            else if (state->u8FrameSize < 17u)
            {
                *((uint16*)(state->pu8RxBuffer) + state->rxIndex) = (uint16)data;
            }
            else
            {
                *((uint32*)(state->pu8RxBuffer) + state->rxIndex) = data;
            }
        }
        state->rxIndex++;
    }
}

/**
* @brief   This function will push data into TX FIFO.
* @details This function will push data into TX FIFO.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @param[in]     numberOfWrites      Number of data can be pushed to TX FIFO.
* @return void
*/
static void Lpspi_Ip_PushData(uint8 u8Instance, uint8 numberOfWrites)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 data;
    uint8 i;

    for (i=0; i < numberOfWrites; i++)
    {
        if(NULL_PTR != state->pu8TxBuffer)
        {
            if (state->u8FrameSize < 9u)
            {
                data = *((uint8*)(state->pu8TxBuffer) + state->txIndex);
            }
            else if (state->u8FrameSize < 17u)
            {
                data = *((uint16*)(state->pu8TxBuffer) + state->txIndex);
            }
            else
            {
                data = *((uint32*)(state->pu8TxBuffer) + state->txIndex);
            }
        }
        else
        {
            data = state->u32DefaultData;
        }
        base->TDR = data;
        state->txIndex++;
    }
}

/**
* @brief   This function will process push data into TX FIFO.
* @details This function will process push data into TX FIFO.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return LPSPI_IP_STATUS_SUCCESS   Data is wrote to TX FIFO.
*         LPSPI_IP_STATUS_FAIL      Data is not wrote to TX FIFO.
*/
static Lpspi_Ip_StatusType Lpspi_Ip_PushDataProcess(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    const Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint8 numberOfWrites, numberOfReads;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_FAIL;

    /* Push data until HW fifo is full or transfer is done. */
    /* After driver code read all frames in RX FIFO, if there are still some frames in TX FIFO, at the time before driver code check number of frames available in TX FIFO to prepare 
    to fill TX FIFO. At that time, another interrupt occurred and preemptive current interrupt, and the time to process that interrupt is longer than the time to transfer all frames 
    in TX FIFO. So TX FIFO will be empty and some frames received in RX FIFO, then the program is returned from that interrupt and fill TX FIFO until full and exist SPI interrupt function. 
    And if there is a interrupt occurred with higher priority of SPI interrupt and the time to process that interrupt is longer than the time to transfer all frames in TX FIFO. 
    So, RX FIFO can be overflow due to SPI interrupt function is not serviced to read RX FIFO.
    To avoid this, limitation total of frames in TX FIFO and RX FIFO is lower than FIFO's size(considered that maybe there is an frame on going). */
    numberOfWrites = (uint8)(((base->FSR) & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT);
    numberOfReads = (uint8)(((base->FSR) & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT);
    if ((numberOfWrites + numberOfReads) < LPSPI_IP_FIFO_SIZE)
    {
        /* maybe there is one frame ongoing and not pushed to RX FIFO, so total of frames should be -1u */
        numberOfWrites =  LPSPI_IP_FIFO_SIZE - (numberOfWrites + numberOfReads) - 1u;
    }
    else
    {
        numberOfWrites = 0u;
    }
        
    if(numberOfWrites != 0u)
    {
        /* Limits to remaining frames. */
        if (numberOfWrites > (state->expectedFifoWrites - state->txIndex))
        {
            numberOfWrites = (uint8)(state->expectedFifoWrites - state->txIndex);
        }

        if(state->expectedFifoWrites == state->txIndex)
        {
            /* disable TX interrupt */
            base->IER &= ~LPSPI_IER_TDIE_MASK;
            if(((boolean)FALSE == state->bKeepCs) &&
                (0u != (base->TCR & LPSPI_TCR_CONT_MASK))
                )
            {
                /* Write last command to TX FIFO to clear CS */
                base->TCR &= ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK);
                status = LPSPI_IP_STATUS_SUCCESS;
            }
        }
        else
        {
            status = LPSPI_IP_STATUS_SUCCESS;
        }
        
        /* Push data into TX FIFO */
        Lpspi_Ip_PushData(u8Instance, numberOfWrites);
    }

    return status;
}

/**
* @brief   This function is called by Lpspi_Ip_IrqHandler or Lpspi_Ip_ManageBuffers. It will process transfer in interrupt mode or polling mode.
* @details This function will fill data into TX FIFO and read data in RX FIFO fill to Rx Buffers.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return void
*/
static void Lpspi_Ip_TransferProcess(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 srStatusRegister;
    uint8 numberOfReads;
    boolean bErrorFlag = (boolean)FALSE;

    if (LPSPI_IP_BUSY == state->status)
    {
        /* Read status and clear all flags. */
        srStatusRegister = base->SR;
        base->SR &= (uint32)0xFFFFFFFFu;
        
        if ((srStatusRegister & (LPSPI_SR_REF_MASK | LPSPI_SR_TEF_MASK)) != 0u)
        {
            /* mark error flag */
            bErrorFlag = (boolean)TRUE;
        }
        else
        {
            /* Read all data available in receive HW fifo. */
            numberOfReads = (uint8)(((base->FSR) & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT);

            /* Prevent hardware faults by limiting RXCOUNT to maximum value. */
            if (numberOfReads > LPSPI_IP_FIFO_SIZE)
            {
                numberOfReads = (uint8)LPSPI_IP_FIFO_SIZE;
            }
            
            if(numberOfReads != 0u)
            {
                /* Limits to remaining frames. */
                if (numberOfReads > (state->expectedFifoReads - state->rxIndex))
                {
                    numberOfReads = (uint8)(state->expectedFifoReads - state->rxIndex);
                }
                /* Read data from RX FIFO */
                Lpspi_Ip_ReadData(u8Instance, numberOfReads);
            }
            /* Process to push data into TX FIFO */
            (void)Lpspi_Ip_PushDataProcess(u8Instance);
        }
        
        /* End of transfer */
        if((state->rxIndex == state->expectedFifoReads) || ((boolean)TRUE == bErrorFlag))
        {
            if(((boolean)FALSE == state->bKeepCs) || ((boolean)TRUE == bErrorFlag))
            {
                SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_12();
                /* Disable module to stop transfer */
                base->CR &= ~LPSPI_CR_MEN_MASK;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_12();
            }
            /* Disable interrupts */
            base->IER = 0U;
            
            if((boolean)TRUE == bErrorFlag)
            {
                state->status = LPSPI_IP_FAULT;
            }
            else
            {
                state->status = LPSPI_IP_IDLE;
            }
            if (state->callback != NULL_PTR)
            {
                if((boolean)TRUE == bErrorFlag)
                {
                    state->callback(u8Instance, LPSPI_IP_EVENT_FAULT);
                }
                else
                {
                    state->callback(u8Instance, LPSPI_IP_EVENT_END_TRANSFER);
                }
            }
        }
    }
}

#if (LPSPI_IP_DMA_USED == STD_ON)
#if (LPSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
static void Lpspi_Ip_TxDmaTcdSGInit(uint8 u8Instance)
{
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[9u];
    uint8 u8TCDSGIndex = 0u;

    /* initialze configuration software TCD Scatter Gather for Tx DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; 
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    
    DmaTcdList[1u].Value = 0u;    /* dummy dest address write, will be updated latter according to ScatterGather to update TCR or TDR */
    DmaTcdList[2u].Value = 1u;  /* dummy src offset is 1 byte, will be updated latter according to frame size and transfer default data */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* dummy 1 byte src transfer size, will be updated latter according to frame size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* dummy 1 byte dest transfer size, will be updated latter according to frame size */
    DmaTcdList[5u].Value = 1u;   /* dummy bytes to transfer for each request, will be updated latter according to frame size */
    DmaTcdList[6u].Value = 0u; /* no dest offset */
    DmaTcdList[7u].Value = 0u; /* dummy iteration count, will be updated latter according to number of frames */
    DmaTcdList[8u].Value = 1u; /* dummy disable hardware request when major loop complete, will be updated latter according to last transfer or not */
    DmaTcdList[0u].Value = 0u; /* dummy src address read, will be updated latter base on pu8TxBuffer */
    
    for(u8TCDSGIndex = 0u; u8TCDSGIndex < state->u8MaxNumOfFastTransfer; u8TCDSGIndex++)
    {
        /* Update software TX DMA TCD Scatter Gather */
        Dma_Ip_SetLogicChannelScatterGatherList(state->txDmaChannel, state->pu8TxDmaFastSGId[u8TCDSGIndex], DmaTcdList, 9u);
    }
}

static void Lpspi_Ip_CmdTxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint32 u32CmdAdd, uint8 u8DisHwReq)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[9u];

    /* configure TX DMA TCD Scatter Gather to update transfer command TCR */
    /* No need to configure dest offset due to it are already set by Lpspi_Ip_TxDmaTcdSGInit */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
    
    DmaTcdList[0u].Value = u32CmdAdd; /* src address read */
    DmaTcdList[1u].Value = (uint32)&base->TCR;    /* dest address write*/
    DmaTcdList[2u].Value = 0u;  /* src offset is 0 byte */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
    DmaTcdList[5u].Value = 4u;   /* bytes to transfer for each request */
    DmaTcdList[6u].Value = 1u; /* iteration count */
    DmaTcdList[7u].Value = u8DisHwReq; /* disable hardware request when major loop complete */
    DmaTcdList[8u].Value = u8DisHwReq; /* Enable Major interrupt at the end of transfer sequence(meanning when u8DisHwReq = 1u) */

    /* Update software TX DMA TCD Scatter Gather */
    Dma_Ip_SetLogicChannelScatterGatherList(state->txDmaChannel, state->pu8TxDmaFastSGId[u8TCDSGIndex], DmaTcdList, 9u);
}

static void Lpspi_Ip_TxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint8 u8DisHwReq)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[9u];

    /* Update buffers index */
    state->txIndex = state->expectedFifoWrites;

    /* configure TX DMA TCD Scatter Gather to fill tx data to TDR */
    /* No need to configure dest offset due to it are already set by Lpspi_Ip_TxDmaTcdSGInit */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
    
    DmaTcdList[1u].Value = (uint32)&base->TDR;    /* dest address write*/
    if(state->u8FrameSize < 9u)
    {
        DmaTcdList[2u].Value = 1u;  /* src offset is 1 byte */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[5u].Value = 1u;   /* bytes to transfer for each request */
    }
    else if (state->u8FrameSize < 17u)
    {
        DmaTcdList[2u].Value = 2u;  /* src offset is 2 bytes */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[5u].Value = 2u;   /* bytes to transfer for each request */
    }
    else
    {
        DmaTcdList[2u].Value = 4u;  /* src offset is 4 bytes */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[5u].Value = 4u;   /* bytes to transfer for each request */
    }
    DmaTcdList[6u].Value = state->expectedFifoWrites; /* iteration count */
    DmaTcdList[7u].Value = u8DisHwReq; /* disable hardware request when major loop complete */
    DmaTcdList[8u].Value = u8DisHwReq; /* Enable Major interrupt at the end of transfer sequence(meanning when u8DisHwReq = 1u) */
    if(NULL_PTR == state->pu8TxBuffer)
    {
        /* send default data */
        DmaTcdList[0u].Value = (uint32)&state->pCmdDmaFast[u8TCDSGIndex].u32DefaultData; /* src address read */
        DmaTcdList[2u].Value = 0u;  /* src offset is 0 byte */
    }
    else
    {
        DmaTcdList[0u].Value = (uint32)state->pu8TxBuffer; /* src address read */
    }

    /* Update software TX DMA TCD Scatter Gather */
    Dma_Ip_SetLogicChannelScatterGatherList(state->txDmaChannel, state->pu8TxDmaFastSGId[u8TCDSGIndex], DmaTcdList, 9u);
}

static void Lpspi_Ip_RxDmaTcdSGInit(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[9u];
    uint8 u8TCDSGIndex = 0u;

    /* initialze configuration software TCD Scatter Gather for Rx DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS; 
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    
    DmaTcdList[0u].Value = (uint32)&base->RDR; /* src address read */
    DmaTcdList[2u].Value = 0u;  /* no src offset */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* dummy 1 byte src transfer size, will be updated latter base on frame size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* dummy 1 byte dest transfer size, will be updated latter base on frame size */
    DmaTcdList[5u].Value = 1u;   /* dummy 1 byte to transfer for each request, will be updated latter base on frame size */
    DmaTcdList[6u].Value = 1u; /* dummy dest offset is 1 byte, will be updated latter base on frame size and discard info */
    DmaTcdList[1u].Value = 0u;    /* dummy dest address write, will be updated latter base on pu8RxBuffer */ 
    DmaTcdList[7u].Value = 0u; /* dummy iteration count, will be updated latter base on number of frames */
    DmaTcdList[8u].Value = 1u; /* dummy disable hardware request when major loop complete, will be updated latter according to last transfer or not */
    
    for(u8TCDSGIndex = 0u; u8TCDSGIndex < state->u8MaxNumOfFastTransfer; u8TCDSGIndex++)
    {
        /* Update software RX DMA TCD Scatter Gather */
        Dma_Ip_SetLogicChannelScatterGatherList(state->rxDmaChannel, state->pu8RxDmaFastSGId[u8TCDSGIndex], DmaTcdList, 9u);
    }
}

static void Lpspi_Ip_RxDmaTcdSGConfig(uint8 u8Instance, uint8 u8TCDSGIndex, uint8 u8DisHwReq)
{
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[8u];

    /* Update buffers index */
    state->rxIndex = state->expectedFifoReads;
    
    /* configure RX DMA TCD Scatter Gather */
    /* No need to configure src address and src offset due to they are already set by Lpspi_Ip_RxDmaTcdSGInit */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;

    if(state->u8FrameSize < 9u)
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[3u].Value = 1u;   /* 1 byte to transfer for each request */
        DmaTcdList[4u].Value = 1u; /* dest offset is 1 bytes */
    }
    else if (state->u8FrameSize < 17u)
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[3u].Value = 2u;   /* 2 bytes to transfer for each request */
        DmaTcdList[4u].Value = 2u; /* dest offset is 2 bytes */
    }
    else
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[3u].Value = 4u;   /* 4 bytes to transfer for each request */
        DmaTcdList[4u].Value = 4u; /* dest offset is 4 bytes */
    }
    if(NULL_PTR == state->pu8RxBuffer)
    {
        /* Discard data */
        DmaTcdList[0u].Value = (uint32)&Spi_u32DiscardData;    /* dest address write*/ 
        DmaTcdList[4u].Value = 0u; /* dest offset is 0 bytes */
    }
    else
    {
        DmaTcdList[0u].Value = (uint32)state->pu8RxBuffer;    /* dest address write*/ 
    }
    DmaTcdList[5u].Value = state->expectedFifoReads; /* iteration count */
    DmaTcdList[6u].Value = u8DisHwReq; /* disable hardware request when major loop complete */
    DmaTcdList[7u].Value = u8DisHwReq; /* Enable Major interrupt at the end of transfer sequence(meanning when u8DisHwReq = 1u) */

    /* Update software RX DMA TCD Scatter Gather */
    Dma_Ip_SetLogicChannelScatterGatherList(state->rxDmaChannel, state->pu8RxDmaFastSGId[u8TCDSGIndex], DmaTcdList, 8u);
}
#endif    

/**
* @brief   This function will configure hardware TCDs for the channels TX DMA, RX DMA 
*          according to current transfer configuration. DMA channels will be started at the end of the function.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return void
*/
static void Lpspi_Ip_TxDmaConfig(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[10u];
    uint16 u16NumberDmaIterWrite = state->expectedFifoWrites;

    /* Limits number of major count */
    if(LPSPI_IP_DMA_MAX_ITER_CNT < u16NumberDmaIterWrite)
    {
        u16NumberDmaIterWrite = LPSPI_IP_DMA_MAX_ITER_CNT;
    }
    else
    {
        /* Nothing to do */
    }

    /* Update buffers index */
    state->txIndex = u16NumberDmaIterWrite;

    /* configure TX DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[9u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ;
    
    DmaTcdList[1u].Value = (uint32)&base->TDR;    /* dest address write*/
    if(state->u8FrameSize < 9u)
    {
        DmaTcdList[2u].Value = 1u;  /* src offset is 1 byte */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[5u].Value = 1u;   /* bytes to transfer for each request */
    }
    else if (state->u8FrameSize < 17u)
    {
        DmaTcdList[2u].Value = 2u;  /* src offset is 2 bytes */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[5u].Value = 2u;   /* bytes to transfer for each request */
    }
    else
    {
        DmaTcdList[2u].Value = 4u;  /* src offset is 4 bytes */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[5u].Value = 4u;   /* bytes to transfer for each request */
    }
    DmaTcdList[6u].Value = 0u; /* no dest offset */
    DmaTcdList[7u].Value = u16NumberDmaIterWrite; /* iteration count */
    DmaTcdList[8u].Value = 1u; /* disable hardware request when major loop complete */
    if(NULL_PTR == state->pu8TxBuffer)
    {
        /* send default data */
        DmaTcdList[0u].Value = (uint32)&state->u32DefaultData; /* src address read */
        DmaTcdList[2u].Value = 0u;  /* src offset is 0 byte */
    }
    else
    {
        DmaTcdList[0u].Value = (uint32)state->pu8TxBuffer; /* src address read */
    }
    /* Set DESTINATION_SIGNED_LAST_ADDR_ADJ = 0 to avoid the case it still stored from previous TCD Scatter Gather */
    DmaTcdList[9u].Value = 0u;    /* No adjust DADD when major loop completed */
    /* write TCD for TX DMA channel */
    Dma_Ip_SetLogicChannelTransferList(state->txDmaChannel, DmaTcdList, 10u);

    /* Enable TX DMA HW request */
    Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
}

/**
* @brief   This function will configure hardware TCDs for the channels TX DMA, RX DMA 
*          according to current transfer configuration. DMA channels will be started at the end of the function.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return void
*/
static void Lpspi_Ip_RxDmaConfig(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[10u];
    uint16 u16NumberDmaIterRead = state->expectedFifoReads;

    /* Limits number of major count */
    if(LPSPI_IP_DMA_MAX_ITER_CNT < u16NumberDmaIterRead)
    {
        u16NumberDmaIterRead = LPSPI_IP_DMA_MAX_ITER_CNT;
    }
    else
    {
        /* Nothing to do */
    }

    /* Update buffers index */
    state->rxIndex = u16NumberDmaIterRead;

    /* configure RX DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[9u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ;
    
    DmaTcdList[0u].Value = (uint32)&base->RDR; /* src address read */
    DmaTcdList[2u].Value = 0u;  /* no src offset */
    if(state->u8FrameSize < 9u)
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[5u].Value = 1u;   /* 1 byte to transfer for each request */
        DmaTcdList[6u].Value = 1u; /* dest offset is 1 bytes */
    }
    else if (state->u8FrameSize < 17u)
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[5u].Value = 2u;   /* 2 bytes to transfer for each request */
        DmaTcdList[6u].Value = 2u; /* dest offset is 2 bytes */
    }
    else
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[5u].Value = 4u;   /* 4 bytes to transfer for each request */
        DmaTcdList[6u].Value = 4u; /* dest offset is 4 bytes */
    }
    if(NULL_PTR == state->pu8RxBuffer)
    {
        /* Discard data */
        DmaTcdList[1u].Value = (uint32)&Spi_u32DiscardData;    /* dest address write*/ 
        DmaTcdList[6u].Value = 0u; /* dest offset is 0 bytes */
    }
    else
    {
        DmaTcdList[1u].Value = (uint32)state->pu8RxBuffer;    /* dest address write*/ 
    }
    DmaTcdList[7u].Value = u16NumberDmaIterRead; /* iteration count */
    DmaTcdList[8u].Value = 1u; /* disable hardware request when major loop complete */
    /* Set DESTINATION_SIGNED_LAST_ADDR_ADJ = 0 to avoid the case it still stored from previous TCD Scatter Gather */
    DmaTcdList[9u].Value = 0u;    /* No adjust DADD when major loop completed */
    /* write TCD for RX DMA channel */
    Dma_Ip_SetLogicChannelTransferList(state->rxDmaChannel, DmaTcdList, 10u);

    /* Enable RX DMA HW request */
    Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
}

static void Lpspi_Ip_TxDmaContinueTransfer(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[1u];
    uint16 u16NumberDmaIterWrite = state->expectedFifoWrites - state->txIndex;

    /* Limits number of major count */
    if(LPSPI_IP_DMA_MAX_ITER_CNT < u16NumberDmaIterWrite)
    {
        u16NumberDmaIterWrite = LPSPI_IP_DMA_MAX_ITER_CNT;
    }
    else
    {
        /* Nothing to do */
    }

    state->txIndex += u16NumberDmaIterWrite;

    /* Update TX DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[0u].Value = u16NumberDmaIterWrite;    /* iteration count */
    Dma_Ip_SetLogicChannelTransferList(state->txDmaChannel, DmaTcdList, 1u);

    /* Disable TX DMA request to avoid overflow because RX DMA needs time to be initialized for next transfer,
    TX DMA request will be enabled later when RX DMA complete by Lpspi_Ip_RxDmaContinueTransfer. */
    base->DER &= ~LPSPI_DER_TDDE_MASK;
    /* Enable TX DMA HW request for TX DMA channel */
    Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    #if (LPSPI_IP_SLAVE_SUPPORT == STD_ON)
    if((boolean)TRUE == state->bSlaveMode)
    {
        /* Push first frame to TX FIFO to ensure that TX FIFO is not empty and CS can be kept in the case of CS continue */
        Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_SET_SOFTWARE_REQUEST);
    }
    #endif
}

static void Lpspi_Ip_RxDmaContinueTransfer(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[1u];
    uint16 u16NumberDmaIterRead = state->expectedFifoReads - state->rxIndex;

    /* Limits number of major count */
    if(LPSPI_IP_DMA_MAX_ITER_CNT < u16NumberDmaIterRead)
    {
        u16NumberDmaIterRead = LPSPI_IP_DMA_MAX_ITER_CNT;
    }
    else
    {
        /* Nothing to do */
    }

    state->rxIndex += u16NumberDmaIterRead;

    /* Update RX DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[0u].Value = u16NumberDmaIterRead;    /* iteration count */
    Dma_Ip_SetLogicChannelTransferList(state->rxDmaChannel, DmaTcdList, 1u);

    /* Enable DMA HW request for RX DMA channel */
    Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    /* Enable TX DMA request due to it is disabled in Lpspi_Ip_TxDmaContinueTransfer */
    base->DER |= LPSPI_DER_TDDE_MASK;
}

/*==================================================================================================
*                                      GLOBAL FUNCTIONS
==================================================================================================*/
/**
* @brief   This function will process TX DMA transfer complete interrupt. 
* @details This function will process continue transfer or end of transfer via TX DMA.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return void
* @implements Lpspi_Ip_IrqTxDmaHandler_Activity
*/
void Lpspi_Ip_IrqTxDmaHandler(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 srStatusRegister = 0u;
    boolean bErrorFlag = (boolean)FALSE;

    if(NULL_PTR != state)
    {
        if (LPSPI_IP_BUSY == state->status)
        {
            /* Read status an clear all flags. */
            srStatusRegister = base->SR;
            base->SR &= (uint32)0xFFFFFFFFu;

            if ((srStatusRegister & (LPSPI_SR_REF_MASK | LPSPI_SR_TEF_MASK)) != 0u)
            {
                 /* mark error flag */
                bErrorFlag = (boolean)TRUE;
            }
            else
            {
                if (state->expectedFifoWrites != state->txIndex)
                {
                    /* Transfer is not finished => update TX pointers */
                    Lpspi_Ip_TxDmaContinueTransfer(u8Instance);
                }
                else
                {
                    /* last command can be written because TX FIFO is not full when TXWATER < 3 */
                    if(((boolean)FALSE == state->bKeepCs) && (0u != (base->TCR & LPSPI_TCR_CONT_MASK)))
                    {
                        /* Write last command to TX FIFO to clear CS */
                        base->TCR &= ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK);
                    }
                }
            }
            
            if ((boolean)TRUE == bErrorFlag)
            {
                SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_13();
                /* Disable module to stop transfer */
                base->CR &= ~LPSPI_CR_MEN_MASK;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_13();
                /* Disable DMA requests. */
                base->DER = 0;
                /* Disable RX DMA HW request because may RX DMA is not completed, no need to apply for TX DMA due to DMA HW request is cleared automatically */
                Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
                state->status = LPSPI_IP_FAULT;
                if (state->callback != NULL_PTR)
                {
                    state->callback(u8Instance, LPSPI_IP_EVENT_FAULT);
                }
            }
        }
    }
    else
    {
        /* Driver is initialized but there was no poll request*/
        /* nothing to do */
    }
}

/**
* @brief   This function will process RX DMA transfer complete interrupt. 
* @details This function will process continue transfer or end of transfer via RX DMA.
*
* @param[in]     u8Instance      Index of the hardware instance.
* @return void
* @implements Lpspi_Ip_IrqRxDmaHandler_Activity
*/
void Lpspi_Ip_IrqRxDmaHandler(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 srStatusRegister = 0u;
    boolean bErrorFlag = (boolean)FALSE;
    boolean bEndOfTransferFlag = (boolean)FALSE;

    if(NULL_PTR != state)
    {
        if (LPSPI_IP_BUSY == state->status)
        {
            /* Read status an clear all flags. */
            srStatusRegister = base->SR;
            base->SR &= (uint32)0xFFFFFFFFu;

            if ((srStatusRegister & (LPSPI_SR_REF_MASK | LPSPI_SR_TEF_MASK)) != 0u)
            {
                 /* mark error flag */
                bErrorFlag = (boolean)TRUE;
            }
            else
            {
                if (state->expectedFifoReads != state->rxIndex)
                {
                    /* Transfer is not finished => update RX pointers */
                    Lpspi_Ip_RxDmaContinueTransfer(u8Instance);
                }
                else
                {
                    bEndOfTransferFlag = (boolean)TRUE;
                }
            }

            if (((boolean)TRUE == bEndOfTransferFlag) || ((boolean)TRUE == bErrorFlag))
            {
                if(((boolean)FALSE == state->bKeepCs) || ((boolean)TRUE == bErrorFlag))
                {
                    SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_14();
                    /* Disable module to stop transfer */
                    base->CR &= ~LPSPI_CR_MEN_MASK;
                    SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_14();
                }
                /* Disable DMA requests. */
                base->DER = 0;
                if((boolean)TRUE == bErrorFlag)
                {
                    state->status = LPSPI_IP_FAULT;
                    /* Disable TX DMA HW request because may TX DMA is not completed, no need to apply for RX DMA due to DMA HW request is cleared automatically */
                    Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
                }
                else
                {
                    state->status = LPSPI_IP_IDLE;
                }
                if (state->callback != NULL_PTR)
                {
                    if((boolean)TRUE == bErrorFlag)
                    {
                        state->callback(u8Instance, LPSPI_IP_EVENT_FAULT);
                    }
                    else
                    {
                        state->callback(u8Instance, LPSPI_IP_EVENT_END_TRANSFER);
                    }
                }
            }
        }
    }
    else
    {
        /* Driver is initialized but there was no poll request*/
        /* nothing to do */
    }
}
#endif /* (LPSPI_IP_DMA_USED == STD_ON) */

#if (STD_ON == LPSPI_IP_ENABLE_USER_MODE_SUPPORT)
/**
* @brief This function will set UAA bit in REG_PROT for SPI unit
*/
static void Lpspi_Ip_SetUserAccess(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    
    SET_USER_ACCESS_ALLOWED((uint32)base,LPSPI_IP_PROT_MEM_U32);
}

/**
* @brief This function will enable writing all SPI registers under protection in User mode by configuring REG_PROT
*/
static void Lpspi_Ip_SetUserAccessAllowed(uint8 u8Instance)
{
    OsIf_Trusted_Call1param(Lpspi_Ip_SetUserAccess, u8Instance);
}
#endif /* LPSPI_IP_ENABLE_USER_MODE_SUPPORT */
/*================================================================================================*/
Lpspi_Ip_StatusType Lpspi_Ip_Init(const Lpspi_Ip_ConfigType *pPhyUnitConfigPtr)
{
    LPSPI_Type* base;
    Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    uint8 u8Instance = 0u;

#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pPhyUnitConfigPtr == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
#endif
    {
        u8Instance = pPhyUnitConfigPtr->u8Instance;
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        base = Lpspi_Ip_Bases[u8Instance];
#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state != NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
#endif
        {
            Lpspi_Ip_StateStructureArray[u8Instance] = pPhyUnitConfigPtr->stateStructure;
            state = Lpspi_Ip_StateStructureArray[u8Instance];
            /* enable in debug mode to ensure CS will be kept when CPU halts at breakpoint */
            base->CR = pPhyUnitConfigPtr->cr | LPSPI_CR_DBGEN_MASK;
            base->CFGR1 = pPhyUnitConfigPtr->cfgr1;
            /* To avoid overflow error when interrupt service is delayed, the maximum number of TX FIFO entry 
            can be filled is LPSPI_IP_FIFO_SIZE - 1 because may 1 frame is shifting out */
            base->FCR = LPSPI_FCR_TXWATER((uint32)LPSPI_IP_FIFO_SIZE - (uint32)2u);
            #if (LPSPI_IP_SLAVE_SUPPORT == STD_ON)
            state->bSlaveMode = pPhyUnitConfigPtr->bSlaveMode;
            #endif
            #if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
            state->ClockMode = LPSPI_IP_NORMAL_CLOCK;
            #endif
            state->bKeepCs = (boolean)FALSE;
            state->bFirstCmd = (boolean)TRUE;
            #if (LPSPI_IP_DMA_USED == STD_ON)
            state->bDmaUsed = pPhyUnitConfigPtr->bDmaUsed;
            state->txDmaChannel = pPhyUnitConfigPtr->txDmaChannel;
            state->rxDmaChannel = pPhyUnitConfigPtr->rxDmaChannel;
            #if (LPSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
            state->u8MaxNumOfFastTransfer = pPhyUnitConfigPtr->u8MaxNumOfFastTransfer;
            state->pCmdDmaFast = pPhyUnitConfigPtr->pCmdDmaFast;
            state->u8NumberTxSG = pPhyUnitConfigPtr->u8NumberTxSG;
            state->u8NumberRxSG = pPhyUnitConfigPtr->u8NumberRxSG;
            state->pu8TxDmaFastSGId = pPhyUnitConfigPtr->pu8TxDmaFastSGId;
            state->pu8RxDmaFastSGId = pPhyUnitConfigPtr->pu8RxDmaFastSGId;
            Lpspi_Ip_TxDmaTcdSGInit(u8Instance);
            Lpspi_Ip_RxDmaTcdSGInit(u8Instance);
            #endif
            #endif
            /* set state to idle */
            state->status = LPSPI_IP_IDLE;
            (void)Lpspi_Ip_UpdateTransferMode(u8Instance, pPhyUnitConfigPtr->transferMode);
        }
    }
    return status;
}
/*================================================================================================*/
Lpspi_Ip_StatusType Lpspi_Ip_DeInit(uint8 u8Instance)
{
    LPSPI_Type* base;
    const Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;

#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
#endif
    {
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            if (state->status == LPSPI_IP_BUSY)
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
            else
            {
                /* Use reset hardware feature. */
                base->CR |= LPSPI_CR_RST(1u);
                base->CR = 0;

                Lpspi_Ip_StateStructureArray[u8Instance] = NULL_PTR;
            }
        }
    }
    return status;
}

/*================================================================================================*/
Lpspi_Ip_StatusType Lpspi_Ip_SyncTransmit(
                                            const Lpspi_Ip_ExternalDeviceType *pExternalDevice,
                                            uint8 *pu8TxBuffer,
                                            uint8 *pu8RxBuffer,
                                            uint16 u16Length,
                                            uint32 u32TimeOut
                                         )
{
    LPSPI_Type *base;
    Lpspi_Ip_StateStructureType *state;
    uint8 numberOfReads;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    Lpspi_Ip_StatusType DataProcessStatus = LPSPI_IP_STATUS_FAIL;
    uint32 TimeoutTicks = OsIf_MicrosToTicks(u32TimeOut, LPSPI_IP_TIMEOUT_METHOD);
    uint32 CurrentTicks = 0u; /* initialize current counter */
    uint32 ElapsedTicks = 0u; /* elapsed will give timeout */
    uint8 u8Instance = 0u;

#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pExternalDevice == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else if (0u == u16Length)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else if (0u == u32TimeOut)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
#endif
    {
        u8Instance = pExternalDevice->u8Instance;
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else if (pExternalDevice->pDeviceParams->u8FrameSize > 16u)
        {
            if ((u16Length%4) != 0u)
            {
                DevAssert(0);
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
        else if (pExternalDevice->pDeviceParams->u8FrameSize > 8u)
        {
            if ((u16Length%2) != 0u)
            {
                DevAssert(0);
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
        else
        {
            /* do nothing */
        }
        if (status != LPSPI_IP_STATUS_FAIL)
#endif
        {
            SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_08();
            if (state->status == LPSPI_IP_BUSY)
            {
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_08();
                status = LPSPI_IP_STATUS_FAIL;
            }
            else
            {
                /* Mark the hardware as busy. */
                state->status = LPSPI_IP_BUSY;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_08();
                
                /* Disable DMA requests and all interrupts */
                base->DER = 0u;
                base->IER = 0u;
                
                /* Update state structure. */
                state->u8FrameSize = pExternalDevice->pDeviceParams->u8FrameSize;
                state->lsb = pExternalDevice->pDeviceParams->lsb;
                state->u32DefaultData = pExternalDevice->pDeviceParams->u32DefaultData;
                state->pExternalDevice = pExternalDevice;
                
                Lpspi_TransmitTxInit(u8Instance, pu8TxBuffer, u16Length);
                Lpspi_TransmitRxInit(u8Instance, pu8RxBuffer, u16Length);
                
                CurrentTicks = OsIf_GetCounter(LPSPI_IP_TIMEOUT_METHOD); /* initialize current counter */
                while((state->rxIndex != state->expectedFifoReads) && (LPSPI_IP_STATUS_SUCCESS == status))
                {
                    /* Read all data available in receive HW fifo. */
                    numberOfReads = (uint8)(((base->FSR) & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT);
                    
                    /* Prevent hardware faults by limiting RXCTR to maximum value. */
                    if (numberOfReads > LPSPI_IP_FIFO_SIZE)
                    {
                        numberOfReads = LPSPI_IP_FIFO_SIZE;
                    }
                    
                    if(numberOfReads != 0u)
                    {
                        /* Limits to remaining frames. */
                        if (numberOfReads > (state->expectedFifoReads - state->rxIndex))
                        {
                            numberOfReads = (uint8)(state->expectedFifoReads - state->rxIndex);
                        }

                        if(numberOfReads != 0u)
                        {
                            ElapsedTicks = 0u;
                        }
                        /* Read data from RX FIFO */
                        Lpspi_Ip_ReadData(u8Instance, numberOfReads);
                    }

                    /* Process to push data into TX FIFO */
                    DataProcessStatus = Lpspi_Ip_PushDataProcess(u8Instance);
                    if(LPSPI_IP_STATUS_SUCCESS == DataProcessStatus)
                    {
                        ElapsedTicks = 0u;
                    }

                    /* Check if errors like overflow or underflow are reported in status register. */
                    if ((base->SR & (LPSPI_SR_TEF_MASK | LPSPI_SR_REF_MASK)) != 0u)
                    {
                        /* Clear status flags. */
                        base->SR &= LPSPI_SR_REF_MASK | LPSPI_SR_TEF_MASK;
                        status = LPSPI_IP_FIFO_ERROR;
                    }
                    ElapsedTicks += OsIf_GetElapsed(&CurrentTicks, LPSPI_IP_TIMEOUT_METHOD);
                    if (ElapsedTicks >= TimeoutTicks)
                    {
                        status = LPSPI_IP_TIMEOUT;
                    }
                }
                /* Disable module to stop transfer when there is an error or CONT bit is cleared */
                if(((boolean)FALSE == state->bKeepCs) || (LPSPI_IP_STATUS_SUCCESS != status))
                {
                    base->CR &= ~LPSPI_CR_MEN_MASK;
                }
                if(LPSPI_IP_STATUS_SUCCESS != status)
                {
                    state->status = LPSPI_IP_FAULT;
                }
                else
                {
                    state->status = LPSPI_IP_IDLE;
                }
            }
        }
    }
    return status;
}

static void Lpspi_TransmitTxInit(uint8 u8Instance,
                                      uint8* pu8TxBuffer,
                                      uint16 numberOfFrames
                                     )
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 u32TransferCommand = 0u;
    uint32 u32Cfgr1 = 0u;
    
    /* Set clock configuration */
    if((boolean)TRUE == state->bFirstCmd)
    {
        SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_11();
        /* Disable module before configure CCR */
        base->CR &= ~LPSPI_CR_MEN_MASK;
        /* Make sure that FIFOs will be empty before start new transfer session */
        #ifdef ERR_IPV_LPSPIV2_0001
            /* ERR050456 workaround: Reset FIFOs using CR[RST] bit */
            /* store CFGR1 and restore after all registers are reset */
            u32Cfgr1 = base->CFGR1;
            base->CR |= LPSPI_CR_RST_MASK;
            base->CR &= ~LPSPI_CR_RST_MASK;
            /* restore CFGR1 */
            base->CFGR1 = u32Cfgr1;
        #else
            base->CR |= LPSPI_CR_RTF_MASK|LPSPI_CR_RRF_MASK;
        #endif
        /* clear all flags */
        base->SR &= (uint32)0xFFFFFFFFu;
        /* Does not use the Clock Configuration Register (CCR) for Slave mode */
        #if (LPSPI_IP_SLAVE_SUPPORT == STD_ON)
        if((boolean)FALSE == state->bSlaveMode)
        #endif
        {
            #if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
                base->CCR = state->pExternalDevice->ccr[state->ClockMode];
            #else
                base->CCR = state->pExternalDevice->ccr;
            #endif
        }
    }
    /* Get transfer command */
    #if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
        u32TransferCommand = state->pExternalDevice->tcr[state->ClockMode] | LPSPI_TCR_FRAMESZ((uint32)state->u8FrameSize - 1u) | LPSPI_TCR_LSBF(state->lsb);
    #else
        u32TransferCommand = state->pExternalDevice->tcr | LPSPI_TCR_FRAMESZ((uint32)state->u8FrameSize - 1u) | LPSPI_TCR_LSBF(state->lsb);
    #endif
    
    /* In Slave mode, CONT bit should be cleared */
    #if (LPSPI_IP_SLAVE_SUPPORT == STD_ON)
    if((boolean)TRUE == state->bSlaveMode)
    {
        u32TransferCommand &= ~LPSPI_TCR_CONT_MASK;
    }
    #endif
    
    if((boolean)TRUE == state->bFirstCmd)
    {
        /* Set transfer command */
        base->TCR = u32TransferCommand;
        /* Enable module after TCR initialized */
        base->CR |= LPSPI_CR_MEN_MASK;
        SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_11();
    }
    else
    {
        if(0u != (u32TransferCommand & LPSPI_TCR_CONT_MASK))
        {
            base->TCR = u32TransferCommand | LPSPI_TCR_CONTC_MASK;
        }
        else
        {
            base->TCR = u32TransferCommand;
        }
    }
    
    /* Update state structure. */
    state->txIndex = 0u;
    state->pu8TxBuffer = pu8TxBuffer;
    if (state->u8FrameSize < 9u)
    {
        state->expectedFifoWrites = numberOfFrames;
    }
    else if (state->u8FrameSize < 17u)
    {
        state->expectedFifoWrites = numberOfFrames/2u;
    }
    else
    {
        state->expectedFifoWrites = numberOfFrames/4u;
    }
}

static void Lpspi_TransmitRxInit(uint8 u8Instance,
                                      uint8* pu8RxBuffer,
                                      uint16 numberOfFrames
                                     )
{
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    
    /* Update state structure. */
    state->rxIndex = 0u;
    state->pu8RxBuffer = pu8RxBuffer;
    if (state->u8FrameSize < 9u)
    {
        state->expectedFifoReads = numberOfFrames;
    }
    else if (state->u8FrameSize < 17u)
    {
        state->expectedFifoReads = numberOfFrames/2u;
    }
    else
    {
        state->expectedFifoReads = numberOfFrames/4u;
    }
}

Lpspi_Ip_StatusType Lpspi_Ip_AsyncTransmit(
                                            const Lpspi_Ip_ExternalDeviceType *pExternalDevice,
                                            uint8 *pu8TxBuffer,
                                            uint8 *pu8RxBuffer,
                                            uint16 u16Length,
                                            Lpspi_Ip_CallbackType EndCallback
                                          )
{
    LPSPI_Type* base;
    Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    uint8 u8Instance = 0u;
    #if (LPSPI_IP_DMA_USED == STD_ON)
    Dma_Ip_LogicChannelTransferListType DmaTcdList[1u];
    #endif

#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pExternalDevice == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else if (0u == u16Length)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
#endif
    {
        u8Instance = pExternalDevice->u8Instance;
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else if (pExternalDevice->pDeviceParams->u8FrameSize > 16u)
        {
            if ((u16Length%4) != 0u)
            {
                DevAssert(0);
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
        else if (pExternalDevice->pDeviceParams->u8FrameSize > 8u)
        {
            if ((u16Length%2) != 0u)
            {
                DevAssert(0);
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
        else
        {
            /* do nothing */
        }
        if (status != LPSPI_IP_STATUS_FAIL)
#endif
        {
            SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_09();
            if (LPSPI_IP_BUSY == state->status)
            {
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_09();
                status = LPSPI_IP_STATUS_FAIL;
            }
            else
            {
                /* Mark the hardware as busy. */
                state->status = LPSPI_IP_BUSY;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_09();
                
                /* Update state structure. */
                state->u8FrameSize = pExternalDevice->pDeviceParams->u8FrameSize;
                state->lsb = pExternalDevice->pDeviceParams->lsb;
                state->u32DefaultData = pExternalDevice->pDeviceParams->u32DefaultData;
                state->pExternalDevice = pExternalDevice;
                state->callback = EndCallback;
                
                Lpspi_TransmitTxInit(u8Instance, pu8TxBuffer, u16Length);
                Lpspi_TransmitRxInit(u8Instance, pu8RxBuffer, u16Length);
                
                #if (LPSPI_IP_DMA_USED == STD_ON)
                if ((boolean)FALSE == state->bDmaUsed)
                #endif
                {
                    /* Disable DMA requests */
                    base->DER = 0u;
                    switch (state->transferMode)
                    {
                        case LPSPI_IP_POLLING:
                            /* Disable interrupts. */
                            base->IER = 0U;
                            break;
                        case LPSPI_IP_INTERRUPT:
                            base->IER = LPSPI_IER_RDIE_MASK | LPSPI_IER_TDIE_MASK | LPSPI_IER_REIE_MASK | LPSPI_IER_TEIE_MASK;
                            break;
                        default:
                            /* Nothing to do */
                            break;
                    }
                }
                #if (LPSPI_IP_DMA_USED == STD_ON)
                else
                {
                    /* Disable all interrupts */
                    base->IER = 0u;
                    /* Activate TX DMA and RX DMA interrupt in interrupt mode or disable then in polling mode. */
                    DmaTcdList[0u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
                    switch(state->transferMode)
                    {
                        case LPSPI_IP_POLLING:
                            /* Disable DMA major interrupt. */
                            DmaTcdList[0u].Value = 0u;
                            break;
                        case LPSPI_IP_INTERRUPT:
                            /* Enable DMA major interrupt. */
                            DmaTcdList[0u].Value = 1u;
                            break;
                        default:
                            /* Nothing to do */
                            break;
                    }
                    Dma_Ip_SetLogicChannelTransferList(state->txDmaChannel, DmaTcdList, 1u);
                    Dma_Ip_SetLogicChannelTransferList(state->rxDmaChannel, DmaTcdList, 1u);

                    /* Initialize DMA configuration for RX before TX*/
                    Lpspi_Ip_RxDmaConfig(u8Instance);
                    Lpspi_Ip_TxDmaConfig(u8Instance);
                    /* Enable DMA request. */
                    base->DER = LPSPI_DER_RDDE_MASK | LPSPI_DER_TDDE_MASK;
                }
                #endif
            }
        }
    }
    return status;
}

#if (LPSPI_IP_DMA_USED == STD_ON)
#if (LPSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
Lpspi_Ip_StatusType Lpspi_Ip_AsyncTransmitFast(
                                       const Lpspi_Ip_FastTransferType *pFastTransferCfg,
                                       uint8 u8NumberOfTransfer,
                                       Lpspi_Ip_CallbackType EndCallback
                                      )
{
    LPSPI_Type* base;
    Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    uint8 u8Instance = 0u;
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    uint8 u8Count = 0u;
    #endif
    uint32 u32Cfgr1 = 0u;

#if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == pFastTransferCfg)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else if (NULL_PTR == pFastTransferCfg[0u].pcExternalDevice)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
#endif
    {
        u8Instance = pFastTransferCfg[0u].pcExternalDevice->u8Instance;
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (NULL_PTR == state)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else if (state->transferMode != LPSPI_IP_INTERRUPT)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else if (u8NumberOfTransfer > state->u8MaxNumOfFastTransfer)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
            for(u8Count = 0u; u8Count < u8NumberOfTransfer; u8Count++)
            {
                if(NULL_PTR == pFastTransferCfg[u8Count].pcExternalDevice)
                {
                    DevAssert(0);
                    status = LPSPI_IP_STATUS_FAIL;
                }
                else if (0u == pFastTransferCfg[u8Count].u16Length)
                {
                    DevAssert(0);
                    status = LPSPI_IP_STATUS_FAIL;
                }
                else if (pFastTransferCfg[0u].pcExternalDevice->pDeviceParams->u8FrameSize > 16u)
                {
                    if ((pFastTransferCfg[u8Count].u16Length%4) != 0u)
                    {
                        DevAssert(0);
                        status = LPSPI_IP_STATUS_FAIL;
                    }
                }
                else if (pFastTransferCfg[0u].pcExternalDevice->pDeviceParams->u8FrameSize > 8u)
                {
                    if ((pFastTransferCfg[u8Count].u16Length%2) != 0u)
                    {
                        DevAssert(0);
                        status = LPSPI_IP_STATUS_FAIL;
                    }
                }
                else
                {
                    if (LPSPI_IP_DMA_MAX_ITER_CNT < pFastTransferCfg[u8Count].u16Length)
                    {
                        DevAssert(0);
                        status = LPSPI_IP_STATUS_FAIL;
                    }
                    else
                    {
                        /* do nothing */
                    }
                }
                
                if(LPSPI_IP_STATUS_FAIL == status)
                {
                    break;
                }
            }

            if(LPSPI_IP_STATUS_FAIL != status)
            #endif
            {
                SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_15();
                if (LPSPI_IP_BUSY == state->status)
                {
                    SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_15();
                    status = LPSPI_IP_STATUS_FAIL;
                }
                else
                {
                    /* Mark the hardware as busy. */
                    state->status = LPSPI_IP_BUSY;

                    /* Update state structure. */
                    /* For Dma Fast transfer, All transfers use the same HWUnit and in Master mode only.
                    Some parameters such as Baudrate, Delays timming SpiTimeClk2Cs, SpiTimeCs2Clk, SpiTimeCs2Cs, SpiDataWidth, SpiTransferStart configuration 
                    must be the same between transfers. So, make sure they are configured the same in each External Device allocated for Dma Fast Transfers.
                    And all those attributes can be got from first transfer in pFastTransferCfg */
                    state->u8FrameSize = pFastTransferCfg[0u].pcExternalDevice->pDeviceParams->u8FrameSize;
                    state->lsb = (uint8)pFastTransferCfg[0u].pcExternalDevice->pDeviceParams->lsb;
                    state->callback = EndCallback;

                    /* Disable module before configure CCR */
                    base->CR &= ~LPSPI_CR_MEN_MASK;
                    /* Make sure that FIFOs will be empty before start new transfer session */
                    #ifdef ERR_IPV_LPSPIV2_0001
                        /* ERR050456 workaround: Reset FIFOs using CR[RST] bit */
                        /* store CFGR1 and restore after all registers are reset */
                        u32Cfgr1 = base->CFGR1;
                        base->CR |= LPSPI_CR_RST_MASK;
                        base->CR &= ~LPSPI_CR_RST_MASK;
                        /* restore CFGR1 */
                        base->CFGR1 = u32Cfgr1;
                    #else
                        base->CR |= LPSPI_CR_RTF_MASK|LPSPI_CR_RRF_MASK;
                    #endif
                    /* clear all flags */
                    base->SR &= (uint32)0xFFFFFFFFu;
                    #if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
                        base->CCR = pFastTransferCfg[0u].pcExternalDevice->ccr[state->ClockMode];
                    #else
                        base->CCR = pFastTransferCfg[0u].pcExternalDevice->ccr;
                    #endif
                    base->CR |= LPSPI_CR_MEN_MASK;
                    SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_15();

                    /* Disable all interrupts */
                    base->IER = 0u;
                    /* Enable DMA request. */
                    base->DER = LPSPI_DER_RDDE_MASK | LPSPI_DER_TDDE_MASK;

                    Lpspi_Ip_DmaFastConfig(u8Instance, pFastTransferCfg, u8NumberOfTransfer);
                }
            }
        }
    }
    return status;
}

/**
* @brief   This function will configure Scatter/Gather TCDs for the channels TX DMA, RX DMA and CMD DMA 
*          according to Dma Fast transfers configuration. DMA channels will be started at the end of the function.
*/
static void Lpspi_Ip_DmaFastConfig(uint8 u8Instance, const Lpspi_Ip_FastTransferType *pFastTransferCfg, uint8 u8NumberOfTransfer)
{
    Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    boolean bClearCS = (boolean)FALSE;
    boolean u8DisHwRequest = 0u;
    uint8 u8Count = 0u;
    uint8 u8TxDmaTCDSGIndex = 0u;
    uint32 u32TransferCommand = 0u;
    boolean bFirstCmd = (boolean)TRUE;
    Dma_Ip_LogicChannelTransferListType DmaTcdList[1u];
    
    DmaTcdList[0u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
    DmaTcdList[0u].Value = 1u;

    for(u8Count = 0u; u8Count < u8NumberOfTransfer; u8Count++)
    {
        /* Update state structure. */
        state->rxIndex = 0u;
        state->txIndex = 0u;
        state->pu8TxBuffer = pFastTransferCfg[u8Count].pu8TxBuffer;
        state->pu8RxBuffer = pFastTransferCfg[u8Count].pu8RxBuffer;
        if (state->u8FrameSize < 9u)
        {
            state->expectedFifoWrites = pFastTransferCfg[u8Count].u16Length;
        }
        else if (state->u8FrameSize < 17u)
        {
            state->expectedFifoWrites = pFastTransferCfg[u8Count].u16Length/2u;
        }
        else
        {
            state->expectedFifoWrites = pFastTransferCfg[u8Count].u16Length/4u;
        }
        state->expectedFifoReads = state->expectedFifoWrites;
        state->pCmdDmaFast[u8Count].u32DefaultData = pFastTransferCfg[u8Count].u32DefaultData;
        
        /* Get transfer command */
        #if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
            u32TransferCommand = pFastTransferCfg[u8Count].pcExternalDevice->tcr[state->ClockMode] | LPSPI_TCR_FRAMESZ((uint32)state->u8FrameSize - 1u) | LPSPI_TCR_LSBF(state->lsb);
        #else
            u32TransferCommand = pFastTransferCfg[u8Count].pcExternalDevice->tcr | LPSPI_TCR_FRAMESZ((uint32)state->u8FrameSize - 1u) | LPSPI_TCR_LSBF(state->lsb);
        #endif
        
        if(0u != (u32TransferCommand & LPSPI_TCR_CONT_MASK))
        {
            if((boolean)TRUE == bFirstCmd)
            {
                bFirstCmd = (boolean)FALSE;
                /* In continue CS, no need to set CONTC for first command */
                state->pCmdDmaFast[u8Count].u32DmaFastTcrCmd = u32TransferCommand;
            }
            else
            {
                /* In continue CS, need to set CONTC for next command */
                state->pCmdDmaFast[u8Count].u32DmaFastTcrCmd = u32TransferCommand | LPSPI_TCR_CONTC_MASK;
            }
            state->pCmdDmaFast[u8Count].u32DmaFastTcrCmdLast = u32TransferCommand & (~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK));
        }
        else
        {
            /* In non-continue CS, set u32DmaFastTcrCmd = u32DmaFastTcrCmdLast */
            state->pCmdDmaFast[u8Count].u32DmaFastTcrCmd = u32TransferCommand;
            state->pCmdDmaFast[u8Count].u32DmaFastTcrCmdLast = u32TransferCommand;
        }
        if((boolean)FALSE == pFastTransferCfg[u8Count].bKeepCs)
        {
            /* After CS is cleared, next transfer will be set as first command */
            bFirstCmd = (boolean)TRUE;
        }

        /* CS will be cleared for last transfer or depend on bKeepCs if not last transfer.
        Disable DMA HW request at the end of transfer. */
        if(u8Count == (u8NumberOfTransfer - 1u))
        {
            bClearCS = (boolean)TRUE;
            u8DisHwRequest = 1u;
        }
        else
        {
            if((boolean)FALSE == pFastTransferCfg[u8Count].bKeepCs)
            {
                bClearCS = (boolean)TRUE;
            }
            else
            {
                bClearCS = (boolean)FALSE;
            }
            u8DisHwRequest = 0u;
        }

        /* Configure software TCDs Scatter Gather for TX DMA channel to update TCR */
        /* No disable dma hw request for transfer command */
        Lpspi_Ip_CmdTxDmaTcdSGConfig(u8Instance, u8TxDmaTCDSGIndex, (uint32)&state->pCmdDmaFast[u8Count].u32DmaFastTcrCmd, 0u);
        u8TxDmaTCDSGIndex++;

        if(((boolean)TRUE == bClearCS) && (0u != (u32TransferCommand & LPSPI_TCR_CONT_MASK)))
        {
            /* Configure software TCDs Scatter Gather for TX DMA channel to fill TDR, no disable dma hw request */
            Lpspi_Ip_TxDmaTcdSGConfig(u8Instance, u8TxDmaTCDSGIndex, 0u);
            u8TxDmaTCDSGIndex++;
            /* disable dma hw request for last transfer command */
            Lpspi_Ip_CmdTxDmaTcdSGConfig(u8Instance, u8TxDmaTCDSGIndex, (uint32)&state->pCmdDmaFast[u8Count].u32DmaFastTcrCmdLast, u8DisHwRequest);
            u8TxDmaTCDSGIndex++;
        }
        else
        {
            /* Configure software TCDs Scatter Gather for TX DMA channel to fill TDR */
            Lpspi_Ip_TxDmaTcdSGConfig(u8Instance, u8TxDmaTCDSGIndex, u8DisHwRequest);
            u8TxDmaTCDSGIndex++;
        }
        
        /* Configure software TCDs Scatter Gather for RX DMA channel */
        Lpspi_Ip_RxDmaTcdSGConfig(u8Instance, u8Count, u8DisHwRequest);
    }
    
    /* When all transfers session are completed and next TCD ScatterGather is loaded to HW. If next TCD ScatterGather loaded has INTMAJOR=0 then 
    Dma_Ip interrupt function will not call Spi Dma notification due to it understood as spurious interrupt(Done flag = 1, INTMAJOR=0).
    So, the workaround is set INTMAJOR=1 for next TCD ScatterGather. */
    if (u8TxDmaTCDSGIndex <= state->u8NumberTxSG)
    {
        /* Set INTMAJOR=1 for next TX TCD ScatterGather */
        Dma_Ip_SetLogicChannelScatterGatherList(state->txDmaChannel, state->pu8TxDmaFastSGId[u8TxDmaTCDSGIndex], DmaTcdList, 1u);
    }
    if (u8Count <= state->u8NumberRxSG)
    {
        /* Set INTMAJOR=1 for next RX TCD ScatterGather */
        Dma_Ip_SetLogicChannelScatterGatherList(state->rxDmaChannel, state->pu8RxDmaFastSGId[u8Count], DmaTcdList, 1u);
    }
    
    /* Load first software TCD to hardware TCD for TX DMA channel */
    Dma_Ip_SetLogicChannelScatterGatherConfig(state->txDmaChannel, state->pu8TxDmaFastSGId[0u]);
    /* Load first software TCD to hardware TCD for RX DMA channel */
    Dma_Ip_SetLogicChannelScatterGatherConfig(state->rxDmaChannel, state->pu8RxDmaFastSGId[0u]);

    /* Enable HW request for RX DMA channel before TX DMA channel */
    Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
}
#endif
#endif

void Lpspi_Ip_ManageBuffers(uint8 u8Instance)
{
    const LPSPI_Type* base;
    const Lpspi_Ip_StateStructureType* state;
    #if (LPSPI_IP_DMA_USED == STD_ON)
    Dma_Ip_LogicChannelStatusType DmaChannelStatus;
    #endif

    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
    }
    else
    #endif
    {
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
        }
        else
        #endif
        {
            if(LPSPI_IP_POLLING == state->transferMode)
            {
                #if (LPSPI_IP_DMA_USED == STD_ON)
                if((boolean)FALSE == state->bDmaUsed)
                #endif
                {
                    if((base->SR & (LPSPI_SR_TDF_MASK | LPSPI_SR_RDF_MASK)) != 0u)
                    {
                        Lpspi_Ip_TransferProcess(u8Instance);
                    }
                }
                #if (LPSPI_IP_DMA_USED == STD_ON)
                else
                {
                    /* Polling RX before TX */
                    Dma_Ip_GetLogicChannelStatus(state->rxDmaChannel, &DmaChannelStatus);
                    if((boolean)TRUE == DmaChannelStatus.Done)
                    {
                        /* Clear DONE bit */
                        Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_CLEAR_DONE);
                        Lpspi_Ip_IrqRxDmaHandler(u8Instance);
                    }
                    
                    Dma_Ip_GetLogicChannelStatus(state->txDmaChannel, &DmaChannelStatus);
                    if((boolean)TRUE == DmaChannelStatus.Done)
                    {
                        /* Clear DONE bit */
                        Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_CLEAR_DONE);
                        Lpspi_Ip_IrqTxDmaHandler(u8Instance);
                    }
                }
                #endif
            }
        }
    }
}
/*================================================================================================*/
Lpspi_Ip_StatusType Lpspi_Ip_UpdateFrameSize(const Lpspi_Ip_ExternalDeviceType *pExternalDevice, uint8 u8FrameSize)
{
    const Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;

    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pExternalDevice == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else if ((LPSPI_IP_FRAMESIZE_MAX < u8FrameSize) || (LPSPI_IP_FRAMESIZE_MIN > u8FrameSize))
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[pExternalDevice->u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            /* Frame size can be changed when no transfers are in progress. */
            if (state->status != LPSPI_IP_BUSY)
            {
                pExternalDevice->pDeviceParams->u8FrameSize = u8FrameSize;
            }
            else
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
    }
    return status;
}

Lpspi_Ip_StatusType Lpspi_Ip_UpdateLsb(const Lpspi_Ip_ExternalDeviceType *pExternalDevice, boolean bLsb)
{
    const Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pExternalDevice == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[pExternalDevice->u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            /* Bite order can be changed when no transfers are in progress. */
            if (state->status != LPSPI_IP_BUSY)
            {
                pExternalDevice->pDeviceParams->lsb = bLsb;
            }
            else
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
    }
    return status;
}

Lpspi_Ip_StatusType Lpspi_Ip_UpdateDefaultTransmitData(const Lpspi_Ip_ExternalDeviceType *pExternalDevice, uint32 u32DefaultData)
{
    const Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (pExternalDevice == NULL_PTR)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[pExternalDevice->u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            /* Bite order can be changed when no transfers are in progress. */
            if (state->status != LPSPI_IP_BUSY)
            {
                pExternalDevice->pDeviceParams->u32DefaultData = u32DefaultData;
            }
            else
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
    }
    return status;
}

Lpspi_Ip_StatusType Lpspi_Ip_UpdateTransferMode(uint8 u8Instance, Lpspi_Ip_ModeType Mode)
{
    Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;

    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            /* Transfer mode can be changed when no transfers are in progress. */
            if (state->status != LPSPI_IP_BUSY)
            {
                state->transferMode = Mode;
            }
            else
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
    }
    return status;
}

void Lpspi_Ip_Cancel(uint8 u8Instance)
{
    LPSPI_Type* base;
    Lpspi_Ip_StateStructureType* state;
    uint32 u32Cfgr1 = 0u;
    
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
    }
    else
    #endif
    {
        base = Lpspi_Ip_Bases[u8Instance];
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
        }
        else
        #endif
        {
            SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_10();
            if(LPSPI_IP_BUSY == state->status)
            {
                /* Disable module to stop transfer */
                base->CR &= ~LPSPI_CR_MEN_MASK;
                /* store CFGR1 and restore after all registers are reset */
                u32Cfgr1 = base->CFGR1;
                /* Disable interrupts and DMA requests. */
                /* Clear FIFO */
                /* RTF and RRF will not clear shifter, so RST must be used to ensure old data in shifter will also be cleared. */
                base->CR |= LPSPI_CR_RST_MASK;
                base->CR &= ~LPSPI_CR_RST_MASK;
                /* restore CFGR1 */
                base->CFGR1 = u32Cfgr1;
                #if (LPSPI_IP_DMA_USED == STD_ON)
                if((boolean)TRUE == state->bDmaUsed)
                {
                    /* Disable all HW request */
                    Dma_Ip_SetLogicChannelCommand(state->rxDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
                    Dma_Ip_SetLogicChannelCommand(state->txDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
                }
                #endif
                /* set state to idle */
                state->status = LPSPI_IP_IDLE;
            }
            SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_10();
        }
    }
}

/**
* @brief   This function is called by LSPI ISRs.
* @details This function will process activities for flags TDF, RDF, REF and TEF.
*
* @param[in]     u8Instance            Instance of the hardware unit.
*
* @implements Lpspi_Ip_IrqHandler_Activity
*/
void Lpspi_Ip_IrqHandler(uint8 u8Instance)
{
    LPSPI_Type* base = Lpspi_Ip_Bases[u8Instance];
    const Lpspi_Ip_StateStructureType* state = Lpspi_Ip_StateStructureArray[u8Instance];
    uint32 u32IrqFlags = 0u;

    if(NULL_PTR != state)
    {
        /* the driver has been initialized */
        u32IrqFlags = base->SR & (LPSPI_SR_TDF_MASK | LPSPI_SR_RDF_MASK | LPSPI_SR_TEF_MASK | LPSPI_SR_REF_MASK);
        u32IrqFlags &= base->IER & (LPSPI_IER_TDIE_MASK | LPSPI_IER_RDIE_MASK | LPSPI_IER_TEIE_MASK | LPSPI_IER_REIE_MASK);
        if(0u != u32IrqFlags)
        {
            Lpspi_Ip_TransferProcess(u8Instance);
        }
        else
        {
            /* Driver has been initialized and received an unconfigured interrupt, clear all flags */
            base->SR &= (uint32)0xFFFFFFFFu;
        }
    }
    else
    {
        /* the driver has not been initialized */
        /* clear all flags */
        base->SR &= (uint32)0xFFFFFFFFu;
    }
}

Lpspi_Ip_HwStatusType Lpspi_Ip_GetStatus(uint8 u8Instance)
{
    const Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_HwStatusType status = LPSPI_IP_UNINIT;
    
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if (u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        if (state != NULL_PTR)
        {
            status = state->status;
        }
    }
    
    return status;
}

#if (LPSPI_IP_DUAL_CLOCK_MODE == STD_ON)
Lpspi_Ip_StatusType Lpspi_Ip_SetClockMode(uint8 u8Instance, Lpspi_Ip_DualClockModeType ClockMode)
{
    Lpspi_Ip_StateStructureType* state;
    Lpspi_Ip_StatusType status = LPSPI_IP_STATUS_SUCCESS;
    
    #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
    if(u8Instance >= LPSPI_INSTANCE_COUNT)
    {
        DevAssert(0);
        status = LPSPI_IP_STATUS_FAIL;
    }
    else
    #endif
    {
        state = Lpspi_Ip_StateStructureArray[u8Instance];
        #if (LPSPI_IP_DEV_ERROR_DETECT == STD_ON)
        if (state == NULL_PTR)
        {
            DevAssert(0);
            status = LPSPI_IP_STATUS_FAIL;
        }
        else
        #endif
        {
            /* Clock mode can be changed when no transfers are in progress. */
            if (state->status != LPSPI_IP_BUSY)
            {
                state->ClockMode = ClockMode;
            }
            else
            {
                status = LPSPI_IP_STATUS_FAIL;
            }
        }
    }
    
    return status;
}
#endif

#define SPI_STOP_SEC_CODE
#include "Spi_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
