/* ======================================================================
 *   Copyright (c) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *  \file     Port_Platform.c
 *
 */
#define PORT_PLATFORM_SOURCE (1)

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include "Std_Types.h"
#include "Port.h"
#include "Port_priv.h"
#define PORT_START_SEC_CODE
#include "Port_MemMap.h"
#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                         Structure Declarations                             */
/* ========================================================================== */
#define PORT_START_SEC_CONST_UNSPECIFIED
#include "Port_MemMap.h"
static const uint32 Port_GPIOPortAddr[5] =
{
    SOC_GPIO_PORTAB_BASE,      
    SOC_GPIO_PORTCD_BASE,    
    SOC_GPIO_PORTEF_BASE,   
    SOC_GPIO_PORTGH_BASE,  
    SOC_GPIO_PORTI_BASE,  
   
};

#define PORT_STOP_SEC_CONST_UNSPECIFIED
#include "Port_MemMap.h"

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

#define PORT_START_SEC_CODE
#include "Port_MemMap.h"


/** @fn void Port_UnlockPadConfig(pinMuxBase_t *pinMuxRegp)
*   @brief Configure the key to enable the pinmuxing.
*
*/
/* SourceId :  */
/* DesignId :  */
/* Requirements :  */

void Port_UnlockPadConfig(pinMuxBase_t *pinMuxRegp)
{
    /* Enable Pin Muxing */
      /* Value of pinMuxRegp can be pinMuxReg */
    pinMuxRegp->IOCFGKICK0 = PORT_UNLOCKPAD_IOCFGKICK0;
    pinMuxRegp->IOCFGKICK1 = PORT_UNLOCKPAD_IOCFGKICK1;

}

/** @fn void Port_LockPadConfig(pinMuxBase_t *pinMuxRegp)
*   @brief Lock to disable the pinmuxing.
*
*/
/* SourceId :  */
/* DesignId :  */
/* Requirements :  */

void Port_LockPadConfig(pinMuxBase_t *pinMuxRegp)
{

     /* Disable Pin Muxing */
    /* Value of pinMuxRegp can be pinMuxReg */
    pinMuxRegp->IOCFGKICK1 = PORT_LOCKPADVALUE;
    pinMuxRegp->IOCFGKICK0 = PORT_LOCKPADVALUE;
}

uint32  Port_GetGPIOPortAddr(uint32 regNum)
{
    uint32 retVal;

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    if (regNum >= PORT_UTILS_ARRAYSIZE(Port_GPIOPortAddr))
    {
        retVal = PORT_DIO_INVALID_BASE_ADDR;
    }
    else
#endif
    {
        retVal = Port_GPIOPortAddr[regNum];
    }

    return (retVal);
}

void Port_GPIOPortInit(const gpioPORT_t  *portAddr)
{
	uint32  regVal = 0U;
	uint32  regVal_1 = PORT_CLEAR_EDGE;
	/** - Port direction */
	(void)regWriteReadback(&portAddr->DIR, M_THIRTY_ONE, M_ZERO, regVal);

    /** - Port output values */                    
	(void)regWriteReadback(&portAddr->DOUT, M_THIRTY_ONE, M_ZERO, regVal);
		
	(void)regWriteReadback(&portAddr->CLR_RIS_TRIG, M_THIRTY_ONE, M_ZERO, regVal_1);
		
	(void)regWriteReadback(&portAddr->CLR_FAL_TRIG, M_THIRTY_ONE, M_ZERO, regVal_1);

}

void Port_GPIOInit(gpioBASE_t *gioBaseREG)
{
      
    uint32  regVal = 0U;
    /** bring GPIO module Bank interrupt disabled */
    (void)regWriteReadback(&gioBaseREG->BINTEN, M_THIRTY_ONE, M_ZERO, regVal);

}

void Port_GPIOEdgTrigConfigure(const gpioPORT_t  *portAddr,uint32 bit,
                              Port_EdgeTrig  TriEdge,
                              boolean TriggerEn)
{
    uint32  regVal = 0U;
	
	if(TriggerEn == TRUE)
	{
		
		if(TriEdge == PORT_RISING_EDGE)
		{
			/* Only enable Rising edge detection*/
			regVal = M_REG_READ32(&portAddr->SET_RIS_TRIG);
			
			regVal |= (uint32) 1U<<bit;

			M_REG_WRITE32(&portAddr->SET_RIS_TRIG,regVal);

            regVal = M_REG_READ32(&portAddr->CLR_FAL_TRIG);

            regVal |= (uint32) 1U<<bit;

            M_REG_WRITE32(&portAddr->CLR_FAL_TRIG,regVal);

		}
		
		
 		else if(TriEdge == PORT_FALLING_EDGE)
		{
			/* Only enable Rising edge detection*/
            regVal = M_REG_READ32(&portAddr->SET_FAL_TRIG);

            regVal |= (uint32) 1U<<bit;

            M_REG_WRITE32(&portAddr->SET_FAL_TRIG,regVal);

            regVal = M_REG_READ32(&portAddr->CLR_RIS_TRIG);

            regVal |= (uint32) 1U<<bit;

            M_REG_WRITE32(&portAddr->CLR_RIS_TRIG,regVal);

		}
		else
		{
			/* Enable both rising and falling edge*/
            regVal = M_REG_READ32(&portAddr->SET_FAL_TRIG);

            regVal |= (uint32) 1U<<bit;

            M_REG_WRITE32(&portAddr->SET_FAL_TRIG,regVal);

            regVal = M_REG_READ32(&portAddr->SET_RIS_TRIG);

            regVal |= (uint32) 1U<<bit;

            M_REG_WRITE32(&portAddr->SET_RIS_TRIG,regVal);
			
		}
	}
	else
	{
        regVal = M_REG_READ32(&portAddr->CLR_FAL_TRIG);

        regVal |= (uint32) 1U<<bit;

        M_REG_WRITE32(&portAddr->CLR_FAL_TRIG,regVal);

        regVal = M_REG_READ32(&portAddr->CLR_RIS_TRIG);

        regVal |= (uint32) 1U<<bit;

        M_REG_WRITE32(&portAddr->CLR_RIS_TRIG,regVal);
	}
	
}

void Port_GPIOIntConfigure(gpioBASE_t *gioBaseREG,
										   const Port_IntrSettingType* gpioIntr)
{
    uint32  regVal = 0U;
	
	regVal=gpioIntr->gpioIntBank;
	
	(void)regWriteReadback(&gioBaseREG->BINTEN, M_THIRTY_ONE, M_ZERO, regVal);



}


/** @fn sint32 Port_ConfigOverrideCtrl(uint32 pinMuxBase, uint32 pin, uint32 outputCtrl, uint32 inputCtrl)
*   @brief Configurations for the input and output override control.
*
*    @param[in] pin: Pin number to be configured
*    @param[in] outputCtrl: Output control selection
*               The parameter \e outputCtrl can be one of the following values:
*                - \b OUTPUT_EN
*                - \b OUTPUT_DIS
*                - \b OUTEN_RETAIN_HW_CTRL
*    @param[in] inputCtrl: Input control selection
*               The parameter \e inputCtrl can be one of the following values:
*                - \b INPUT_EN
*                - \b INPUT_DIS
*                - \b INPEN_RETAIN_HW_CTRL
*
*    @return Value < 0 - in case of error
*            Value = 0 - success
*/
/* SourceId :  */
/* DesignId :  */
/* Requirements :  */
sint32 Port_ConfigOverrideCtrl(uint32 *pinMuxBase, uint32 pin, uint32 outputCtrl, 
															   uint32 inputCtrl)
{
    sint32 retVal = 0;

    /* Setup the output control of the pin */
    if (OUTEN_RETAIN_HW_CTRL != outputCtrl)
    {
        pinMuxBase[(pin / 4U)] &= PIN_OUTEN_MASK;

        (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]), M_SEVEN, M_SEVEN, outputCtrl);

    }
    else    /* OUTEN_RETAIN_HW_CTRL */
    {

        pinMuxBase[(pin / 4U)] &= PIN_OUTEN_OVRRIDE_MASK;
        pinMuxBase[(pin / 4U)] |= OUTEN_OVRRIDE_EN;
	
    }

    /* Setup the input control of the pin */
    if (INPEN_RETAIN_HW_CTRL != inputCtrl)
    {

        (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]), M_FIVE, M_FIVE, inputCtrl);

    }
    /* INPEN_RETAIN_HW_CTRL */
    else
    {

        pinMuxBase[(pin / 4U)] |= INPEN_OVRRIDE_EN;
    }
    return retVal;
}

/** @fn sint32 Port_SelectFunc(uint32 *pinMuxBase, uint32 pin, uint32 func)
*   @brief Setup the pin personality.
*
*   This function sets up the functional personality of the pin.
*   The specified signal will be brought out on the pin.
*   As there is no strict check on the parameters passed, the values passed
*   must be from the macro specified in the header pinmux.h.
*
*    @param[in] pin: Pin number to be configured
*    @param[in] func: Desired signal functionality to be muxed onto the pin
*/
/* SourceId :  */
/* DesignId :  */
/* Requirements :  */
sint32 Port_SelectFunc(uint32 *pinMuxBase, uint32 pin, uint32 func)
{
    sint32 retVal = 0;
    uint32  muxmode_val;
    uint32  pin_reg_addr;
	uint32  baseAdd = SOC_IOMUX_REG_BASE;

    pinMuxBase[(pin / 4U)] &= PIN_FUNCTION_SEL_MASK;

    pinMuxBase[(pin / 4U)] |= (func & ~PIN_FUNCTION_SEL_MASK);
    return retVal;
}


/** @fn sint32 Port_ConfigPulls(uint32 *pinMuxBase,uint32 pin, uint32 pullVal)
*   @brief Configurations for the pulls on the pins.
*
*    @param[in] pin: Pin number to be configured
*    @param[in] pullVal: Pull selection
*               The parameter \e pullVal can be one of the following values:
*                - \b PULLUP_EN
*                - \b PULLDOWN_EN
*
*    @return Value < 0 - in case of error
*            Value = 0 - success
*/
sint32 Port_ConfigPulls(uint32 *pinMuxBase, uint32 pin, uint32 pullVal)
{
    sint32 retVal = 0;

    /* Setup the configured pull control of the pin */

    pinMuxBase[(pin / 4U)] &= PIN_PULL_SELECT_MASK;

    (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]), M_NINE, M_NINE, pullVal);
    return retVal;
}

/** @fn sint32 Port_ConfigSlew(uint32 *pinMuxBase, uint32 pin, uint32 slewVal)
*   @brief Configurations for the slew on the pins.
*
*    @param[in] pin: Pin number to be configured
*    @param[in] slewVal: Slew selection
*               The parameter \e slewVal can be one of the following values:
*                - \b SLEW_LOW
*                - \b SLEW_HIGH
*
*    @return Value < 0 - in case of error
*            Value = 0 - success
*/
sint32 Port_ConfigSlew(uint32 *pinMuxBase, uint32 pin, uint32 slewVal)
{
    sint32 retVal = 0;

    /* Setup the configured slew of the pin */

    pinMuxBase[(pin / 4U)] &= PIN_SLEW_CONTROL_MASK;

    (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]), M_TEN, M_TEN, slewVal);
    return retVal;
}

/** @fn sint32 Port_ConfigPullInhibitEnable(uint32 *pinMuxBase, uint32 pin, 
*                                            uint32 pullInhibitEnableVal)
*   @brief Configurations for the pullInhibit on the pins.
*
*    @param[in] pin: Pin number to be configured
*    @param[in] slewVal: PIN_PULL_INHIBIT  selection
*               The parameter \e PIN_PULL_INHIBIT can be one of the following values:
*                - \b PIN_PULL_INHIBIT_DISABLE
*                - \b PIN_PULL_INHIBIT_ENABLE
*
*    @return Value < 0 - in case of error
*            Value = 0 - success
*/
sint32 Port_ConfigPullInhibitEnable(uint32 *pinMuxBase, uint32 pin, uint32 InhibitVal)
{
    sint32 retVal = 0;
       /* Setup the configured pullInhibitEnable of the pin */
    pinMuxBase[(pin / 4U)] &= PIN_PULL_INHIBIT_MASK;
    
    (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]), M_EIGHT, M_EIGHT, InhibitVal);
    return retVal;
}

sint32 Port_resetPadConfig(uint32 *pinMuxBase, uint32 pin)
{
     sint32 retVal = 0;
     /*Reset the value */
     uint32_t regVal = 0x000005F0U; 
    
    (void)regWriteReadback(&(pinMuxBase[(pin / 4U)]),  M_THIRTY_ONE, M_ZERO, regVal);    
    return retVal;

}

/*
 * \brief       Function to program the pad properties
 *
 *
 * \param[in]   baseAdd - Base address of pad config register
 * \param[in]       padConfig - property of the pad to be configured.
 *
 * \return           error status.If error has occured it returns a non zero
 *                   value.
 *                   If no error has occured then return status will be zero. .
 *
 */

void Port_ConfigurePadCore(uint32 baseAdd,
    CONSTP2CONST(Port_PadRegSettingType, AUTO, PORT_APPL_DATA)padRegSetting)
{

    Port_UnlockPadConfig(((pinMuxBase_t*)baseAdd));

    Port_resetPadConfig((uint32 *)baseAdd, padRegSetting->pin_reg_offset);

    (void)Port_ConfigOverrideCtrl((uint32 *)baseAdd, padRegSetting->pin_reg_offset, 
		padRegSetting->oe_n_override_ctrl, padRegSetting->ie_n_override_ctrl );


    if ( padRegSetting->muxmode != PORT_PAD_REGSETTING_DEFAULT )
    {

        (void)Port_SelectFunc((uint32 *)baseAdd, padRegSetting->pin_reg_offset, 
														padRegSetting->muxmode);
    }
    if ( padRegSetting->pullinhibit != PORT_PAD_REGSETTING_DEFAULT )
    {

        (void)Port_ConfigPullInhibitEnable((uint32 *)baseAdd, padRegSetting->pin_reg_offset, 
													padRegSetting->pullinhibit);
    }    
    if ( padRegSetting->pulludenable != PORT_PAD_REGSETTING_DEFAULT )
    {

        (void)Port_ConfigPulls((uint32 *)baseAdd, padRegSetting->pin_reg_offset, 
												   padRegSetting->pulludenable);
    }

    if ( padRegSetting->slewcontrol != PORT_PAD_REGSETTING_DEFAULT )
    {

        (void)Port_ConfigSlew((uint32 *)baseAdd, padRegSetting->pin_reg_offset, 
													padRegSetting->slewcontrol);
    }

    Port_LockPadConfig(((pinMuxBase_t*)baseAdd));

}

uint32 Port_ReadMuxMode(uint32 pin_reg_offset)
{
    uint32  muxmode_val;
    uint32  pin_reg_addr;
    uint32  baseAdd = SOC_IOMUX_REG_BASE;
 
    Port_UnlockPadConfig((pinMuxBase_t * )baseAdd);

    pin_reg_addr = baseAdd + pin_reg_offset;

    muxmode_val  = M_REG_READ32(pin_reg_addr);

    Port_LockPadConfig((pinMuxBase_t * )baseAdd);

    /*Get the function select [3:0] from the register value*/
    muxmode_val = (uint32)((uint32)muxmode_val & 0xFU);

    return muxmode_val;
}

/** @fn void Port_GPIOSetBit(gioPORT_t *port, uint32 bit, uint32 value)
*   @brief Write Bit
*   @param[in] port pointer to GIO port:
*              - gioPORTA: PortA pointer
*              - gioPORTB: PortB pointer
*              - gioPORTC: PortC pointer
*              - gioPORTD: PortD pointer
*   @param[in] bit number 0-7 that specifies the bit to be written to.
*              - 0: LSB
*              - 7: MSB
*   @param[in] value binary value to write to bit
*
*   Writes a value to the specified pin of the given GIO port
*/
/* SourceId :  */
/* DesignId :  */
/* Requirements :  */
void Port_GPIOSetBit(gpioPORT_t *port, uint32 bit, uint32 value)
{

    if (value != 0U)
    {
        port->DSET = (uint32)1U << bit;
    }
    else
    {
        port->DCLR = (uint32)1U << bit;
    }

}

/** @fn void Port_SetPinDirection(gioPORT_t *port, uint32 dir)
*   @brief Set Port Direction
*   @param[in] port pointer to GIO port:
*              - gioPORTA: PortA pointer
*              - gioPORTB: PortB pointer
*              - gioPORTC: PortC pointer
*              - gioPORTD: PortD pointer
*   @param[in] dir value to write to DIR register
*
*   Set the direction of GIO pins at runtime.
*/

void Port_SetDirection(const gpioPORT_t *port, uint32 bit, uint32 dir)
{

    uint32 pinMask = (uint32) 1U << bit ;
    uint32 oeRegVal = 0U;

    oeRegVal = M_REG_READ32(&port->DIR);

    if (dir != 0U)
    {
        oeRegVal |=  pinMask;
        (void)regWriteReadback(&port->DIR, M_THIRTY_ONE, M_ZERO, oeRegVal);

    }
    else
    {
        oeRegVal &= ~ pinMask;
        (void)regWriteReadback(&port->DIR, M_THIRTY_ONE, M_ZERO, oeRegVal);

    }

}

#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"

