/*
 * Copyright 2018 NXP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * File: msdi_s32k1xx.c
 *
 * This file implements external functions required by MSDI SW driver.
 * It is closely related to this demo example.
 */

/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "Mcal.h"
#include "Siul2_Dio_Ip.h"
//#include "Adc_Sar_Ip.h"
#include "Lpspi_Ip.h"
#include <CD1030_Drv/msdi.h>
#include <CD1030_Drv/msdi_s32k3.h>
//#include "Lpspi_Ip.h"
//#include "Lpspi_Ip_BOARD_InitPeripherals_PBcfg.h"
//#include "osif/osif.h"

#define Lpspi_Ip_DeviceAttributes_SPI0_MSDI_BOARD_InitPeripherals (Lpspi_Ip_DeviceAttributes_SPI0_PCS2_CD1030_Instance_0_BOARD_InitPeripherals)

/*******************************************************************************
 * Global variables
 ******************************************************************************/
msdi_drv_config_t drvConfigCD1030;

/*******************************************************************************
 * Code
 ******************************************************************************/

/*FUNCTION**********************************************************************
 *
 * Function Name : BCC_ConfigureLPSPI
 * Description   : This function configures LPSPI for usage with BCC driver.
 *
 *END**************************************************************************/
uint8_t MSDI_ConfigureLPSPI(void)
{
#if 0
    lpspi_master_config_t msdiSpiSdkConfig;
    status_t status = STATUS_SUCCESS;

    /* Initialize LPSPI periphery. */
	if (MSDI_LPSPI_BAUD > MSDI_SPI_FREQ_MAX)
	{
		return STATUS_UNSUPPORTED;
	}

	msdiSpiSdkConfig.bitcount = 32U;
	msdiSpiSdkConfig.bitsPerSec = MSDI_LPSPI_BAUD;
	msdiSpiSdkConfig.callback = NULL;
	msdiSpiSdkConfig.callbackParam = NULL;
	msdiSpiSdkConfig.clkPhase = LPSPI_CLOCK_PHASE_1ST_EDGE;
	msdiSpiSdkConfig.clkPolarity = LPSPI_SCK_ACTIVE_HIGH;
	msdiSpiSdkConfig.pcsPolarity = LPSPI_ACTIVE_LOW;
	msdiSpiSdkConfig.isPcsContinuous = true;
	msdiSpiSdkConfig.lpspiSrcClk = MSDI_LPSPI_SRCCLK;
	msdiSpiSdkConfig.lsbFirst = false;
	msdiSpiSdkConfig.transferType = LPSPI_USING_INTERRUPTS;
	msdiSpiSdkConfig.whichPcs = LPSPI_PCS0; /* HW PCS is not used. */

    status = LPSPI_DRV_MasterInit(MSDI_LPSPI_INSTANCE,
                &(g_lpspiState[MSDI_LPSPI_INSTANCE]), &msdiSpiSdkConfig);
    if (status != STATUS_SUCCESS)
    {
        return status;
    }

    /* Initialize CSB_M pin. */
    PINS_DRV_SetPinDirection(MSDI_CSB_INSTANCE, MSDI_CSB_PIN, 1);
    PINS_DRV_SetPins(MSDI_CSB_INSTANCE, 1U << MSDI_CSB_PIN);
#endif
    return E_OK;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : MSDI_TransferSpi
 * Description   : This function performs one 32b LPSPI transfer to MSDI device.
 *
 *END**************************************************************************/
msdi_status_t MSDI_TransferSpi(uint8_t drvInstance, const uint32_t sendData, uint32_t* const rcvData)
{
#ifdef USE_TWO_FRAMES_FORMAT_FOR_MSDI
    uint16_t sendBuffer[2];
    uint16_t rcvBuffer[2];
    uint32_t tmpStatus;

    DEV_ASSERT(rcvData != NULL);

    /* Fill in the send buffer. */
    sendBuffer[1] = (uint16_t)(sendData & 0xFFFFU);
    sendBuffer[0] = (uint16_t)((sendData >> 16) & 0xFFFFU);

    tmpStatus = Lpspi_Ip_SyncTransmit(MSDI_SPI_INST, \
  		  &Lpspi_Ip_DeviceAttributes_BOARD_InitPeripherals[MSDI_SPI_CS_ID], \
		  sendBuffer, rcvBuffer, (uint16_t)2, 1000U);

	*rcvData = ((uint32_t)rcvBuffer[1]) | (((uint32_t)rcvBuffer[0]) << 16U);

    return MSDI_STATUS_SUCCESS;
#else
    Std_ReturnType tmpStatus;

    DEV_ASSERT(rcvData != NULL);

    //while(Lpspi_Ip_GetStatus(MSDI_SPI_INST) == LPSPI_IP_BUSY) {}
    while(Lpspi_Ip_GetStatus(drvInstance) == LPSPI_IP_BUSY) {}
   	tmpStatus = Lpspi_Ip_SyncTransmit(&Lpspi_Ip_DeviceAttributes_SPI0_MSDI_BOARD_InitPeripherals, (uint8_t *)&sendData, (uint8_t *)rcvData, (uint16_t)4, 1000U);

	if(tmpStatus==E_OK)
		return MSDI_STATUS_SUCCESS;
	else
		return MSDI_STATUS_COMM_ERROR;
#endif
}

/*FUNCTION**********************************************************************
 *
 * Function Name : MSDI_Assert
 * Description   : User implementation of assert.
 *
 *END**************************************************************************/
void MSDI_Assert(bool x)
{
    DEV_ASSERT(x);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : MSDI_WaitMs
 * Description   : Waits for specified amount of milliseconds.
 *
 *END**************************************************************************/
void MSDI_WaitMs(uint16_t delay)
{
	OsIf_Delay_Ms(delay);
}


/*!
 * @brief Initializes CD1020 initConfig structure for usage with this example.
 * (1) Configures all SP pins as Switch to Battery.
 * (2) Configures all pins as non-tri-state.
 * (3) Sets SG0 as AMUX output.
 */
msdi_status_t initCD1030(msdi_drv_config_t *drvConfig)
{
    msdi_init_config_t initCfg;
    msdi_status_t status = MSDI_STATUS_SUCCESS;
    //msdi_amux_cfg_t amuxCfg = { MSDI_AMUX_ASETT0_HIZ, MSDI_AMUX_ASEL_CD1030_SG0 };
    msdi_amux_cfg_t amuxCfg = { MSDI_AMUX_ASETT0_HIZ, MSDI_AMUX_ASEL_CD1030_NO_INPUT };

    /* Fill in the MSDI driver configuration structure. */
    drvConfig->drvInstance = 0;
    drvConfig->deviceType = MSDI_DEVICE_CD1030;

    /* Get default CD1020 register values. */
    MSDI_GetDefaultInitConfig(drvConfig, &initCfg);

    /* Configure all pins as non-tri-state. */
    initCfg.triStateSg =
            MSDI_TRI_STATE_DIS(0) |
            MSDI_TRI_STATE_DIS(1) |
            MSDI_TRI_STATE_DIS(2) |
            MSDI_TRI_STATE_DIS(3) |
            MSDI_TRI_STATE_DIS(4) |
            MSDI_TRI_STATE_DIS(5) |
            MSDI_TRI_STATE_DIS(6) |
            MSDI_TRI_STATE_DIS(7) |
            MSDI_TRI_STATE_DIS(8) |
            MSDI_TRI_STATE_DIS(9) |
            MSDI_TRI_STATE_DIS(10) |
            MSDI_TRI_STATE_DIS(11) |
            MSDI_TRI_STATE_DIS(12) |
            MSDI_TRI_STATE_DIS(13);

    initCfg.triStateSp =
            MSDI_TRI_STATE_DIS(0) |
            MSDI_TRI_STATE_DIS(1) |
            MSDI_TRI_STATE_DIS(2) |
            MSDI_TRI_STATE_DIS(3) |
            MSDI_TRI_STATE_DIS(4) |
            MSDI_TRI_STATE_DIS(5) |
            MSDI_TRI_STATE_DIS(6) |
            MSDI_TRI_STATE_DIS(7) |
            MSDI_TRI_STATE_DIS(8);

    /* Configure all SP pins as Switch to Battery. */
    initCfg.devConfig.spx =
            MSDI_CFG_SPX_BAT(0) |
            MSDI_CFG_SPX_BAT(1) |
            MSDI_CFG_SPX_BAT(2) |
            MSDI_CFG_SPX_BAT(3) |
            MSDI_CFG_SPX_BAT(4) |
            MSDI_CFG_SPX_BAT(5) |
            MSDI_CFG_SPX_BAT(6) |
            MSDI_CFG_SPX_BAT(7);

    /* Exit LPM. Just in case that CD1020 is already in LPM. */
    MSDI_ExitLPM(drvConfig);

    /* Initialize CD1020 registers. */
    status |= MSDI_Init(drvConfig, &initCfg);

    /* Sets SG0 as AMUX input. */
    status |= MSDI_SetAMUXChannel(drvConfig, &amuxCfg);

    return status;
}

/***************************************************
 * Injected an ADC sampling on PTE11_ADC0_P6, to get MSDI AMUX value
 ****************************************************/
msdi_status_t MSDI_ReadAmuxValue(uint32_t adcInst, uint32_t adcChanIdx, uint16_t *pData){
	uint16_t tmpData;
	//wait if the ADC Injected conversion is occupied by other tasks
	while((Adc_Sar_Ip_GetStatusFlags(adcInst)&ADC_SAR_IP_STATUS_FLAG_INJECTED_STARTED) != 0);
	Adc_Sar_Ip_EnableChannel(adcInst, ADC_SAR_IP_CONV_CHAIN_INJECTED, adcChanIdx);
	Adc_Sar_Ip_StartConversion(adcInst, ADC_SAR_IP_CONV_CHAIN_INJECTED);
	//wait till injected conversion is completed, read result
	for(uint32_t cnt=0; cnt<1000; cnt++){
		tmpData = Adc_Sar_Ip_GetConvData(adcInst, adcChanIdx);
		if(tmpData>0)
			break;
	}
	*pData = tmpData;
	Adc_Sar_Ip_DisableChannel(adcInst, ADC_SAR_IP_CONV_CHAIN_INJECTED, adcChanIdx);
	if(tmpData>0)
		return MSDI_STATUS_SUCCESS;
	else
		return MSDI_STATUS_PARAM_RANGE;
}
/*******************************************************************************
 * EOF
 ******************************************************************************/
