/**************************************************************************//**
 * @file     RTC.c
 * @version  V3.00
 * @brief    N9H20 series RTC driver source file
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

/*---------------------------------------------------------------------------------------------------------*/
/* Includes of system headers                                                                              */
/*---------------------------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "wblib.h"
#include "wbtypes.h"
#include "N9H20_RTC.h"

/*---------------------------------------------------------------------------------------------------------*/
/* Macro, type and constant definitions                                                                    */
/*---------------------------------------------------------------------------------------------------------*/
#define RTC_GLOBALS

//#define RTC_DEBUG
#ifdef RTC_DEBUG
#define RTCDEBUG     DrvSIO_printf
#else
#define RTCDEBUG(...)
#endif

/*---------------------------------------------------------------------------------------------------------*/
/* Global file scope (static) variables                                                                    */
/*---------------------------------------------------------------------------------------------------------*/
static PFN_RTC_CALLBACK  *g_pfnRTCCallBack_Tick    = NULL, *g_pfnRTCCallBack_Alarm   = NULL, *g_pfnRTCCallBack_PSWI   = NULL;

static UINT32 volatile g_u32RTC_Count  = 0;
static CHAR g_chHourMode = 0;
static BOOL volatile g_bIsEnableTickInt  = FALSE;
static BOOL volatile g_bIsEnableAlarmInt = FALSE;

static UINT32 volatile g_u32Reg, g_u32Reg1,g_u32hiYear,g_u32loYear,g_u32hiMonth,g_u32loMonth,g_u32hiDay,g_u32loDay;
static UINT32 volatile g_u32hiHour,g_u32loHour,g_u32hiMin,g_u32loMin,g_u32hiSec,g_u32loSec;

/*---------------------------------------------------------------------------------------------------------*/
/* Functions                                                                                               */
/*---------------------------------------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------------------------------------*/
/* Function:     <RTC_ISR>                                                                                 */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               VOID                                                                                      */
/* Returns:                                                                                                */
/*               None                                                                                      */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* Description:                                                                                            */
/*               Install ISR to handle interrupt event                                                     */
/*---------------------------------------------------------------------------------------------------------*/

static VOID RTC_ISR (VOID)
{ 
    UINT32 volatile u32RegRIIR;

    u32RegRIIR = inp32(RIIR);
    if (u32RegRIIR & RTC_TICK_INT)                                       /* tick interrupt occurred */
    {
          outp32(RIIR, RTC_TICK_INT);
          g_u32RTC_Count++;                                              /* maintain RTC tick count */

          if (g_pfnRTCCallBack_Tick != NULL)                             /* execute tick callback function */
          {
              g_pfnRTCCallBack_Tick();
          }

    }

    if (u32RegRIIR & RTC_ALARM_INT)                                     /* alarm interrupt occurred */
    {    
          outp32(RIIR, RTC_ALARM_INT);

          RTC_Ioctl(0,RTC_IOC_DISABLE_INT,RTC_ALARM_INT,0);
           
          if (g_pfnRTCCallBack_Alarm != NULL)                           /* execute alarm callback function */
          {
              g_pfnRTCCallBack_Alarm();
          }
   }
    if (u32RegRIIR & RTC_PSWI_INT)                                     /* alarm interrupt occurred */
    {    
          outp32(RIIR, RTC_PSWI_INT);

         // RTC_Ioctl(0,RTC_IOC_DISABLE_INT,RTC_PSWI_INT,0);
           
          if (g_pfnRTCCallBack_PSWI != NULL)                           /* execute alarm callback function */
          {
              g_pfnRTCCallBack_PSWI();
          }
   }   
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_SetFrequencyCompensation                                                              */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               float number                                                                              */
/* Returns:                                                                                                */
/*               E_SUCCESS                Success.                                                         */
/*               E_RTC_ERR_FCR_VALUE      Wrong Compenation VALUE                                          */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*                                                                                                         */
/*               Set Frequecy Compenation Data                                                             */
/*---------------------------------------------------------------------------------------------------------*/
UINT32 RTC_SetFrequencyCompensation(FLOAT fnumber)
{
    INT32 i32intergerPart;
    INT32 i32fractionPart;
    INT32 i32RegInt,i32RegFra;
   	UINT32 u32Reg;

    i32intergerPart = (INT32) (fnumber);
    i32fractionPart = ((INT32) ( ((fnumber - i32intergerPart) *100)) / 100);
    i32RegInt = i32intergerPart - RTC_FCR_REFERENCE;
    i32RegFra = ((i32fractionPart) * 60);
    /*-----------------------------------------------------------------------------------------------------*/
    /* Judge Interger part is reasonable                                                                   */
    /*-----------------------------------------------------------------------------------------------------*/

    if ( (i32RegInt < 0) | (i32RegInt > 15) )
    {
        return E_RTC_ERR_FCR_VALUE ;
    }

    u32Reg = RTC_WriteEnable();
    if (u32Reg != 0)
    {
        return E_RTC_ERR_EIO ;
    }
    outp32(RTC_FCR, (UINT32)(g_u32Reg >>8 | i32RegFra));

    return E_RTC_SUCCESS;
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_WriteEnable                                                                           */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               VOID                                                                                      */
/* Returns:                                                                                                */
/*               E_SUCCESS                  Success.                                                       */
/*               E_RTC_ERR_FAILED           FAILED                                                         */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*                                                                                                         */
/*               Access PW to AER to make access other register enable                                     */
/*---------------------------------------------------------------------------------------------------------*/
UINT32 RTC_WriteEnable (VOID)
{
    INT32 i32i;
    
    outp32(INIR, RTC_INIT_KEY);
    outp32(AER, RTC_WRITE_KEY);


    for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++)
    {
        /*-------------------------------------------------------------------------------------------------*/
        /* check RTC_AER[16] to find out RTC write enable                                                  */
        /*-------------------------------------------------------------------------------------------------*/
        if ( inp32(AER) & 0x10000 )
        {
            break;
        }
    }

    if (i32i == RTC_WAIT_COUNT)
    {
        RTCDEBUG ("\nRTC: RTC_WriteEnable, set write enable FAILED!\n");
        return E_RTC_ERR_EIO;
    }

    return E_RTC_SUCCESS;
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Init                                                                                  */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               VOID                                                                                      */
/* Returns:                                                                                                */
/*               E_SUCCESS             Success.                                                            */
/*               E_RTC_ERR_EIO         Initial RTC FAILED.                                                 */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*                                                                                                         */
/*               Initial RTC and install ISR                                                               */
/*---------------------------------------------------------------------------------------------------------*/


UINT32 RTC_Init (VOID)
{
    INT32 i32i;

    outp32(REG_APBCLK, inp32(REG_APBCLK) | RTC_CKE);
    /*-----------------------------------------------------------------------------------------------------*/
    /* Initial time data struct and some parameters.                                                       */
    /*-----------------------------------------------------------------------------------------------------*/
    g_pfnRTCCallBack_Alarm = NULL;
    g_pfnRTCCallBack_Tick = NULL;
    g_pfnRTCCallBack_PSWI = NULL;
    g_u32RTC_Count = 0;
    /*-----------------------------------------------------------------------------------------------------*/
    /* When RTC is power on, write 0xa5eb1357 to RTC_INIR to reset all logic.                              */
    /*-----------------------------------------------------------------------------------------------------*/
    outp32(INIR, RTC_INIT_KEY);

    for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++)
    {
        if ( inp32(INIR) & 0x01 )
        {            /* Check RTC_INIR[0] to find out RTC reset signal */
            break;

        }
    }
        
    if (i32i == RTC_WAIT_COUNT)
    {
        RTCDEBUG("\nRTC: RTC_Init, initial RTC FAILED!\n");
        return E_RTC_ERR_EIO;
    }

    /*-----------------------------------------------------------------------------------------------------*/
    /* Install RTC ISR                                                                                     */
    /*-----------------------------------------------------------------------------------------------------*/
     outp32( RIIR, RTC_ALL_INT );
     
    sysInstallISR(IRQ_LEVEL_1, IRQ_RTC, (PVOID)RTC_ISR);
    sysSetLocalInterrupt(ENABLE_IRQ);
    sysEnableInterrupt(IRQ_RTC);

    return E_RTC_SUCCESS;
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Open                                                                                  */
/*                                                                                                         */
/* Parameter:    RTC_TIME_DATA_T *sPt            Just Set Current_Timer                                    */
/*                                                                                                         */
/* Returns:                                                                                                */
/*               E_SUCCESS            Success.                                                             */
/*               E_RTC_ERR_EIO        Initial RTC FAILED.                                                  */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*               Just Set Current_Timer .                                                                  */
//*--------------------------------------------------------------------------------------------------------*/

UINT32 RTC_Open (RTC_TIME_DATA_T *sPt)
{
    UINT32 u32Reg;
    outp32(REG_APBCLK, inp32(REG_APBCLK) | RTC_CKE);
    /*-----------------------------------------------------------------------------------------------------*/
    /* DO BASIC JUDGEMENT TO Check RTC time data value is reasonable or not.                               */
    /*-----------------------------------------------------------------------------------------------------*/
    if ( ((sPt->u32Year - RTC_YEAR2000) > 99)|
         ((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12))|
         ((sPt->u32cDay   == 0) || (sPt->u32cDay   > 31)))
    {
        return E_RTC_ERR_CALENDAR_VALUE;
    }

    if (sPt->u8cClockDisplay == RTC_CLOCK_12)
    {
        if ( (sPt->u32cHour == 0) || (sPt->u32cHour > 12) )
        {
            return E_RTC_ERR_TIMESACLE_VALUE ;
        }
    }
    else if (sPt->u8cClockDisplay == RTC_CLOCK_24)
    {
        if (sPt->u32cHour > 23)
        {
            return E_RTC_ERR_TIMESACLE_VALUE ;
        }
    }
    else
    {
        return E_RTC_ERR_TIMESACLE_VALUE ;
    }

    if ((sPt->u32cMinute > 59) |
        (sPt->u32cSecond > 59) |
        (sPt->u32cSecond > 59))
    {
        return E_RTC_ERR_TIME_VALUE ;
    }
    if (sPt->u32cDayOfWeek > 6)
    {
        return E_RTC_ERR_DWR_VALUE ;
    }

    /*-----------------------------------------------------------------------------------------------------*/
    /* Important, call RTC_WriteEnable() before write data into any register.                              */
    /*-----------------------------------------------------------------------------------------------------*/
    g_u32Reg = RTC_WriteEnable();
    if (g_u32Reg != 0)
    {
        return E_RTC_ERR_EIO;
    }

    /*-----------------------------------------------------------------------------------------------------*/
    /* Second, set RTC time data.                                                                          */
    /*-----------------------------------------------------------------------------------------------------*/
    if (sPt->u8cClockDisplay == RTC_CLOCK_12)
    {
        g_chHourMode = RTC_CLOCK_12;
        RTC_WriteEnable();
        outp32(TSSR, RTC_CLOCK_12);

        /*-------------------------------------------------------------------------------------------------*/
        /* important, range of 12-hour PM mode is 21 upto 32                                               */
        /*-------------------------------------------------------------------------------------------------*/
        if (sPt->u8cAmPm == RTC_PM)
            sPt->u32cHour += 20;
    }
    else                                                                               /* RTC_CLOCK_24 */
    {
        g_chHourMode = RTC_CLOCK_24;
        RTC_WriteEnable();
        outp32(TSSR, RTC_CLOCK_24);
        RTCDEBUG ("RTC: 24-hour\n");
    }

    outp32(DWR, (UINT32)sPt->u32cDayOfWeek);
    g_u32hiYear  = (sPt->u32Year - RTC_YEAR2000) / 10;
    g_u32loYear  = (sPt->u32Year - RTC_YEAR2000) % 10;
    g_u32hiMonth =  sPt->u32cMonth              / 10;
    g_u32loMonth =  sPt->u32cMonth              % 10;
    g_u32hiDay   =  sPt->u32cDay                / 10;
    g_u32loDay   =  sPt->u32cDay                % 10;
    u32Reg    = (g_u32hiYear << 20);
    u32Reg    |= (g_u32loYear << 16);
    u32Reg    |= (g_u32hiMonth << 12);
    u32Reg    |= (g_u32loMonth << 8);
    u32Reg    |= (g_u32hiDay << 4);
    u32Reg    |= g_u32loDay;
    g_u32Reg = u32Reg;
    outp32 (CLR, (UINT32)g_u32Reg);

    g_u32hiHour  = sPt->u32cHour / 10;
    g_u32loHour  = sPt->u32cHour % 10;
    g_u32hiMin   = sPt->u32cMinute / 10;
    g_u32loMin   = sPt->u32cMinute % 10;
    g_u32hiSec   = sPt->u32cSecond / 10;
    g_u32loSec   = sPt->u32cSecond % 10;
    u32Reg     = (g_u32hiHour << 20);
    u32Reg    |= (g_u32loHour << 16);
    u32Reg    |= (g_u32hiMin << 12);
    u32Reg    |= (g_u32loMin << 8);
    u32Reg    |= (g_u32hiSec << 4);
    u32Reg    |= g_u32loSec;
    g_u32Reg = u32Reg;
    outp32(TLR, (UINT32)g_u32Reg);
    
    RTC_WriteEnable();
   // u32Reg = inp32(TLR);
    while( inp32(TLR) != (UINT32)g_u32Reg);
    
    return E_RTC_SUCCESS;
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Read                                                                                  */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               eTime                          Currnet_Timer/ Alarm_Time                                  */
/*               RTC_TIME_DATA_T *spt           Time Data                                                  */
/* Returns:                                                                                                */
/*               E_SUCCESS                Success.                                                         */
/*               E_RTC_ERR_EIO            Initial RTC FAILED.                                              */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*               Read current date/time or alarm date/time from RTC                                        */
//*--------------------------------------------------------------------------------------------------------*/

UINT32 RTC_Read (E_RTC_TIME_SELECT eTime, RTC_TIME_DATA_T *sPt)
{
    UINT32 u32Tmp;

    g_u32Reg = RTC_WriteEnable();
    if (g_u32Reg != 0)
    {
        return E_RTC_ERR_EIO;
    }    
    
    sPt->u8cClockDisplay = inp32(TSSR);                               /* 12/24-hour */
    sPt->u32cDayOfWeek = inp32(DWR);                                  /* Day of week */

    switch (eTime)
    {
        case RTC_CURRENT_TIME:
        {
            g_u32Reg   = inp32(CLR);
            g_u32Reg1  = inp32(TLR);
            break;
        }
        case RTC_ALARM_TIME:
        {
            g_u32Reg   = inp32(CAR);
            g_u32Reg1  = inp32(TAR);
            break;
        }
        default:
        {
            return E_RTC_ERR_ENOTTY;
        }
    }


    g_u32hiYear  = (g_u32Reg & 0xF00000) >> 20;
    g_u32loYear  = (g_u32Reg & 0xF0000) >> 16;
    g_u32hiMonth = (g_u32Reg & 0x1000) >> 12;
    g_u32loMonth = (g_u32Reg & 0xF00) >> 8;
    g_u32hiDay   = (g_u32Reg & 0x30) >> 4;
    g_u32loDay   =  g_u32Reg & 0xF;

    u32Tmp = (g_u32hiYear * 10);
    u32Tmp+= g_u32loYear;
    sPt->u32Year   =   u32Tmp  + RTC_YEAR2000;
    
    u32Tmp = (g_u32hiMonth * 10);
    sPt->u32cMonth = u32Tmp + g_u32loMonth;
    
    u32Tmp = (g_u32hiDay * 10);
    sPt->u32cDay   =  u32Tmp  + g_u32loDay;


    g_u32hiHour = (g_u32Reg1 & 0x300000) >> 20;
    g_u32loHour = (g_u32Reg1 & 0xF0000) >> 16;
    g_u32hiMin  = (g_u32Reg1 & 0x7000) >> 12;
    g_u32loMin  = (g_u32Reg1 & 0xF00) >> 8;
    g_u32hiSec  = (g_u32Reg1 & 0x70) >> 4;
    g_u32loSec  =  g_u32Reg1 & 0xF;


    if (sPt->u8cClockDisplay == RTC_CLOCK_12)
    {
    
        u32Tmp = (g_u32hiHour * 10);
        u32Tmp+= g_u32loHour;
        sPt->u32cHour = u32Tmp;                                /* AM: 1~12. PM: 21~32. */
        switch (eTime)
        {
            case RTC_CURRENT_TIME:
            {
                if (sPt->u32cHour >= 21)
                {
                    sPt->u8cAmPm = RTC_PM;
                    sPt->u32cHour -= 20;
                }
                else
                {
                    sPt->u8cAmPm = RTC_AM;
                }
                break;
            }
            case RTC_ALARM_TIME:
            {
                if (sPt->u32cHour < 12)
                {
                    if(sPt->u32cHour == 0)
                        sPt->u32cHour = 12;
                    sPt->u8cAmPm = RTC_AM;
                }
                else
                {
                    sPt->u32cHour -= 12;
                    if(sPt->u32cHour == 0)
                        sPt->u32cHour = 12;
                    sPt->u8cAmPm = RTC_PM;
                }
                break;
            }
            default:
            {
                return E_RTC_ERR_ENOTTY;
            }
        }
        u32Tmp = (g_u32hiMin  * 10);
        u32Tmp+= g_u32loMin;
        sPt->u32cMinute = u32Tmp;
        
        u32Tmp = (g_u32hiSec  * 10);
        u32Tmp+= g_u32loSec;
        sPt->u32cSecond = u32Tmp;

    }
    else
    {   /* RTC_CLOCK_24 */
        u32Tmp = (g_u32hiHour * 10);
        u32Tmp+= g_u32loHour;
        sPt->u32cHour   = u32Tmp;
        
        u32Tmp = (g_u32hiMin  * 10);
        u32Tmp+= g_u32loMin;
        sPt->u32cMinute = u32Tmp;
        
        u32Tmp = (g_u32hiSec  * 10);
        u32Tmp+= g_u32loSec;
        sPt->u32cSecond = u32Tmp;
    }

    return E_RTC_SUCCESS;
}



/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Write                                                                                 */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               eTime                          Currnet_Timer/ Alarm_Time                                  */
/*               RTC_TIME_DATA_T *sPt           Time Data                                                  */
/* Returns:                                                                                                */
/*               E_SUCCESS               Success.                                                          */
/*               E_RTC_ERR_EIO           Initial RTC FAILED.                                               */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*               Read current date/time or alarm date/time from RTC                                        */
//*--------------------------------------------------------------------------------------------------------*/
UINT32 RTC_Write(E_RTC_TIME_SELECT eTime, RTC_TIME_DATA_T *sPt)
{
    UINT32 u32Reg;
    
    /*-----------------------------------------------------------------------------------------------------*/
    /* Check RTC time data value is reasonable or not.                                                     */
    /*-----------------------------------------------------------------------------------------------------*/
    if ( ((sPt->u32Year - RTC_YEAR2000) > 99)|
         ((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12))|
         ((sPt->u32cDay   == 0) || (sPt->u32cDay   > 31)))
    {
        RTCDEBUG ("\nRTC: Year value is incorrect\n");
        return E_RTC_ERR_CALENDAR_VALUE;
    }

    if ( (sPt->u32Year - RTC_YEAR2000) > 99 )
    {
        RTCDEBUG ("\nRTC: Year value is incorrect\n");
        return E_RTC_ERR_CALENDAR_VALUE;
    }

    if ( (sPt->u32cMonth == 0) || (sPt->u32cMonth > 12) )
    {
        RTCDEBUG ("\nRTC: Month value is incorrect\n");
        return E_RTC_ERR_CALENDAR_VALUE;
    }

    if ( (sPt->u32cDay == 0) || (sPt->u32cDay > 31) )
    {
        RTCDEBUG ("\nRTC: Day value is incorrect\n");
        return E_RTC_ERR_CALENDAR_VALUE;
    }

    if (sPt->u8cClockDisplay == RTC_CLOCK_12)
    {
        if ( (sPt->u32cHour == 0) || (sPt->u32cHour > 12) )
        {
            RTCDEBUG ("\nRTC: Hour value is incorrect\n");
            return E_RTC_ERR_TIME_VALUE;
        }
    }
    else if (sPt->u8cClockDisplay == RTC_CLOCK_24)
    {
        if (sPt->u32cHour > 23)
        {
            RTCDEBUG ("\nRTC: Hour value is incorrect\n");
            return E_RTC_ERR_TIME_VALUE;
        }
    }
    else
    {
        RTCDEBUG ("\nRTC: Clock mode is incorrect\n");
        return E_RTC_ERR_TIME_VALUE;
    }

    if (sPt->u32cMinute > 59)
    {
        RTCDEBUG ("\nRTC: Minute value is incorrect\n");
        return E_RTC_ERR_TIME_VALUE;
    }

    if (sPt->u32cSecond > 59)
    {
        RTCDEBUG ("\nRTC: Second value is incorrect\n");
        return E_RTC_ERR_TIME_VALUE;
    }

    if (sPt->u32cDayOfWeek > 6)
    {
        RTCDEBUG ("\nRTC: Day of week value is incorrect\n");
        return E_RTC_ERR_DWR_VALUE;
    }


    /*-----------------------------------------------------------------------------------------------------*/
    /* Important, call RTC_Open() before write data into any register.                                     */
    /*-----------------------------------------------------------------------------------------------------*/
    g_u32Reg = RTC_WriteEnable();
    if (g_u32Reg != 0)
    {
        return E_RTC_ERR_EIO;
    }

    switch (eTime)
    {

        case RTC_CURRENT_TIME:
            /*---------------------------------------------------------------------------------------------*/
            /* Second, set RTC time data.                                                                  */
            /*---------------------------------------------------------------------------------------------*/

            if (sPt->u8cClockDisplay == RTC_CLOCK_12)
            {
                g_chHourMode = RTC_CLOCK_12;
                outp32(TSSR, RTC_CLOCK_12);
                RTCDEBUG ("RTC: 12-hour\n");
                /*-----------------------------------------------------------------------------------------*/
                /* important, range of 12-hour PM mode is 21 upto 32                                       */
                /*-----------------------------------------------------------------------------------------*/
                if (sPt->u8cAmPm == RTC_PM)
                    sPt->u32cHour += 20;
            }
            else                                                                  /* RTC_CLOCK_24 */
            {
                g_chHourMode = RTC_CLOCK_24;
                outp32(TSSR, RTC_CLOCK_24);
                RTCDEBUG ("RTC: 24-hour\n");
            }

            outp32(DWR,(UINT32) sPt->u32cDayOfWeek);

            g_u32hiYear  = (sPt->u32Year - RTC_YEAR2000) / 10;
            g_u32loYear  = (sPt->u32Year - RTC_YEAR2000) % 10;
            g_u32hiMonth = sPt->u32cMonth / 10;
            g_u32loMonth = sPt->u32cMonth % 10;
            g_u32hiDay   = sPt->u32cDay / 10;
            g_u32loDay   = sPt->u32cDay % 10;
            
            u32Reg = (g_u32hiYear << 20);
            u32Reg|= (g_u32loYear << 16);
            u32Reg|= (g_u32hiMonth << 12);
            u32Reg|= (g_u32loMonth << 8);
            u32Reg|= (g_u32hiDay << 4);
            u32Reg|= g_u32loDay;
            g_u32Reg = u32Reg;
            RTCDEBUG ("RTC: REG_RTC_CLR[0x%08x]\n", inp32(CLR));
            RTC_WriteEnable();
            outp32 (CLR, (UINT32)g_u32Reg);

            g_u32hiHour  = sPt->u32cHour / 10;
            g_u32loHour  = sPt->u32cHour % 10;
            g_u32hiMin   = sPt->u32cMinute / 10;
            g_u32loMin   = sPt->u32cMinute % 10;
            g_u32hiSec   = sPt->u32cSecond / 10;
            g_u32loSec   = sPt->u32cSecond % 10;
            
            u32Reg = (g_u32hiHour << 20);
            u32Reg|= (g_u32loHour << 16);
            u32Reg|= (g_u32hiMin << 12);
            u32Reg|= (g_u32loMin << 8);
            u32Reg|= (g_u32hiSec << 4);
            u32Reg|= g_u32loSec;
            g_u32Reg = u32Reg;
            RTCDEBUG ("RTC: REG_RTC_TLR[0x%08x]\n", inp32(TLR));
            RTC_WriteEnable();
            outp32(TLR, (UINT32)g_u32Reg);
            
            RTC_WriteEnable();
            while(inp32(TLR) != (UINT32)g_u32Reg);

            if (g_chHourMode == RTC_CLOCK_12)
            {
                if (sPt->u8cAmPm == RTC_PM)                   /* important, range of 12-hour PM mode is 21 upto 32 */
                    sPt->u32cHour -= 20;
            }
            return E_RTC_SUCCESS;


         case RTC_ALARM_TIME:

            g_pfnRTCCallBack_Alarm = NULL;                    /* Initial call back function.*/
            /*---------------------------------------------------------------------------------------------*/
            /* Second, set alarm time data.                                                                */
            /*---------------------------------------------------------------------------------------------*/
            g_u32hiYear = (sPt->u32Year - RTC_YEAR2000) / 10;
            g_u32loYear = (sPt->u32Year - RTC_YEAR2000) % 10;
            g_u32hiMonth = sPt->u32cMonth / 10;
            g_u32loMonth = sPt->u32cMonth % 10;
            g_u32hiDay = sPt->u32cDay / 10;
            g_u32loDay = sPt->u32cDay % 10;
            
            u32Reg = (g_u32hiYear << 20);
            u32Reg|= (g_u32loYear << 16);
            u32Reg|= (g_u32hiMonth << 12);
            u32Reg|= (g_u32loMonth << 8);
            u32Reg|= (g_u32hiDay << 4);
            u32Reg|= g_u32loDay;
            g_u32Reg = u32Reg;
            outp32(CAR, (UINT32)g_u32Reg);

            if (g_chHourMode == RTC_CLOCK_12)
            {
                if (sPt->u8cAmPm == RTC_PM)       /* important, range of 12-hour PM mode is 21 upto 32 */
                    sPt->u32cHour += 20;
            }
            g_u32hiHour   = sPt->u32cHour / 10;
            g_u32loHour   = sPt->u32cHour % 10;
            g_u32hiMin  = sPt->u32cMinute / 10;
            g_u32loMin  = sPt->u32cMinute % 10;
            g_u32hiSec  = sPt->u32cSecond / 10;
            g_u32loSec  = sPt->u32cSecond % 10;
            
            u32Reg = (g_u32hiHour << 20);
            u32Reg|= (g_u32loHour << 16);
            u32Reg|= (g_u32hiMin << 12);
            u32Reg|= (g_u32loMin << 8);
            u32Reg|= (g_u32hiSec << 4);
            u32Reg|= g_u32loSec;
            
            g_u32Reg = u32Reg;
            outp32(TAR, (UINT32)g_u32Reg);
            
            if (g_chHourMode == RTC_CLOCK_12)
            {
                if (sPt->u8cAmPm == RTC_PM)       /* important, range of 12-hour PM mode is 21 upto 32 */
                {
                    sPt->u32cHour -= 20;
      
                    g_u32hiHour   = (sPt->u32cHour + 12) / 10;
                    g_u32loHour   = (sPt->u32cHour + 12) % 10;
                    g_u32hiMin  = sPt->u32cMinute / 10;
                    g_u32loMin  = sPt->u32cMinute % 10;
                    g_u32hiSec  = sPt->u32cSecond / 10;
                    g_u32loSec  = sPt->u32cSecond % 10;

                    u32Reg = (g_u32hiHour << 20);
                    u32Reg|= (g_u32loHour << 16);
                    u32Reg|= (g_u32hiMin << 12);
                    u32Reg|= (g_u32loMin << 8);
                    u32Reg|= (g_u32hiSec << 4);
                    u32Reg|= g_u32loSec;

                    g_u32Reg = u32Reg;
                } 
            }            
            /*---------------------------------------------------------------------------------------------*/
            /* Third, install alarm callback function.                                                     */
            /*---------------------------------------------------------------------------------------------*/
            if (sPt->pfnAlarmCallBack != NULL)
                g_pfnRTCCallBack_Alarm = sPt->pfnAlarmCallBack;
            /*---------------------------------------------------------------------------------------------*/
            /* Finally, enable alarm interrupt.                                                            */
            /*---------------------------------------------------------------------------------------------*/

            RTC_Ioctl(0,RTC_IOC_ENABLE_INT,RTC_ALARM_INT,0);
            
            u32Reg = inp32(TAR);
            RTC_WriteEnable();
            while(inp32(TAR) != (UINT32)g_u32Reg);
            
            return E_RTC_SUCCESS;

        default:
        {
            return E_RTC_ERR_ENOTTY;
        }
    }

}



/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Ioctl                                                                                 */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               i32Num             Interface number.   always set 0                                       */
/*               eCmd               Command.                                                               */
/*               u32Arg0            Arguments for the command.                                             */
/*               u32Arg1            Arguments for the command.                                             */
/* Returns:                                                                                                */
/*               E_SUCCESS               Success.                                                          */
/*               E_RTC_ERR_ENOTTY        Command not support, or parameter incorrect.                      */
/*               E_RTC_ERR_ENODEV        Interface number incorrect.                                       */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*               Support some commands for application.                                                    */
//*--------------------------------------------------------------------------------------------------------*/

UINT32 RTC_Ioctl (INT32 i32Num, E_RTC_CMD eCmd, UINT32 u32Arg0, UINT32 u32Arg1)
{
    INT32 i32Ret;
    UINT32 u32Reg;
    RTC_TICK_T *ptick;

    if (i32Num != 0)
        return E_RTC_ERR_ENODEV;

    switch (eCmd)
    {

        case RTC_IOC_IDENTIFY_LEAP_YEAR:
        {
            u32Reg = inp32(LIR);
            if (u32Reg & 0x01)
            {
                *(PUINT32)u32Arg0 = RTC_LEAP_YEAR;
                RTCDEBUG("\nRTC: It's a leap year\n");
            }
            else
            {
                *(PUINT32)u32Arg0 = 0;
                RTCDEBUG("\nRTC: It's not a leap year\n");
            }
            break;
        }
        case RTC_IOC_SET_TICK_MODE:
        {
            ptick = (RTC_TICK_T *) u32Arg0;
            
            if (g_bIsEnableTickInt== TRUE)
            {            
                RTC_Ioctl(0,RTC_IOC_DISABLE_INT,RTC_TICK_INT,0);
                g_bIsEnableTickInt = TRUE;
            }    
            g_u32RTC_Count = 0;

            u32Reg = RTC_WriteEnable();
            if (u32Reg != 0)
            {
                return E_RTC_ERR_EIO ;
            }
            if (ptick->ucMode > RTC_TICK_1_128_SEC)                            /*Tick mode 0 to 7 */
            {
                return E_RTC_ERR_ENOTTY ;
            }
            
            outp32(TTR, ptick->ucMode);
           
            
            if (ptick->pfnTickCallBack != NULL)
            {
                g_pfnRTCCallBack_Tick = ptick->pfnTickCallBack;
            }
            else
            {
                g_pfnRTCCallBack_Tick = NULL;
            }
            
            RTC_WriteEnable();
            while(inp32(TTR) != ptick->ucMode);
            /*---------------------------------------------------------------------------------------------*/
            /* Reset tick interrupt status if program enable tick interrupt before.                        */
            /*---------------------------------------------------------------------------------------------*/
            if (g_bIsEnableTickInt== TRUE)
            {

                RTC_Ioctl(0,RTC_IOC_ENABLE_INT,RTC_TICK_INT,0);
                return E_RTC_SUCCESS;
            }
            break;
        }

        case RTC_IOC_GET_TICK:
        {
            (*(PUINT32)u32Arg0) = g_u32RTC_Count;
            break;
        }

        case RTC_IOC_RESTORE_TICK:
        {
            g_u32RTC_Count = 0;
            break;
        }

        case RTC_IOC_ENABLE_INT:
        {
            INT32 i32Ret;

            i32Ret = RTC_WriteEnable();
            if (i32Ret != 0)
            {
                return E_RTC_ERR_EIO;
            }
            switch ((RTC_INT_SOURCE)u32Arg0)
            {
                case RTC_TICK_INT:
                {
                    g_bIsEnableTickInt   = TRUE;
                    outp32(RIER, inp32(RIER) | RTC_TICK_INT);
                    break;
                }
                case RTC_ALARM_INT:
                {
                    g_bIsEnableAlarmInt  = TRUE;
                    outp32(RIER, inp32(RIER) | RTC_ALARM_INT);
                    break;
                }
                case RTC_PSWI_INT:
                {
                    g_bIsEnableAlarmInt  = TRUE;
                    outp32(RIER, inp32(RIER) | RTC_PSWI_INT);
                    break;
                }              
                default:
                {
                    return E_RTC_ERR_ENOTTY;

                }
            }
            break;
        }
        case RTC_IOC_DISABLE_INT:
        {
            INT32 i32Ret;

            i32Ret = RTC_WriteEnable();
            if (i32Ret != 0)
            {
                return E_RTC_ERR_EIO;
            }            
            switch ((RTC_INT_SOURCE)u32Arg0)
            {
                case RTC_TICK_INT:
                {
                    g_bIsEnableTickInt   = FALSE;
                    outp32( RIER, inp32(RIER) & (~RTC_TICK_INT) );
                    outp32( RIIR, inp32(RIIR) & (RTC_TICK_INT) );
                    break;
                }
                case RTC_ALARM_INT:
                {
                    g_bIsEnableAlarmInt  = FALSE;
                    outp32( RIER, inp32(RIER) & (~RTC_ALARM_INT) );
                    outp32( RIIR, inp32(RIIR) & (RTC_ALARM_INT) );
                    break;
                }
                case RTC_PSWI_INT:
                {
                    g_bIsEnableAlarmInt  = FALSE;
                    outp32( RIER, inp32(RIER) & (~RTC_PSWI_INT) );
                    outp32( RIIR, inp32(RIIR) & (RTC_PSWI_INT) );
                    break;
                }
                case RTC_ALL_INT:
                {
                    g_bIsEnableTickInt   = FALSE;
                    g_bIsEnableAlarmInt  = FALSE;
                    outp32( RIER, 0 );
                    outp32( RIIR, RTC_ALL_INT );

                    break;
                }
                default:
                {
                    return E_RTC_ERR_ENOTTY;
                }
            }
            break;
        }

        case RTC_IOC_SET_FREQUENCY:
        {
            i32Ret= RTC_SetFrequencyCompensation(u32Arg0) ;
            if (i32Ret != 0)
            {
                return E_RTC_ERR_ENOTTY;
            }
            break;
        }
        case RTC_IOC_SET_POWER_ON:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }
            outp32(PWRON, inp32(PWRON) | 0x01);

            break;
        }
        case RTC_IOC_SET_POWER_OFF:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }
            outp32(PWRON, (inp32(PWRON) & ~0x05) | 2);
            //outp32(REG_APBCLK, inp32(REG_APBCLK) & ~RTC_CKE);
            outp32(REG_AHBCLK,0);
            while(1);
        }
        case RTC_IOC_SET_POWER_OFF_PERIOD:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }

            outp32(PWRON, (inp32(PWRON) & ~0xF0000) | ((u32Arg0 & 0xF) << 16));

            while(((inp32(PWRON) & 0xF0000)) != ((u32Arg0 & 0xF) << 16) );
            break;
        }
        case RTC_IOC_ENABLE_HW_POWEROFF:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }
            outp32(PWRON, (inp32(PWRON) | 0x04));
            while(!(inp32(PWRON) & 0x04));
            break;
        }
        case RTC_IOC_DISABLE_HW_POWEROFF:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }
            outp32(PWRON, (inp32(PWRON) & ~0x04));
            while((inp32(PWRON) & 0x04));
            break;
        }
        case RTC_IOC_SET_PSWI_CALLBACK:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }

            RTC_Ioctl(0, RTC_IOC_ENABLE_INT, RTC_PSWI_INT, 0);

            if (((PFN_RTC_CALLBACK  *) u32Arg0) != NULL)
            {
                g_pfnRTCCallBack_PSWI = (PFN_RTC_CALLBACK  *) u32Arg0;
            }
            else
            {
                g_pfnRTCCallBack_PSWI = NULL;
            }
            break;
        }
        case RTC_IOC_GET_POWERKEY_STATUS:
        {
            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }

            g_u32Reg = RTC_WriteEnable();
            if (g_u32Reg != 0)
            {
                return E_RTC_ERR_EIO;
            }

            if(inp32(PWRON) & 0x80)
                *(PUINT32)u32Arg0 = 1;
            else
                *(PUINT32)u32Arg0 = 0;

            break;
        }
        default:
        {
            return E_RTC_ERR_ENOTTY;
        }
    }

    return E_RTC_SUCCESS;
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function:     RTC_Close                                                                                 */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               VOID                                                                                      */
/* Returns:                                                                                                */
/*               E_SUCCESS                Success.                                                         */
/*               E_RTC_ERR_ENODEV         Interface number incorrect.                                      */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* DESCRIPTION                                                                                             */
/*               Disable AIC channel of RTC and both tick and alarm interrupt..                            */
/*---------------------------------------------------------------------------------------------------------*/

UINT32 RTC_Close (VOID)
{

    g_bIsEnableTickInt = FALSE;
    
    sysDisableInterrupt(IRQ_RTC);
   

    RTC_Ioctl(0,RTC_IOC_DISABLE_INT,RTC_ALL_INT,0);


    return E_RTC_SUCCESS;
}

extern UINT32 RTC_Init(VOID);
extern UINT32 RTC_Open(RTC_TIME_DATA_T *sPt);
extern UINT32 RTC_Ioctl(INT32 nNum, E_RTC_CMD uCmd, UINT32 uArg0, UINT32 u32Arg1);
extern UINT32 RTC_Read(E_RTC_TIME_SELECT eTime, RTC_TIME_DATA_T *sPt);
extern UINT32 RTC_Write(E_RTC_TIME_SELECT eTime, RTC_TIME_DATA_T *sPt);
extern UINT32 RTC_Close(VOID);