/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : 
*   Dependencies         : none
*
*   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.
==================================================================================================*/
/**
*   @file       Clock_Ip.c
*   @version    0.9.0
*
*   @brief   CLOCK driver implementations.
*   @details CLOCK driver implementations.
*
*   @addtogroup CLOCK_DRIVER Clock Ip Driver
*   @{
*/

/**
* @page misra_violations MISRA-C:2012 violations
*
* @section Clock_Ip_c_REF_1
* Violates MISRA 2012 Advisory Rule 20.1, #include directives should only be preceded by preprocessor
* directives or comments. AUTOSAR imposes the specification of the sections in which certain parts
* of the driver must be placed.
*
* @section Clock_Ip_c_REF_2
* Violates MISRA 2012 Advisory Rule 4.8, This file includes the definition
* of types but does not use it. Header is common for all files
*
* @section Clock_Ip_c_REF_3
* Violates MISRA 2012 Advisory Directive 4.9, A function should be used in preference to a function-like macro where they are interchangeable.
* Function like macro are used to reduce code complexity
*
* @section Clock_Ip_c_REF_4
* Violates MISRA 2012 Advisory Rule 12.3, The comma operator should not be used.
* The comma is used  to abstract the trusted call function and to determine when the return into user mode is needed.
*
* @section Clock_Ip_c_REF_5
* Violates MISRA 2012 Advisory Rule 8.7, Functions and objects should not be defined with external linkage if
* they are referenced in only one translation unit.
* These functions represent the API of the driver. External linkage is needed to "export" the API.
*/

#include "Clock_Ip_Private.h"
#include "OsIf.h"

/*==================================================================================================
                               SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define CLOCK_IP_VENDOR_ID_C                      43
#define CLOCK_IP_AR_RELEASE_MAJOR_VERSION_C       4
#define CLOCK_IP_AR_RELEASE_MINOR_VERSION_C       4
#define CLOCK_IP_AR_RELEASE_REVISION_VERSION_C    0
#define CLOCK_IP_SW_MAJOR_VERSION_C               0
#define CLOCK_IP_SW_MINOR_VERSION_C               9
#define CLOCK_IP_SW_PATCH_VERSION_C               0

/*==================================================================================================
*                                     FILE VERSION CHECKS
==================================================================================================*/
/* Check if Clock_Ip.c file and Clock_Ip_Private.h file are of the same vendor */
#if (CLOCK_IP_VENDOR_ID_C != CLOCK_IP_PRIVATE_VENDOR_ID)
    #error "Clock_Ip.c and Clock_Ip_Private.h have different vendor ids"
#endif

/* Check if Clock_Ip.c file and Clock_Ip_Private.h file are of the same Autosar version */
#if ((CLOCK_IP_AR_RELEASE_MAJOR_VERSION_C != CLOCK_IP_PRIVATE_AR_RELEASE_MAJOR_VERSION) || \
     (CLOCK_IP_AR_RELEASE_MINOR_VERSION_C != CLOCK_IP_PRIVATE_AR_RELEASE_MINOR_VERSION) || \
     (CLOCK_IP_AR_RELEASE_REVISION_VERSION_C != CLOCK_IP_PRIVATE_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of Clock_Ip.c and Clock_Ip_Private.h are different"
#endif

/* Check if Clock_Ip.c file and Clock_Ip_Private.h file are of the same Software version */
#if ((CLOCK_IP_SW_MAJOR_VERSION_C != CLOCK_IP_PRIVATE_SW_MAJOR_VERSION) || \
     (CLOCK_IP_SW_MINOR_VERSION_C != CLOCK_IP_PRIVATE_SW_MINOR_VERSION) || \
     (CLOCK_IP_SW_PATCH_VERSION_C != CLOCK_IP_PRIVATE_SW_PATCH_VERSION) \
    )
    #error "Software Version Numbers of Clock_Ip.c and Clock_Ip_Private.h are different"
#endif

#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
/* Check if Clock_Ip.c file and OsIf.h file are of the same Autosar version */
#if ((CLOCK_IP_AR_RELEASE_MAJOR_VERSION_C    != OSIF_AR_RELEASE_MAJOR_VERSION) || \
     (CLOCK_IP_AR_RELEASE_MINOR_VERSION_C    != OSIF_AR_RELEASE_MINOR_VERSION))
    #error "AutoSar Version Numbers of Clock_Ip.c and OsIf.h are different"
#endif
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define MCU_START_SEC_CODE
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

static void ClockNotificatonsEmptyCallback(Clock_Ip_ClockNotificationType notification, Clock_Ip_NameType clockName);
static void Clock_Ip_Sleep(void);

#define MCU_STOP_SEC_CODE
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

/* Clock start initialized section data */
#define MCU_START_SEC_VAR_INIT_BOOLEAN
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

static boolean clockTreeIsConsumingPll = FALSE;                                                      /* Clock tree is using a PLL output */
/* Clock stop initialized section data */
#define MCU_STOP_SEC_VAR_INIT_BOOLEAN
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

#define MCU_START_SEC_VAR_INIT_UNSPECIFIED
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

static Clock_Ip_NotificationsCallbackType clockNotificationsCallback = ClockNotificatonsEmptyCallback;   /* Clock Report Error Callback */
const Clock_Ip_ClockConfigType *clockConfig = NULL_PTR;                                           /* Reference to the current clock configuration */
/* Clock stop initialized section data */
#define MCU_STOP_SEC_VAR_INIT_UNSPECIFIED
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

/* Clock start uninitialized section data */
#define  MCU_START_SEC_VAR_NO_INIT_8
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

static uint8 ClockCalcFreqCallIdx;

/* Clock stop uninitialized section data */
#define  MCU_STOP_SEC_VAR_NO_INIT_8
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"


/* Clock start section code */
#define MCU_START_SEC_CODE
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_Init
 * Description   : This function configures all clocks according to a clock configuration.
 *
 * @implements Clock_Ip_Init_Activity
 * END**********************************************************************************/
Clock_Ip_StatusType Clock_Ip_Init(Clock_Ip_ClockConfigType const * config)
{
    Clock_Ip_StatusType clockStatus = CLOCK_IP_ERROR;
    Clock_Ip_PllStatusType pllStatus;

    (void)consumerClockCallbacks;
    (void)xoscCallbackIndex;
    (void)extOscCallbacks;
    (void)ircoscCallbackIndex;
    (void)intOscCallbacks;
    (void)pcfsCallbackIndex;
    (void)pcfsCallbacks;
    (void)dividerCallbackIndex;
    (void)dividerCallbacks;
    (void)calcFreqCallbacks;

    (void)CLOCK_MODULE_INSTANCE;
    (void)CLOCK_CALLBACK;
    (void)INTERFACE_CLOCK;
    (void)SELECTOR_INDEX;
    (void)PCFS_INSTANCE;
    (void)DIVIDER_INDEX;
    (void)PCTL_INDEX;
    (void)PCC_INDEX;
    (void)PARTITION_INDEX;
    (void)COLLECTION_INDEX;
    (void)PCFS_HW_INDEX;
    (void)ENABLE_REQUEST;
    (void)PCFS_SW_INDEX;
    (void)TRIGGER_FEATURE;


#if (defined(CLOCK_IP_ENABLE_USER_MODE_SUPPORT))
  #if (STD_ON == CLOCK_IP_ENABLE_USER_MODE_SUPPORT)
    /* Set user access allowed for Clock */
    Clock_Ip_SetUserAccessAllowed();
  #endif
#endif
    CLOCK_DEV_ASSERT(NULL_PTR != config);

    Clock_Ip_InitClock(config);

    if (clockTreeIsConsumingPll)
    {
        pllStatus = Clock_Ip_GetPllStatus();
        if (CLOCK_IP_PLL_LOCKED == pllStatus)
        {
            Clock_Ip_DistributePll();
            clockStatus = CLOCK_IP_SUCCESS;
        }
    }
    else
    {
        clockStatus = CLOCK_IP_SUCCESS;
    }

    return clockStatus;
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_InitClock
 * Description   : This function configures all clocks according to a clock configuration.
 *
 * @implements Clock_Ip_InitClock_Activity
 * END**********************************************************************************/
void Clock_Ip_InitClock(Clock_Ip_ClockConfigType const * config)
{
    uint32 callbackIndex;
    uint32 i;

    ClockCalcFreqCallIdx = 0U;

    CLOCK_DEV_ASSERT(NULL_PTR != config);
    /* Clear all the settings for CMU0/1/2... */
    /* In case one clock configuration has the CMU disabled, then need to make the transition to
    reset state of CMU modules. */
    if (NULL_PTR != clockConfig)
    {
        for (i = 0U; i < config->cmusCount; i++)    /* Reset all clock monitor units from previous configuration. */
        {
            callbackIndex = cmuCallbackIndex[clockFeatures[config->cmus[i].name][CLOCK_CALLBACK]];
            cmuCallbacks[callbackIndex].Reset(&config->cmus[i]);
        }
    }

    /* Save the current clock configuration to be used by "Clock_Ip_DistributePllClock". */
    clockConfig = config;

    /* Platform specific initialization:
     * DFS reset, FIRC_CLK configuration etc. */
    SpecificPlatformInitClock(config);

    /*********************************************************************
     ***  Ramp down to safe configuration. Reset elements from clock tree:
     ***  selectors, fractional dividers, plls and xoscs
     ***********************************************************************/

    for (i = 0U; i < config->selectorsCount; i++)    /* Ramp down all selectors from configuration to SAFE_CLOCK */
    {
        callbackIndex = selectorCallbackIndex[clockFeatures[config->selectors[i].name][CLOCK_CALLBACK]];
        selectorCallbacks[callbackIndex].Reset(&config->selectors[i]);
    }

    for (i = 0U; i < config->fracDivsCount; i++)    /* Put in reset state all fractional dividers from configuration */
    {
        callbackIndex = fractional_dividerCallbackIndex[clockFeatures[config->fracDivs[i].name][CLOCK_CALLBACK]];
        fracDivCallbacks[callbackIndex].Reset(&config->fracDivs[i]);
    }

    for (i = 0U; i < config->pllsCount; i++)       /* Power down all plls from configuration */
    {
        callbackIndex = pllCallbackIndex[clockFeatures[config->plls[i].name][CLOCK_CALLBACK]];
        pllCallbacks[callbackIndex].Reset(&config->plls[i]);
    }

    for (i = 0U; i < config->xoscsCount; i++)     /* Power down all xoscs from configuration */
    {
        callbackIndex = xoscCallbackIndex[clockFeatures[config->xoscs[i].name][CLOCK_CALLBACK]];
        extOscCallbacks[callbackIndex].Reset(&config->xoscs[i]);
    }

    /*******************************************************
     *** Load the new configuration. Selectors that might
     *** be clocked from PLLs/XOCs shouldn't be configured.
     *******************************************************/

    for (i = 0U; i < config->ircoscsCount; i++)   /* Set internal oscillators from configuration */
    {
        callbackIndex = ircoscCallbackIndex[clockFeatures[config->ircoscs[i].name][CLOCK_CALLBACK]];
        intOscCallbacks[callbackIndex].Set(&config->ircoscs[i]);
    }

    for (i = 0U; i < config->xoscsCount; i++)     /* Configure all xoscs from configuration */
    {
        callbackIndex = xoscCallbackIndex[clockFeatures[config->xoscs[i].name][CLOCK_CALLBACK]];
        extOscCallbacks[callbackIndex].Set(&config->xoscs[i]);
    }

    /* Complete the process frequency calculations */
    Clock_Ip_Sleep();

    /* Configure the PCFS  */
    for (i = 0U; i < config->pcfsCount; i++)       /* Configure all progressive frequency switching clocks from configuration */
    {
        callbackIndex = pcfsCallbackIndex[clockFeatures[config->pcfs[i].name][CLOCK_CALLBACK]];
        pcfsCallbacks[callbackIndex].Set(&config->pcfs[i]);
    }

    /* Configure the clock divider triggers that are under MCU control */
    for (i = 0U; i < config->dividerTriggersCount; i++)    /* Set divider triggers from configuration. */
    {
        callbackIndex = dividertriggerCallbackIndex[clockFeatures[config->dividerTriggers[i].name][CLOCK_CALLBACK]];
        dividerTriggerCallbacks[callbackIndex].Configure(&config->dividerTriggers[i]);
    }

    /* Configure the clock dividers that are under MCU control */
    for (i = 0U; i < config->dividersCount; i++)    /* Set dividers from configuration. */
    {
        callbackIndex = dividerCallbackIndex[clockFeatures[config->dividers[i].name][CLOCK_CALLBACK]];
        dividerCallbacks[callbackIndex].Set(&config->dividers[i]);
    }

    /* Trigger update for all divider trigger that are under MCU control */
    for (i = 0U; i < config->dividerTriggersCount; i++)    /* Set divider triggers from configuration. */
    {
        callbackIndex = dividertriggerCallbackIndex[clockFeatures[config->dividerTriggers[i].name][CLOCK_CALLBACK]];
        dividerTriggerCallbacks[callbackIndex].TriggerUpdate(&config->dividerTriggers[i]);
    }

    /* Configure PLL clock generators */
    for (i = 0U; i < config->pllsCount; i++)       /* Configure all plls from configuration asynchronously. Do not wait. */
    {
        callbackIndex = pllCallbackIndex[clockFeatures[config->plls[i].name][CLOCK_CALLBACK]];
        pllCallbacks[callbackIndex].Set(&config->plls[i]);
    }

    /* Configure fractional dividers */
    /* Note: The DFS configuration might actually need to be done after we
     * know that the PLLs are all locked in "Clock_Ip_GetPllStatus". */
    for (i = 0U; i < config->fracDivsCount; i++)    /* Configure all fractional dividers from configuration asynchronously. Do not wait. */
    {
        callbackIndex = fractional_dividerCallbackIndex[clockFeatures[config->fracDivs[i].name][CLOCK_CALLBACK]];
        fracDivCallbacks[callbackIndex].Set(&config->fracDivs[i]);
    }

#ifdef FEATURE_CLOCK_IP_HAS_RAM_WAIT_STATES
    /* The entry point of the flash and RAM controllers configuration. */
    clockNotificationsCallback(CLOCK_IP_RAM_MEMORY_CONFIG_ENTRY_POINT, RESERVED_CLK);

    SetRamWaitStates();

    /* The exit point of the flash and RAM controllers configuration. */
    clockNotificationsCallback(CLOCK_IP_RAM_MEMORY_CONFIG_EXIT_POINT, RESERVED_CLK);
#endif

#ifdef FEATURE_CLOCK_IP_HAS_FLASH_WAIT_STATES
    /* The entry point of the flash and RAM controllers configuration. */
    clockNotificationsCallback(CLOCK_IP_FLASH_MEMORY_CONFIG_ENTRY_POINT, RESERVED_CLK);

    SetFlashWaitStates();

    /* The exit point of the flash and RAM controllers configuration. */
    clockNotificationsCallback(CLOCK_IP_FLASH_MEMORY_CONFIG_EXIT_POINT, RESERVED_CLK);
#endif

    clockTreeIsConsumingPll = FALSE;   /* Check if the clock tree is using a PLL output */

    /* Switch the clock multiplexers under MCU control to the configured source clocks */
    /* Note: if the configured source clock of a ClockMux is the output clock of a PLL/DFS,
     * the configuration will be skipped and the respective ClockMux will be switched in
     * the "Clock_Ip_DistributePllClock" function instead, when the source clock will have
     * stabilized already. */
    for (i = 0U; i < config->selectorsCount; i++)    /* Set only if selected inputs are not clocked from XOSCs or PLLs */
    {
        if ((IRCOSC_TYPE == clockName_sourceType[config->selectors[i].value]))  {

            callbackIndex = selectorCallbackIndex[clockFeatures[config->selectors[i].name][CLOCK_CALLBACK]];
            selectorCallbacks[callbackIndex].Set(&config->selectors[i]);
        }
        else
        {
            /* At least one mux is consuming pll */
            clockTreeIsConsumingPll = TRUE;
        }
    }

    for (i = 0U; i < config->gatesCount; i++)    /* Set clock gates that are under clock control. */
    {
        callbackIndex = gateCallbackIndex[clockFeatures[config->gates[i].name][CLOCK_CALLBACK]];
        gateCallbacks[callbackIndex].Set(&config->gates[i]);
    }

    /* Check if the clock tree is using a PLL output */
    if ( FALSE == clockTreeIsConsumingPll )
    {
#if CLOCK_SPECIFIC_PERIPH_NO > 0U
        /* Configure the specific modules like eMios */
        SpecificPeripheralClockInitialization(&config->specificPeriphalConfiguration);
#endif
        /* Set the Clock Monitoring Units ( CMU0 .. n ). */
        for (i = 0U; i < config->cmusCount; i++)
        {
            callbackIndex = cmuCallbackIndex[clockFeatures[config->cmus[i].name][CLOCK_CALLBACK]];
            cmuCallbacks[callbackIndex].Set(&config->cmus[i]);
        }
    }
    else
    {
        /* The clock tree is using at least one PLL/DFS output clock as source. */
        /* The user must wait until the PLLs and DFSs are locked by polling Clock_Ip_GetPllStatus */
        /* and then call "Clock_Ip_DistributePllClock" */
    }
    /* When mcu clock distribution is updated or power mode is changed, frequencies must be updated. */
    UpdateFrequencies(RUN_MODE);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_GetPllStatus
 * Description   : This function configures all clocks according to a clock configuration.
 * If no configuration is received, no change will be processed in HW and clock driver
 * will calculate frequencies only.
 *
 * @implements Clock_Ip_GetPllStatus_Activity
 * END**********************************************************************************/
Clock_Ip_PllStatusType Clock_Ip_GetPllStatus(void)
{

    Clock_Ip_PllStatusType retValue = CLOCK_IP_PLL_STATUS_UNDEFINED;
    clock_pll_status_t pllStatus;
#ifdef CLOCK_IP_DFS_SUPPORT
  #if (STD_ON == CLOCK_IP_DFS_SUPPORT)
    clock_dfs_status_t dfsStatus;
  #endif
#endif
    uint32 i, callbackIndex;

    for (i = 0U; i < NUMBER_OF_HARDWARE_PLL; i++)
    {
        callbackIndex = pllCallbackIndex[clockFeatures[HwPllName[i]][CLOCK_CALLBACK]];
        pllStatus = pllCallbacks[callbackIndex].Complete(HwPllName[i]);
        if (STATUS_PLL_UNLOCKED == pllStatus)
        {
            retValue = CLOCK_IP_PLL_UNLOCKED;
            break;
        }
        else
        {
            if (STATUS_PLL_LOCKED == pllStatus)
            {
                retValue = CLOCK_IP_PLL_LOCKED;
            }
        }
    }
#ifdef CLOCK_IP_DFS_SUPPORT
  #if (STD_ON == CLOCK_IP_DFS_SUPPORT)
    if (CLOCK_IP_PLL_LOCKED == retValue)
    {
        for (i = 0U; i < NUMBER_OF_HARDWARE_DFS; i++)
        {
            callbackIndex = fractional_dividerCallbackIndex[clockFeatures[HwDfsName[i]][CLOCK_CALLBACK]];
            dfsStatus = fracDivCallbacks[callbackIndex].Complete(HwDfsName[i]);
            if (STATUS_DFS_UNLOCKED == dfsStatus)
            {
                retValue = CLOCK_IP_PLL_UNLOCKED;
                break;
            }
        }
    }
  #endif
#endif
    return retValue;
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_DistributePll
 * Description   : Function completes the PLL configuration and then activates the PLL clock to Mcu
 * The function will not distribute the PLL clock if the driver state does not allow it, or the PLL is not stable.
 *
 * @implements Clock_Ip_DistributePll_Activity
 * END**********************************************************************************/
void Clock_Ip_DistributePll(void)
{

    uint32 i, callbackIndex;

    CLOCK_DEV_ASSERT(NULL_PTR != clockConfig);
    /* 'clockConfig' is set by Clock_Ip_InitClock().
     *  It doesn't make sense to call PLL distribution without clock initialization. */
    if (NULL_PTR != clockConfig)
    {
        for (i = 0U; i < clockConfig->selectorsCount; i++)    /* Set only if selected inputs are clocked from XOSCs or PLLs */
        {
            if (IRCOSC_TYPE != clockName_sourceType[clockConfig->selectors[i].value])  {

                callbackIndex = selectorCallbackIndex[clockFeatures[clockConfig->selectors[i].name][CLOCK_CALLBACK]];
                selectorCallbacks[callbackIndex].Set(&clockConfig->selectors[i]);
            }
        }

        /* In the case of PLL is enabled but PLL clock source is not used by any clock Mux.
           So, no need to re-configure for CMUs, because they are configured by Clock_Ip_InitClock */
        /* Check if the clock tree is using a PLL output */
        if ( clockTreeIsConsumingPll )
        {
#if CLOCK_SPECIFIC_PERIPH_NO > 0U
            SpecificPeripheralClockInitialization(&clockConfig->specificPeriphalConfiguration);
#endif
            /* Enable CMU if used */
            for (i = 0U; i < clockConfig->cmusCount; i++)
            {
                callbackIndex = cmuCallbackIndex[clockFeatures[clockConfig->cmus[i].name][CLOCK_CALLBACK]];
                cmuCallbacks[callbackIndex].Set(&clockConfig->cmus[i]);
            }
        }
    }

    /* When mcu clock distribution is updated or
     * power mode is changed, frequencies must be updated.
     */
    UpdateFrequencies(RUN_MODE);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_DisableClockMonitor
 * Description   : Disables a clock monitor.
 *
 * @implements Clock_Ip_DisableClockMonitor_Activity
 * END**********************************************************************************/
void Clock_Ip_DisableClockMonitor(Clock_Ip_NameType clockName)
{

    uint32 callbackIndex;

    callbackIndex = cmuCallbackIndex[clockFeatures[clockName][CLOCK_CALLBACK]];
    cmuCallbacks[callbackIndex].Disable(clockName);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_GetClockMonitorStatus
 * Description   : Returns the clock monitor status.
 *
 * @implements Clock_Ip_GetClockMonitorStatus_Activity
 * END**********************************************************************************/
Clock_Ip_CmuStatusType Clock_Ip_GetClockMonitorStatus(Clock_Ip_NameType clockName)
{
    uint32 callbackIndex;

    callbackIndex = cmuCallbackIndex[clockFeatures[clockName][CLOCK_CALLBACK]];
    return cmuCallbacks[callbackIndex].GetStatus(clockName);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_ClearClockMonitorStatus
 * Description   : Clears status flags for a monitor clock.
 *
 * @implements Clock_Ip_ClearClockMonitorStatus_Activity
 * END**********************************************************************************/
void Clock_Ip_ClearClockMonitorStatus(Clock_Ip_NameType clockName)
{

    uint32 callbackIndex;

    callbackIndex = cmuCallbackIndex[clockFeatures[clockName][CLOCK_CALLBACK]];
    cmuCallbacks[callbackIndex].Clear(clockName);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_PowerModeChangeNotification
 * Description   : Notifies clock driver when a power mode is changed.
 *
 * @implements Clock_Ip_PowerModeChangeNotification_Activity
 * END**********************************************************************************/
void Clock_Ip_PowerModeChangeNotification(power_modes_t powerMode,power_notification_t notification)
{
    (void)notification;
    UpdateFrequencies(powerMode);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_InstallNotificationsCallback
 * Description   : This function installs a callback for clock notifications. 
 *
 * @implements Clock_Ip_InstallNotificationsCallback_Activity
 * END**********************************************************************************/
void Clock_Ip_InstallNotificationsCallback(Clock_Ip_NotificationsCallbackType callback)
{
    CLOCK_DEV_ASSERT(NULL_PTR != callback);

    clockNotificationsCallback = callback;
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_DisableModuleClock
 * Description   : Disables clock for a peripheral. 
 *
 * @implements Clock_Ip_DisableModuleClock_Activity
 * END**********************************************************************************/
void Clock_Ip_DisableModuleClock(Clock_Ip_NameType clockName)
{

    uint32 callbackIndex;

    callbackIndex = gateCallbackIndex[clockFeatures[clockName][CLOCK_CALLBACK]];
    gateCallbacks[callbackIndex].Update(clockName,TRUE);
}

/*FUNCTION******************************************************************************
 *
 * Function Name : Clock_Ip_EnableModuleClock
 * Description   : Enable clock for a peripheral. 
 *
 * @implements Clock_Ip_EnableModuleClock_Activity
 * END**********************************************************************************/
void Clock_Ip_EnableModuleClock(Clock_Ip_NameType clockName)
{

    uint32 callbackIndex;

    callbackIndex = gateCallbackIndex[clockFeatures[clockName][CLOCK_CALLBACK]];
    gateCallbacks[callbackIndex].Update(clockName,FALSE);
}



/*FUNCTION**********************************************************************
 *
 * Function Name : Clock_Ip_GetClockFrequency
 * Description   : This function returns the frequency of a given clock
 *
 * @implements Clock_Ip_GetClockFrequency_Activity
 * END**************************************************************************/
uint32 Clock_Ip_GetClockFrequency(Clock_Ip_NameType clockName)
{
    uint32 frequency;
#if (defined(CLOCK_IP_DEV_ERROR_DETECT))
  #if (CLOCK_IP_DEV_ERROR_DETECT == STD_ON)
    CLOCK_DEV_ASSERT((((uint32)clockName) < ((uint32)CLOCK_NAMES_NO)) && (THE_LAST_PRODUCER_CLK != clockName));
  #endif
#endif

    if(((uint32)clockName) > ((uint32)THE_LAST_PRODUCER_CLK))
    {
        frequency = consumerClockCallbacks[((uint32)clockName) - ((uint32)THE_LAST_PRODUCER_CLK) - (uint32)1U]();
    }
    else
    {
        frequency = GetProducerClockFreq(clockName);
    }
    return frequency;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Clock_Ip_Sleep.
 * Description   : Complete the process frequency calculations
 *
 *END**************************************************************************/
static void Clock_Ip_Sleep(void)
{
    while(ClockCalcFreqCallIdx < (CALC_FREQ_CALLBACKS_NO-1U))
    {
        calcFreqCallbacks[ClockCalcFreqCallIdx]();
        ClockCalcFreqCallIdx++;
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Clock_Ip_TimeDelay.
 * Description   : TimeDelay. Process frequency calculations on behalf of TimeDelay function.
 *
 *END**************************************************************************/
void Clock_Ip_TimeDelay(void)
{
    calcFreqCallbacks[ClockCalcFreqCallIdx]();

    if (ClockCalcFreqCallIdx < (CALC_FREQ_CALLBACKS_NO-1U))
    {
        ClockCalcFreqCallIdx++;
    }
}

#if (defined(CLOCK_IP_ENABLE_USER_MODE_SUPPORT))
  #if (STD_ON == CLOCK_IP_ENABLE_USER_MODE_SUPPORT)
/*FUNCTION**********************************************************************
 *
 * Function Name : Clock_Ip_SetUserAccessAllowed.
 * Description   : Set user access allowed.
 *
 *END**************************************************************************/
void Clock_Ip_SetUserAccessAllowed(void)
{
    /**
    * @violates @ref Clock_Ip_c_REF_3 A function should be used in preference to a function-like macro where they are interchangeable.
    */
    /**
    * @violates @ref Clock_Ip_c_REF_4 The comma is used  to abstract the trusted call function and to determine when the return into user mode is needed.
    */
    OsIf_Trusted_Call(SpecificSetUserAccessAllowed);
}
  #endif
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : ClockNotificatonsEmptyCallback.
 * Description   : Notification clock call back.
 *
 *END**************************************************************************/
static void ClockNotificatonsEmptyCallback(Clock_Ip_ClockNotificationType notification, Clock_Ip_NameType clockName)
{
    /* No implementation */
    (void)notification;
    (void)clockName;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : ReportClockErrors
 * Description   : Report clock error
 *
 *END**************************************************************************/
void ReportClockErrors(Clock_Ip_ClockNotificationType error, Clock_Ip_NameType clockName)
{
    clockNotificationsCallback(error,clockName);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : ClockStartTimeout
 * Description   : Checks for timeout condition
 *
 *END**************************************************************************/
void ClockStartTimeout(uint32 *startTimeOut,
                       uint32 *elapsedTimeOut,
                       uint32 *timeoutTicksOut,
                       uint32 timeoutUs)
{
    *startTimeOut    = OsIf_GetCounter(CLOCK_TIMEOUT_TYPE);
    *elapsedTimeOut  = 0U;
    *timeoutTicksOut = OsIf_MicrosToTicks(timeoutUs, CLOCK_TIMEOUT_TYPE);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : ClockTimeoutExpired
 * Description   : Checks for timeout expiration condition
 *
 *END**************************************************************************/
boolean ClockTimeoutExpired(uint32 *startTimeInOut,
                            uint32 *elapsedTimeInOut,
                            uint32 TimeoutTicks)
{
    *elapsedTimeInOut += OsIf_GetElapsed(startTimeInOut, CLOCK_TIMEOUT_TYPE);

    return ((*elapsedTimeInOut >= TimeoutTicks)? TRUE : FALSE);
}


/* Clock stop section code */
#define MCU_STOP_SEC_CODE
/**
* @violates @ref Clock_Ip_c_REF_1 #include directives should only be preceded by preprocessor
* directives or comments.
*/
#include "Mcu_MemMap.h"

/*! @}*/

/*******************************************************************************
 * EOF
 ******************************************************************************/
