/******************************************************************************
 * $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 hwdg.c
 **
 ** A detailed description is available at
 ** @link HwdgGroup Hardware Watchdog functions description @endlink
 **
 ** History:
 **   - 2014-05-16  0.01  HS  Initial version for Traveo
 *****************************************************************************/

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


#if defined( PDL_PERIPHERAL_HWDG_ACTIVE )

/**
 *****************************************************************************
 ** \addtogroup HwdgGroup
 *****************************************************************************/
/*! @{ */

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/
/*! key for unlocking HW-WDG regs */
#define HWDG_PROT_UNLOCK        (0xEDACCE55)

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

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/
/**
 *****************************************************************************
 ** \brief Data needed by HWDG module for operation
 *****************************************************************************/
typedef struct stc_hwdg_intern_data
{
    func_ptr_t pfnPreWarnCallback;  /*! Callback for HWDG prior warning interrupt */
    func_ptr_t pfnNmiCallback;      /*! Callback for HWDG NMI interrupt */
} stc_hwdg_intern_data_t;

/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
static stc_hwdg_intern_data_t m_stcHwdgInternData;

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

/**
 *****************************************************************************
  ** \brief ISR for HWDG pre warning interrupt.
 **
 ** This ISR calls the callback function that has been given configuration
 ** (see Hwdg_Init() and #stc_hwdg_config_t).
 *****************************************************************************/
FN_IRQ_DEFINE_BEGIN(Hwdg_Isr_PreWarn, INTERRUPTS_IRQ_NUMBER_2)
{
    /* Clear prior warning interrupt flag. Registers need to be unlocked for */
    /* writing first. */
    HWDG_PROT = HWDG_PROT_UNLOCK;
    PDL_WRITE_REG_SYNC(HWDG_INTCLR_IRQCLR, 1);

    /* Call registered interrupt callback function if available. */
    /* If no callback is registered, the interrupt should not be enabled anyway. */
    /* The NULL pointer check is done just for safety reasons. */
    if (m_stcHwdgInternData.pfnPreWarnCallback != NULL)
    {
        m_stcHwdgInternData.pfnPreWarnCallback();
    }
}
FN_IRQ_DEFINE_END()

/**
 *****************************************************************************
  ** \brief ISR for HWDG NMI.
 **
 ** This ISR calls the callback function that has been given configuration
 ** (see Hwdg_Init() and #stc_hwdg_config_t).
 *****************************************************************************/
FN_NMI_DEFINE_BEGIN(Hwdg_Isr_NMI, INTERRUPTS_NMI_NUMBER_6)
{
    /* Clear prior warning interrupt flag. Registers need to be unlocked for */
    /* writing first. */
    HWDG_PROT = HWDG_PROT_UNLOCK;
    PDL_WRITE_REG_SYNC(HWDG_INTCLR_NMICLR, 1);

    /* Call registered interrupt callback function if available. */
    /* If no callback is registered, the interrupt should not be enabled anyway. */
    /* The NULL pointer check is done just for safety reasons. */
    if (m_stcHwdgInternData.pfnNmiCallback != NULL)
    {
        m_stcHwdgInternData.pfnNmiCallback();
    }
}
FN_NMI_DEFINE_END()

/**
 *****************************************************************************
 ** \brief Initialize hardware WDG
 **
 ** This function initializes the hardware WDG module. After a reset,
 ** the HWDG runs automatically and setup is completed by BOOTROM.
 **
 ** \note HWDG configurations are set by BOOTROM and those configurations are described
 **       by flash markers. For more detail of the flash markers, please see related HWM.
 **       When using with the template project, flash marker configurations are described
 **       in "flash_marker.asm". Please modify WDR(Watchdog Description Record)
 **       configurations to suit your requirement.
 **
 ** \pre Must be run from privileged mode.
 **
 ** \param [in]  pstcConfig         HWDG configuration
 **
 ** \retval Ok                      Initialization of HWDG module successful
 ** \retval ErrorInvalidParameter   If following conditions are met:
 **             - pstcConfig is NULL
 **             - pstcConfig does not fit HWDG IRQ and NMI settings.
 **               (When IRQ/NMI is enabled, a callback function is required.)
 **               (When IRQ/NMI is disabled, a callback function should not be supplied.)
 ** \retval ErrorAccessRights       If called from non-privileged mode
 *****************************************************************************/
en_result_t Hwdg_Init(const stc_hwdg_config_t *pstcConfig)
{
    boolean_t bPrivilegedMode;

    /* --------------- Check parameters and conditions ---------------- */
    /* Check CPU mode */
    /* WDG configurations can be set only when CPU is in the privilege mode */
    bPrivilegedMode = Cpu_CpuIsInPrivilegedMode();
    if (bPrivilegedMode == FALSE)
    {
        return ErrorAccessRights;
    }

    /* NULL pointer check */
    if (pstcConfig == NULL)
    {
        return ErrorInvalidParameter;
    }
    /* Check if  pstcConfig setting fits HWDG IRQ setting. */
    if ((HWDG_INT_IRQEN == 1) && (pstcConfig->pfnPreWarnCallback == NULL))
    {
        return ErrorInvalidParameter;
    } else if ((HWDG_INT_IRQEN == 0) && (pstcConfig->pfnPreWarnCallback != NULL))
    {
        return ErrorInvalidParameter;
    } else
    {
        /* correct setting */
    }
    /* Check if pstcConfig setting fits HWDG NMI setting. */
    if ((HWDG_INT_RSTEN == 1) && (pstcConfig->pfnNmiCallback != NULL))
    {
        return ErrorInvalidParameter;
    } else if ((HWDG_INT_RSTEN == 0) && (pstcConfig->pfnNmiCallback == NULL))
    {
        return ErrorInvalidParameter;
    } else
    {
        /* correct setting */
    }

    /* Store callback function */
    m_stcHwdgInternData.pfnNmiCallback = pstcConfig->pfnNmiCallback;
    m_stcHwdgInternData.pfnPreWarnCallback = pstcConfig->pfnPreWarnCallback;

    /* ---------------  Access registers ---------------- */
    /* Disable IRQs for protected sequences */
    IRQ_DISABLE_LOCAL();

    /* Clear interrupt flags */
    HWDG_PROT = HWDG_PROT_UNLOCK;
    HWDG_INTCLR_IRQCLR = 1;
    HWDG_PROT = HWDG_PROT_UNLOCK;
    HWDG_INTCLR_NMICLR = 1;

    /* Clear reset cause */
    HWDG_PROT = HWDG_PROT_UNLOCK;
    HWDG_RSTCAUSE = 0x00000000;

    /* restore IRQ state */
    IRQ_RESTORE();

    /* HWDG setup completed */
    return Ok;
}


/**
 *****************************************************************************
 ** \brief Return the HWDG reset cause
 **
 ** The last WDG reset cause will be cleared by Hwdg_Init().
 ** If this function is called after Hwdg_Init(), it will always return "no cause".
 **
 ** \pre Must be run before calling Hwdg_Init
 **
 ** \param [out] pstcResetCause     Returns previous HWDG reset cause.
 **
 ** \retval Ok                      Getting of reset cause is successful
 ** \retval ErrorInvalidParameter   If Hwdg_GetResetCause#pstcResetCause is NULL
 *****************************************************************************/
en_result_t Hwdg_GetResetCause(stc_hwdg_reset_cause_t* pstcResetCause)
{
    /* --------------- Check parameters and conditions ---------------- */
    if (pstcResetCause == NULL)
    {
        return ErrorInvalidParameter;
    }

    /* ---------------  Access registers ---------------- */
    pstcResetCause->bHwdgTriggerWhileUnlocked =
            (HWDG_RSTCAUSE_RSTCAUSE4 == 0) ? FALSE : TRUE;
    pstcResetCause->bHwdgTriggerTooEarly =
            (HWDG_RSTCAUSE_RSTCAUSE3 == 0) ? FALSE : TRUE;
    pstcResetCause->bHwdgNotTriggered =
            (HWDG_RSTCAUSE_RSTCAUSE2 == 0) ? FALSE : TRUE;
    pstcResetCause->bHwdgTriggerSequenceViolated =
            (HWDG_RSTCAUSE_RSTCAUSE1 == 0) ? FALSE : TRUE;
    pstcResetCause->bHwdgWrongTriggerValue =
            (HWDG_RSTCAUSE_RSTCAUSE0 == 0) ? FALSE : TRUE;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Clear the HWDG counter
 **
 ** \param [in] u8TrgVal0,1         Trigger values of the HWDG counter clearing.
 **                                 This values must be set to the same value as
 **                                 HWDG0_TRG0CFG, HWDG0_TRG1CFG.
 **
 ** \retval Ok                      Clearing the HWDG is successful.
 ** \retval Error                   The HWDG counter has not reached window lower limit.
 *****************************************************************************/
en_result_t Hwdg_Clear(uint8_t u8TrgVal0, uint8_t u8TrgVal1)
{
    uint32_t cnt;

    /* --------------- Check parameters and conditions ---------------- */
    cnt = Hwdg_GetCounterValue();
    if (cnt < HWDG_RUNLLS )
    {
        return Error;
    }

    /* ---------------  Access registers ---------------- */
    /* Clear HWDG */
    IRQ_DISABLE_LOCAL();
    HWDG_TRG0 = u8TrgVal0;
    HWDG_TRG1 = u8TrgVal1;
    IRQ_RESTORE();

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Get HWDG counter value
 **
 ** This function returns the current count value of the HWDG counter
 ** register.
 **
 ** \retval   Current watchdog counter value
 *****************************************************************************/
uint32_t Hwdg_GetCounterValue(void)
{
    /* ---------------  Access registers ---------------- */
    return HWDG_CNT;
}

/*! @} */
#endif /* PDL_PERIPHERAL_SWDG_ACTIVE */

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
