/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************
 ** \file frt.c
 **
 ** A detailed description is available at
 ** @link FrtGroup FRT Module description @endlink
 **
 ** History:
 ** - 2014-05-30  0.01  ST  First version
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "pdl.h"
#include "interrupts.h"


#if defined( PDL_PERIPHERAL_FRT_ACTIVE )

/**
 *****************************************************************************
 ** \addtogroup FrtGroup
 *****************************************************************************/
//@{

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/


/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/


/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/


/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/


/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/
static void FrtIrqHandler( volatile stc_frtn_t* pstcFrt,
                           stc_frt_intern_data_t* pstcFrtInternData
                         ) ;


/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

#include "frt_generated.c"

/**
 *****************************************************************************
 ** \brief ISR callback for FRT.
 **
 ** This handler is called by the FRT ISR whenever a FRT triggers an interrupt.
 ** It in return calls the callback function that has been given
 ** during FRT initialization (see Frt_Init() and stc_frt_config_t) and clears
 ** the interrupt flags of the Free Running Timer.
 **
 ** \param [in] pstcFrt           FRT unit instance that caused the interrupt.
 ** \param [in] pstcFrtInternData Internal data associated with the FRT instance.
 *****************************************************************************/
static void FrtIrqHandler( volatile stc_frtn_t* pstcFrt,
                           stc_frt_intern_data_t* pstcFrtInternData
                         )
{
    /* Check if a compare clear/overflow interrupt is raised */
    if ( pstcFrt->unTCCS.stcField.u1ICLR == 1 )
    {
        /* Clear compare clear flag */
        PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1ICLRC, 1);

        /* Call callback */
        if ( pstcFrtInternData->pfnCompareClearCallback != NULL )
        {
            pstcFrtInternData->pfnCompareClearCallback() ;
        }
    } /* if ( pstcFrt->unTCCS.stcField.u1ICLR == 1 ) */

    /* Check if a zero detect interrupt is raised */
    if ( pstcFrt->unTCCS.stcField.u1IRQZF == 1 )
    {
        /* Clear compare clear flag */
        PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1IRQZFC, 1);

        /* Call callback */
        if ( pstcFrtInternData->pfnZeroDetectCallback != NULL )
        {
            pstcFrtInternData->pfnZeroDetectCallback() ;
        }
    } /* if ( pstcFrt->unTCCS.stcField.u1IRQZF == 1 ) */
} /* FrtIrqHandler */


/**
 *****************************************************************************
 ** \brief Initialize a Free Running Timer configuration
 **
 ** This function initializes the given FRT instance with the provided
 ** parameters.
 ** The parameters are checked for plausibility and the given callbacks are
 ** stored internally.
 **
 ** To enable the configuration and prevent side effects, the timer is stopped
 ** before the settings are applied. The interrupts are disabled and the
 ** interrupt mask counters are set to zero.
 **
 ** \param [in]  pstcFrt          FRT unit instance
 ** \param [in]  pstcConfig       FRT configuration
 **
 ** \retval Ok                    FRT configuration has been applied.
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **             - pstcFrt == NULL
 **             - pstcConfig == NULL
 *****************************************************************************/
en_result_t Frt_Init( volatile stc_frtn_t* pstcFrt, const stc_frt_config_t* pstcConfig )
{
    /* Pointer to internal data structure */
    stc_frt_intern_data_t* pstcInternData ;

    /* Shadow data to avoid RMW and speed up HW access */
    un_frtn_tccs_t     unTCCS     = { 0 } ;
    un_frtn_teccs_t    unTECCS    = { 0 } ;

    /* Check parameters */
    if ( pstcFrt    == NULL ||
         pstcConfig == NULL
       )
    {
        return ErrorInvalidParameter ;
    }

    /* Stop FRT before configuration */
    pstcFrt->unTCCSS.stcField.u1STOPS = 1 ;
    PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1IRQZFC, 1);
    PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1ICLRC, 1);

    /* Clear timer */
    /* Since the timer is now stopped the FRTn_TCCS_SCLR bit will not work. */
    /* We have to write to the FRTn_TCDT register instead. */
    pstcFrt->unTCDT.u32Register = 0x00000000 ;

    /* Get pointer to internal data structure */
    pstcInternData = FrtGetInternDataPtr( pstcFrt ) ;
    /* Store callbacks and related parameters if needed */
    if ( pstcInternData != NULL )
    {
        pstcInternData->pfnCompareClearCallback    = \
                                           pstcConfig->pfnCompareClearCallback ;
        pstcInternData->pfnZeroDetectCallback      = \
                                             pstcConfig->pfnZeroDetectCallback ;
    }

    /* FRT configuration */

    /* Setup Compare Clear Buffer Enable */
    unTCCS.stcField.u1BFE   = \
                       (pstcConfig->bCompareClearBufferEnable == TRUE) ? 1 : 0 ;

    /* Setup Count Mode of FRT */
    unTCCS.stcField.u1MODE = \
                              (pstcConfig->bUpDownCountEnable == TRUE) ? 1 : 0 ;

    /* Setup interrupt mask selection */
    unTCCS.stcField.u3MSI   = pstcConfig->enInterruptMaskSelection ;

    /* Setup clock settings */
    unTCCS.stcField.u4CLK   = pstcConfig->enPrescaler ;

    /* Stop is the default mode */
    unTCCS.stcField.u1STOP = 1 ;

    /* Setup interrupt mask mode2 */
    unTECCS.stcField.u1MODE2 = \
                              (pstcConfig->bInterruptMaskMode2 == TRUE) ? 1 : 0 ;

    /* Set Compare clear interrupt mask selection */
    unTECCS.stcField.u3MSI   = pstcConfig->enCompareClearInterruptMaskSelection ;


    /* Now write shadow data to real HW */
    pstcFrt->unTECCS.u32Register    = unTECCS.u32Register ;
    pstcFrt->unTCCS.u32Register     = unTCCS.u32Register ;

    return Ok ;
} /* Frt_Init */


/**
 *****************************************************************************
 ** \brief Start a FRT.
 **
 ** This function starts the given FRT. If callbacks were set by Frt_Init(),
 ** the FRT interrupts are enabled and the internal ISR in turn calls the given callbacks.
 **
 ** The interrupts(and thus the callbacks) are not enabled even if callbacks were set by Frt_Init().
 **
 ** \param [in]  pstcFrt               FRT unit instance
 ** \param [in]  u16CompareClearValue  Compare clear value to count up to
 **
 ** \retval Ok                         FRT has been started.
 ** \retval ErrorInvalidParameter      If one of the following conditions are met:
 **                                 - pstcFrt == NULL
 **                                 - pstcConfig == NULL
 *****************************************************************************/
en_result_t Frt_Start( volatile stc_frtn_t* pstcFrt,
                       uint32_t u32CompareClearValue
                     )
{
    /* Pointer to internal data structure */
    stc_frt_intern_data_t* pstcInternData ;

    /* Check for NULL pointer */
    if ( pstcFrt == NULL )
    {
        return ErrorInvalidParameter ;
    }

    /* Enable interrupt if a callback has been given */
    pstcInternData = FrtGetInternDataPtr( pstcFrt ) ;

    if ( pstcInternData->pfnCompareClearCallback != NULL ||
         pstcInternData->pfnZeroDetectCallback   != NULL
       )
    {
        /* Enable zero detect interrupt */
        pstcFrt->unTCCSS.stcField.u1IRQZES = \
                       (pstcInternData->pfnZeroDetectCallback != NULL) ? 1 : 0 ;

        /* Enable compare clear interrupt */
        pstcFrt->unTCCSS.stcField.u1ICRES = \
                     (pstcInternData->pfnCompareClearCallback != NULL) ? 1 : 0 ;
    }

    /* Stop FRT (set stop bit) */
    pstcFrt->unTCCSS.stcField.u1STOPS = 1 ;

    /* Clear timer */
    pstcFrt->unTCDT.u32Register = 0x00000000;

    /* Set compare clear value */
    pstcFrt->unCPCLRB.u32Register = u32CompareClearValue ;

    /* Clear "zero detect" and "compare clear" flags */
    PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1IRQZFC, 1);
    PDL_WRITE_REG_SYNC(pstcFrt->unTCCSC.stcField.u1ICLRC, 1);

    /* Start counting (clear stop bit) */
    pstcFrt->unTCCSC.stcField.u1STOPC = 1 ;

    return Ok ;
} /* Frt_Start */


/**
 *****************************************************************************
 ** \brief Stop a running FRT.
 **
 ** This function stops the timer and disables the FRT interrupts for the specified
 ** FRT instance.
 **
 ** \param [in]  pstcFrt          FRT unit instance
 **
 ** \retval Ok                    FRT has been stopped
 ** \retval ErrorInvalidParameter If pstcFrt == NULL
 *****************************************************************************/
en_result_t Frt_Stop( volatile stc_frtn_t* pstcFrt )
{
    /* Check for NULL pointer */
    if ( pstcFrt == NULL )
    {
        return ErrorInvalidParameter;
    }

    /* Stop FRT (set stop bit) */
    pstcFrt->unTCCSS.stcField.u1STOPS = 1 ;

    /* Disable zero detect interrupt */
    PDL_SAFELY_DISABLE_INTERRUPT(pstcFrt->unTCCSC.stcField.u1IRQZEC, 1)

    /* Disable compare clear interrupt */
    PDL_SAFELY_DISABLE_INTERRUPT(pstcFrt->unTCCSC.stcField.u1ICLRC, 1)

    return Ok ;
} /* Frt_Stop */


/**
 *****************************************************************************
 ** \brief Get a Timer data.
 **
 ** This function get a Timer data value.
 **
 ** \param [in]   pstcFrt          FRT unit instance
 ** \param [out]  data             Timer data
 **
 ** \retval Ok                    Got a timer data.
 ** \retval ErrorInvalidParameter If pstcFrt == NULL.
 *****************************************************************************/
en_result_t Frt_GetCount( volatile stc_frtn_t* pstcFrt, uint32_t* data )
{
    /* Check for NULL pointer */
    if ( pstcFrt == NULL )
    {
        return ErrorInvalidParameter;
    }

    *data = pstcFrt->unTCDT.u32Register;

    return Ok ;
} /* Frt_GetCount */


//@}
#endif /* PDL_PERIPHERAL_FRT_ACTIVE */
/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
