/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : PORT_CI
*   Dependencies         : none
*
*   Autosar Version      : 4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 1.0.0
*   Build Version        : S32K1_RTD_1_0_0_HF01_D2109_ASR_REL_4_4_REV_0000_20210907
*
*   (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.
==================================================================================================*/

/**
*   @file    Port_Ci_Port_Ip.c
*
*   @addtogroup Port_IPL
*   @{
*/


#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 "Port_Ci_Port_Ip.h"
#ifdef PORT_ENABLE_USER_MODE_SUPPORT
   #define USER_MODE_REG_PROT_ENABLED   (PORT_ENABLE_USER_MODE_SUPPORT)
   #include "RegLockMacros.h"
   #include "OsIf_Internal.h"
#endif
#include "SchM_Port.h"

/*=================================================================================================
                               SOURCE FILE VERSION INFORMATION
==================================================================================================*/
/**
* @brief        Parameters that shall be published within the Port driver header file and also in the
*               module description file
* @details      The integration of incompatible files shall be avoided.
*
*/
#define PORT_CI_PORT_IP_VENDOR_ID_C                    43
#define PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_C     4
#define PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_C     4
#define PORT_CI_PORT_IP_AR_RELEASE_REVISION_VERSION_C  0
#define PORT_CI_PORT_IP_SW_MAJOR_VERSION_C             1
#define PORT_CI_PORT_IP_SW_MINOR_VERSION_C             0
#define PORT_CI_PORT_IP_SW_PATCH_VERSION_C             0

/*=================================================================================================
*                                      FILE VERSION CHECKS
=================================================================================================*/
/* Check if the files Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h are of the same vendor */
#if (PORT_CI_PORT_IP_VENDOR_ID_C != PORT_CI_PORT_IP_VENDOR_ID_H)
    #error "Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h have different vendor ids"
#endif
/* Check if the files Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h are of the same Autosar version */
#if ((PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_C    != PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_H)  || \
     (PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_C    != PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_H)  || \
     (PORT_CI_PORT_IP_AR_RELEASE_REVISION_VERSION_C != PORT_CI_PORT_IP_AR_RELEASE_REVISION_VERSION_H)  \
    )
    #error "AutoSar Version Numbers of Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h are different"
#endif
/* Check if the files Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h are of the same software version */
#if ((PORT_CI_PORT_IP_SW_MAJOR_VERSION_C != PORT_CI_PORT_IP_SW_MAJOR_VERSION_H) || \
     (PORT_CI_PORT_IP_SW_MINOR_VERSION_C != PORT_CI_PORT_IP_SW_MINOR_VERSION_H) || \
     (PORT_CI_PORT_IP_SW_PATCH_VERSION_C != PORT_CI_PORT_IP_SW_PATCH_VERSION_H)    \
    )
    #error "Software Version Numbers of Port_Ci_Port_Ip.c and Port_Ci_Port_Ip.h are different"
#endif

#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
    #ifdef PORT_ENABLE_USER_MODE_SUPPORT
        /* Check if the files Port_Ci_Port_Ip.c and RegLockMacros.h are of the same version */
        #if ((PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_C != REGLOCKMACROS_AR_RELEASE_MAJOR_VERSION) || \
            (PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_C  != REGLOCKMACROS_AR_RELEASE_MINOR_VERSION)   \
            )
            #error "AutoSar Version Numbers of Port_Ci_Port_Ip.c and RegLockMacros.h are different"
        #endif

        /* Check if the files Port_Ci_Port_Ip.c and OsIf_Internal.h are of the same version */
        #if ((PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_C != OSIF_INTERNAL_AR_RELEASE_MAJOR_VERSION) || \
            (PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_C  != OSIF_INTERNAL_AR_RELEASE_MINOR_VERSION)   \
            )
            #error "AutoSar Version Numbers of Port_Ci_Port_Ip.c and OsIf_Internal.h are different"
        #endif
    #endif
    /* Check if the files Port_Ci_Port_Ip.c and SchM_Port.h are of the same version */
    #if ((PORT_CI_PORT_IP_AR_RELEASE_MAJOR_VERSION_C != SCHM_PORT_AR_RELEASE_MAJOR_VERSION) || \
        (PORT_CI_PORT_IP_AR_RELEASE_MINOR_VERSION_C  != SCHM_PORT_AR_RELEASE_MINOR_VERSION)   \
        )
        #error "AutoSar Version Numbers of Port_Ci_Port_Ip.c and SchM_Port.h are different"
    #endif
#endif
/*=================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
=================================================================================================*/

/*=================================================================================================
*                                       LOCAL MACROS
=================================================================================================*/

/*=================================================================================================
*                                      LOCAL CONSTANTS
=================================================================================================*/

/*=================================================================================================
*                                      LOCAL VARIABLES
=================================================================================================*/

/*=================================================================================================
*                                      GLOBAL CONSTANTS
=================================================================================================*/

/*=================================================================================================
                                       GLOBAL VARIABLES
=================================================================================================*/
#define PORT_START_SEC_CONST_32
#include "Port_MemMap.h"

/**
* @brief Base address array for PORT instances
*/
PORT_Type * Port_au32PortCiPortBaseAddr[5] = IP_PORT_BASE_PTRS;

/**
* @brief Base address array for GPIO instances
*/
GPIO_Type * Port_au32PortCiGpioBaseAddr[5] = IP_GPIO_BASE_PTRS;

#define PORT_STOP_SEC_CONST_32
#include "Port_MemMap.h"
/*=================================================================================================
*                                   LOCAL FUNCTION PROTOTYPES
=================================================================================================*/
#define PORT_START_SEC_CODE
#include "Port_MemMap.h"
/*!
 * @brief Initializes the pins with the given configuration structure
 *
 * This function configures the pins with the options provided in the
 * given structure.
 *
 * @param[in] pinNumber the number of configured pins in structure
 * @param[in] config the configuration structure
  */
static void Port_Ci_Port_Ip_PinInit(const Port_Ci_Port_Ip_PinSettingsConfig * config);

/*==================================================================================================
*                                         LOCAL FUNCTIONS
==================================================================================================*/
/*FUNCTION**********************************************************************
 *
 * Function Name : PINS_Init
 * Description   : This function configures the pin feature with the options
 * provided in the given structure.
 *
 ******************************************************************************/
static void Port_Ci_Port_Ip_PinInit(const Port_Ci_Port_Ip_PinSettingsConfig * config)
{
    uint32 pinsValues = 0U;
    uint32 digitalFilters;

    PORT_CI_PORT_DEV_ASSERT((boolean)(config != NULL_PTR));
    PORT_CI_PORT_DEV_ASSERT((boolean)(config->pinPortIdx < 32));
    PORT_CI_PORT_DEV_ASSERT((boolean)((config->portBase->PCR[config->pinPortIdx]) & PORT_PCR_LK_MASK) == 0);

    if (config->pullConfig != PORT_INTERNAL_PULL_NOT_ENABLED)
    {
        pinsValues |= PORT_PCR_PE(1);
        pinsValues |= PORT_PCR_PS(config->pullConfig);
    }
#ifdef FEATURE_PORT_CI_PORT_IP_HAS_DRIVE_STRENGTH
    pinsValues |= PORT_PCR_DSE(config->driveStrength);
#endif /* FEATURE_PORT_CI_PORT_IP_HAS_DRIVE_STRENGTH */
#ifdef FEATURE_PORT_CI_PORT_IP_HAS_LOCK_REGISTER
    pinsValues |= PORT_PCR_LK(config->lockRegister);
#endif /* FEATURE_PORT_CI_PORT_IP_HAS_LOCK_REGISTER */
    pinsValues |= PORT_PCR_PFE(config->passiveFilter?1U:0U);
    pinsValues |= PORT_PCR_MUX(config->mux);

    /* Enter critical region */
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_01();

    /* Read current digital filter of port */
    digitalFilters = (uint32)(config->portBase->DFER);
    digitalFilters &= ~(1UL << (config->pinPortIdx));
    digitalFilters |= (((uint32)(config->digitalFilter?1U:0U)) << (config->pinPortIdx));
    /* Write to digital filter enable register */
    config->portBase->DFER = digitalFilters;

    /* Configure initial value for GPIO pin in GPIO mux */
    if (PORT_MUX_AS_GPIO == config->mux)
    {
        /* Check if the direction of the pin is OUTPUT. In this case the driver needs to set the output level too */
        if (PORT_CI_PORT_PIN_OUT == config->direction)
        {
            if ((uint8)1 == config->initValue)
            {
                config->gpioBase->PSOR |= ((uint32)1 << (config->pinPortIdx));
            }
            else if ((uint8)0 == config->initValue)
            {
                config->gpioBase->PCOR |= ((uint32)1 << (config->pinPortIdx));
            }
            else
            {
                /* No action to be done */
            }
            /* Set the pin direction as output in the PDDR register of GPIO IP */
            config->gpioBase->PDDR |= (uint32)1 << (config->pinPortIdx);
        }
        /* The direction of pin is INPUT or HIGH Z */
        else
        {
            /* Clear the pin direction as input in the PDDR register of GPIO IP */
            config->gpioBase->PDDR &= ~((uint32)1 << (config->pinPortIdx));
#ifndef FEATURE_PORT_CI_PORT_IP_S32K11X_DERIVATIVE
            /* Check if the pin is HIGH_Z. In this case the driver needs to disable port input in PIDR register of GPIO IP*/
            if (PORT_CI_PORT_PIN_HIGH_Z == config->direction)
            {
                config->gpioBase->PIDR |= ((uint32)1 << (config->pinPortIdx));
            }
#endif
        }
    }

    /* Exit critical region */
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_01();

    /* Write to Multiplexed Signal Configuration Register */
    config->portBase->PCR[config->pinPortIdx] = pinsValues;
}

/*==================================================================================================
*                                        GLOBAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_ReadPCR
 * Description   : This function supports to read value of the pin control register.
 *
 ******************************************************************************/
uint32 Port_Ci_Port_Ip_ReadPCR(const PORT_Type * base, uint32 MscrInstance)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(MscrInstance < 32));

    return base->PCR[MscrInstance];
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPCR
 * Description   : This function supports to write value of the pin control register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetPCR(PORT_Type * base, uint32 MscrInstance, uint32 value)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(MscrInstance < 32));
    PORT_CI_PORT_DEV_ASSERT((boolean)((base->PCR[MscrInstance]) & PORT_PCR_LK_MASK) == 0);

    base->PCR[MscrInstance] = value;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPSOR
 * Description   : This function supports to write value on the port set output register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetPSOR(GPIO_Type * base, uint32 Pin)
{
    base->PSOR = (Pin);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPCOR
 * Description   : This function supports to write value on the port clear output register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetPCOR(GPIO_Type * base, uint32 Pin)
{
    base->PCOR = (Pin);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPDDR
 * Description   : This function supports to set value on the port data direction register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetPDDR(GPIO_Type * base, uint32 Pin)
{
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_02();
    base->PDDR |= (Pin);
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_02();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPDDR
 * Description   : This function supports to clear value on the port data direction register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_ClearPDDR(GPIO_Type * base, uint32 Pin)
{
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_03();
    base->PDDR &= ~(Pin);
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_03();
}

#ifndef FEATURE_PORT_CI_PORT_IP_S32K11X_DERIVATIVE
/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetPIDR
 * Description   : This function supports to set value on the port input disable register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetPIDR(GPIO_Type * base, uint32 Pin)
{
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_04();
    base->PIDR |= (Pin);
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_04();
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetDFER
 * Description   : This function supports to set value on the digital filter enable register.
 *
 ******************************************************************************/
void Port_Ci_Port_Ip_SetDFER(PORT_Type * base, uint32 pinMask)
{
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_05();
    base->DFER |= pinMask;
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_05();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_Init
 * Description   : This function configures the pins with the options provided
 * in the given structure.
 *
 * @implements Port_Ci_Port_Ip_Init_Activity
 ******************************************************************************/
Port_Ci_Port_Ip_PortStatusType Port_Ci_Port_Ip_Init(uint32 pinCount,
                                       const Port_Ci_Port_Ip_PinSettingsConfig config[])
{
    uint32 i;

    for (i = 0U; i < pinCount; i++)
    {
        Port_Ci_Port_Ip_PinInit(&config[i]);
    }

    return PORT_CI_PORT_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetMuxModeSel
 * Description   : This function configures the pin muxing.
 *
 * @implements Port_Ci_Port_Ip_SetMuxModeSel_Activity
 ******************************************************************************/
void Port_Ci_Port_Ip_SetMuxModeSel(PORT_Type * const base,
                                   uint32 pin,
                                   Port_Ci_Port_Ip_PortMux mux)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(pin < PORT_PCR_COUNT));
    PORT_CI_PORT_DEV_ASSERT((boolean)((base->PCR[pin]) & PORT_PCR_LK_MASK) == 0);
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_06();
    uint32 regValue = base->PCR[pin];
    regValue &= ~(PORT_PCR_MUX_MASK);
    regValue |= PORT_PCR_MUX(mux);
    base->PCR[pin] = regValue;
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_06();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_EnableDigitalFilter
 * Description   : This function enables digital filter feature for digital pin muxing.
 *
 * @implements Port_Ci_Port_Ip_EnableDigitalFilter_Activity
 ******************************************************************************/
void Port_Ci_Port_Ip_EnableDigitalFilter(PORT_Type * const base,
                                         uint32 pin)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(pin < PORT_PCR_COUNT));
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_07();
    base->DFER |= ((uint32)1U << pin);
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_07();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_DisableDigitalFilter
 * Description   : This function disables digital filter feature for digital
 * pin muxing.
 *
 * @implements Port_Ci_Port_Ip_DisableDigitalFilter_Activity
 ******************************************************************************/
void Port_Ci_Port_Ip_DisableDigitalFilter(PORT_Type * const base,
                                          uint32 pin)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(pin < PORT_PCR_COUNT));
    SchM_Enter_Port_PORT_EXCLUSIVE_AREA_08();
    base->DFER &= ~((uint32)1U << pin);
    SchM_Exit_Port_PORT_EXCLUSIVE_AREA_08();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_ConfigDigitalFilter
 * Description   : This function configures digital filter for port with
 * given configuration.
 *
 * @implements Port_Ci_Port_Ip_ConfigDigitalFilter_Activity
 ******************************************************************************/
void Port_Ci_Port_Ip_ConfigDigitalFilter(PORT_Type * const base,
                                         const Port_Ci_Port_Ip_DigitalFilterConfigType * config)
{
    PORT_CI_PORT_DEV_ASSERT((boolean)(config->u8Width <= PORT_DFWR_FILT_MASK));
    base->DFCR = PORT_DFCR_CS(config->u8Clock);
    base->DFWR = PORT_DFWR_FILT(config->u8Width);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Port_Ci_Port_Ip_SetGlobalPinControl
 * Description   : This function quickly configures multiple pins within the one port for
 * the same peripheral function with the same pin configuration. Supports up to 16 pins with
 * the lower or upper half of pin registers at the same port.
 *
 * @implements Port_Ci_Port_Ip_SetGlobalPinControl_Activity
 ******************************************************************************/
void Port_Ci_Port_Ip_SetGlobalPinControl(PORT_Type * const base,
                                         uint16 pins,
                                         uint16 value,
                                         Port_Ci_Port_Ip_PortGlobalControlPins halfPort)
{
    uint16 mask = 0;
    mask |= PORT_PCR_PS_MASK;
    mask |= PORT_PCR_PE_MASK;
    mask |= PORT_PCR_PFE_MASK;
    mask |= PORT_PCR_DSE_MASK;
    mask |= PORT_PCR_MUX_MASK;
    mask |= PORT_PCR_LK_MASK;
    mask &= value;

    switch (halfPort)
    {
        case PORT_GLOBAL_CONTROL_LOWER_HALF_PINS:
            base->GPCLR = (((uint32)pins) << PORT_GPCLR_GPWE_SHIFT) | (uint32)mask;
            break;
        case PORT_GLOBAL_CONTROL_UPPER_HALF_PINS:
            base->GPCHR = (((uint32)pins) << PORT_GPCLR_GPWE_SHIFT) | (uint32)mask;
            break;
        default:
            /* nothing to configure */
            PORT_CI_PORT_DEV_ASSERT((boolean)FALSE);
            break;
    }
}

#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
