/**************************************************************************//**
 * @file     PWM.c
 * @version  V3.00
 * @brief    N9H26 series PWM 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 "N9H26_PWM.h"

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

/*---------------------------------------------------------------------------------------------------------*/
/* Global file scope (static) variables                                                                    */
/*---------------------------------------------------------------------------------------------------------*/
static PWM_CALLBACK_T pfnPWMHandler = {FALSE};
UINT32 volatile g_u32PwmHz;

/*---------------------------------------------------------------------------------------------------------*/
/* Function:     <PWM0_ISR>                                                                                */
/*                                                                                                         */
/* Parameter:                                                                                              */
/*               VOID                                                                                      */
/* Returns:                                                                                                */
/*               None                                                                                      */
/* Side effects:                                                                                           */
/*                                                                                                         */
/* Description:                                                                                            */
/*               ISR to handle PWM0 interrupt event           		                                       */
/*---------------------------------------------------------------------------------------------------------*/
static VOID PWM_ISR (void)
{ 
    UINT32 volatile u32RegPIIR,u32RegCCR0,u32RegCCR1;

    u32RegPIIR = inp32(PIIR);
    u32RegCCR0 = inp32(CCR0);
    u32RegCCR1 = inp32(CCR1);    
    
    if (u32RegPIIR & 0xF )    
    {
		if(u32RegPIIR & PIIR0)
    	{
    		outp32(PIIR, PIIR0);    
			if (pfnPWMHandler.pfnPWM0CallBack != NULL)                           
            	pfnPWMHandler.pfnPWM0CallBack();	
    	} 	    	    	
		if(u32RegPIIR & PIIR1)
    	{
    		outp32(PIIR, PIIR1);    
			if (pfnPWMHandler.pfnPWM1CallBack != NULL)                           
            	pfnPWMHandler.pfnPWM1CallBack();	
    	}   
		if(u32RegPIIR & PIIR2)
    	{
    		outp32(PIIR, PIIR2);    
			if (pfnPWMHandler.pfnPWM2CallBack != NULL)                           
            	pfnPWMHandler.pfnPWM2CallBack();	
    	} 
		if(u32RegPIIR & PIIR3)
    	{
    		outp32(PIIR, PIIR3);    
			if (pfnPWMHandler.pfnPWM3CallBack != NULL)                           
            	pfnPWMHandler.pfnPWM3CallBack();	
    	}    
    }

    if (u32RegCCR0 & CIIR0) 
    {
    	outp32(CCR0, inp32(CCR0) & ~CIIR0);
        if (pfnPWMHandler.pfnCAP0CallBack != NULL)
        {
        	pfnPWMHandler.pfnCAP0CallBack();
        }
	}

    if (u32RegCCR0 & CIIR1) 
    {
    	outp32(CCR0, inp32(CCR0) & ~CIIR1);
        if (pfnPWMHandler.pfnCAP1CallBack != NULL)
        {
        	pfnPWMHandler.pfnCAP1CallBack();
        }
	}		

    if (u32RegCCR1 & CIIR2) 
    {
    	outp32(CCR1, inp32(CCR1) & ~CIIR2);
        if (pfnPWMHandler.pfnCAP2CallBack != NULL)
        {
        	pfnPWMHandler.pfnCAP2CallBack();
        }
	}		 
    if (u32RegCCR1 & CIIR3) 
    {
    	outp32(CCR1, inp32(CCR1) & ~CIIR3);
        if (pfnPWMHandler.pfnCAP3CallBack != NULL)
        {
        	pfnPWMHandler.pfnCAP3CallBack();
        }
	}			
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_IsTimerEnabled                                                                            */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer - [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3         			       */
/*                                                                                                         */
/* Returns:                                                                                                */
/*               0		disable                                                                            */
/*               1		enable	                                                                           */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get PWM specified timer enable/disable state  	               */
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_IsTimerEnabled(UINT8 u8Timer)
{
	return ((inp32(PCR) & (1 << ((u8Timer & 0x7) << 3))) ? TRUE : FALSE);
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerCounter                                                                           */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3   				   */
/*               u16Counter     - [in]      Timer counter : 0~65535                                        */
/* Returns:                                                                                                */
/*               0		disable                                                                            */
/*               1		enable	                                                                           */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to set the PWM specified timer counter 			           		   */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_SetTimerCounter(UINT8 u8Timer, UINT16 u16Counter)
{
	outp32(CNR0 + (u8Timer & 0x07) * 12, u16Counter);		
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetTimerCounter                                                                           */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3  			       */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               The specified timer counter value                                                         */
/*              											                                        	   */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get the PWM specified timer counter value 		               */
/*---------------------------------------------------------------------------------------------------------*/
UINT32 PWM_GetTimerCounter(UINT8 u8Timer)
{
	return (inp32(PDR0 + 0x0C * (u8Timer & 0x07)) & 0xFFFF);
}



/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvPWM_InstallCallBack		                                                                   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		DRVPWM_TIMER0/DRVPWM_TIMER1/DRVPWM_TIMER2/DRVPWM_TIMER3        */
/*         									DRVPWM_CAP0/DRVPWM_CAP1/DRVPWM_CAP2/DRVPWM_CAP3        		   */
/*               pfncallback	- [in]		The call back function for specified timer / capture		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None                                                                            		   */
/*               			                                                                          	   */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to iNnstall the PWM timer/capture interrupt call back function      */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_InstallCallBack(
	UINT8 u8Timer,
	PFN_PWM_CALLBACK pfncallback,
	PFN_PWM_CALLBACK *pfnOldcallback
)
{
	switch(u8Timer)
	{	
		case PWM_TIMER0:
		case PWM_CAP0:			
		    if(pfncallback != NULL)
		    {
		    	if(u8Timer & 0x10)
		    	{
		    		*pfnOldcallback = pfnPWMHandler.pfnCAP0CallBack;
		       	    pfnPWMHandler.pfnCAP0CallBack = pfncallback;
		       	}
		       	else
		       	{
		       		*pfnOldcallback = pfnPWMHandler.pfnPWM0CallBack;
		       		pfnPWMHandler.pfnPWM0CallBack = pfncallback;
		       	}
	    	}
			break;
		case PWM_TIMER1:
		case PWM_CAP1:		
		    if(pfncallback != NULL)
		    {
		    	if(u8Timer & 0x10)
		    	{
		    		*pfnOldcallback = pfnPWMHandler.pfnCAP1CallBack; 
		       	    pfnPWMHandler.pfnCAP1CallBack = pfncallback;
		       	}
		       	else
		       	{
		       		*pfnOldcallback = pfnPWMHandler.pfnPWM1CallBack;
		       		pfnPWMHandler.pfnPWM1CallBack = pfncallback;
		       	}
	    	}		
			break;
		case PWM_TIMER2:
		case PWM_CAP2:
		    if(pfncallback != NULL)
		    {
		    	if(u8Timer & 0x10)
		    	{
		    		*pfnOldcallback = pfnPWMHandler.pfnCAP2CallBack;
		       	    pfnPWMHandler.pfnCAP2CallBack = pfncallback;
		       	}
		       	else
		       	{
		       		*pfnOldcallback = pfnPWMHandler.pfnPWM2CallBack;
		       		pfnPWMHandler.pfnPWM2CallBack = pfncallback;
		       	}
	    	}				
			break;
		case PWM_TIMER3:
		case PWM_CAP3:
		    if(pfncallback != NULL)
		    {
		    	if(u8Timer & 0x10)
		    	{
		    		*pfnOldcallback = pfnPWMHandler.pfnCAP3CallBack;
		       	    pfnPWMHandler.pfnCAP3CallBack = pfncallback;
		       	}
		       	else
		       	{
		       		*pfnOldcallback = pfnPWMHandler.pfnPWM3CallBack; 
		       		pfnPWMHandler.pfnPWM3CallBack = pfncallback;
		       	}
	    	}				

			
			break;									
	}
	
	sysInstallISR(IRQ_LEVEL_1, IRQ_PWM, (PVOID)PWM_ISR);	
	sysSetLocalInterrupt(ENABLE_IRQ);
	sysEnableInterrupt(IRQ_PWM);   	
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_EnableInt		                                                                     	   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3    				   */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3       		 			   */
/*               u8Int	 		- [in]		PWM_CAP_RISING_INT/PWM_CAP_FALLING_INT/PWM_CAP_ALL_INT		   */
/*              					        (The parameter is valid only when capture function)	       	   */
/*               pfncallback	- [in]		The call back function for specified timer / capture		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None                                                                            		   */
/*               			                                                                          	   */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to Enable the PWM timer/capture interrupt 		                   */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_EnableInt(UINT8 u8Timer, UINT8 u8Int)
{
	if(u8Timer & 0x10)
	{		
		if(u8Timer & 0x02)		
			outp32(CCR1, (inp32(CCR1) & ~(0x06 << ((u8Timer & 0x01) << 4 ))) |	((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));					
		else
			outp32(CCR0, (inp32(CCR0) & ~(0x06 << ((u8Timer & 0x01) << 4 ))) |	((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));					
	}
	else
		outp32(PIER,  inp32(PIER) | (1<<u8Timer));
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_DisableInt		  		                                                                   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3      			   */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        					   */
/*               u8Int	 		- [in]		PWM_CAP_RISING_INT/PWM_CAP_FALLING_INT/PWM_CAP_ALL_INT	 	   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None                                                                            		   */
/*               			                                                                          	   */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to clear the PWM timer/capture interrupt 		                   */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_DisableInt(UINT8 u8Timer, UINT8 u8Int)
{   
	if(u8Timer & 0x10)
	{
		if(u8Timer & 0x02)		
			outp32(CCR1, inp32(CCR1) & ~((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));					
		else
			outp32(CCR0, inp32(CCR0) & ~((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));					
		
	}
	else
	{		    
  		outp32(PIER,  inp32(PIER) & ~(1 << (u8Timer & 0x03)));
   		outp32(PIIR,  inp32(PIIR) & ~(1 << (u8Timer & 0x03)));
   	} 
	switch(u8Timer)
	{	
		case PWM_TIMER0:
		case PWM_CAP0:			
       	    pfnPWMHandler.pfnCAP0CallBack = NULL;
       		pfnPWMHandler.pfnPWM0CallBack = NULL;	
			break;
		case PWM_TIMER1:
		case PWM_CAP1:		
       	    pfnPWMHandler.pfnCAP1CallBack = NULL;
       		pfnPWMHandler.pfnPWM1CallBack = NULL;	
			break;
		case PWM_TIMER2:
		case PWM_CAP2:
       	    pfnPWMHandler.pfnCAP2CallBack = NULL;
       		pfnPWMHandler.pfnPWM2CallBack = NULL;	
			break;
		case PWM_TIMER3:
		case PWM_CAP3:
       	    pfnPWMHandler.pfnCAP3CallBack = NULL;
       		pfnPWMHandler.pfnPWM3CallBack = NULL;	
			break;									
	}
	
	
	if(((inp32(PIER) & 0xF) == 0) && ((inp32(CCR0) & 0x60006) == 0) && ((inp32(CCR1) & 0x60006) == 0))
		sysDisableInterrupt(IRQ_PWM);   		 
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_ClearInt		                                                                      	   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3       			   */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        		 			   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None                                                                            		   */
/*               			                                                                          	   */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to clear the PWM timer/capture interrupt 		                   */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_ClearInt(UINT8 u8Timer)
{
	if(u8Timer & 0x10)
	{
		if(u8Timer & 0x02)
			outp32(CCR1, (inp32(CCR1) & 0xF000F) | (1 << (((u8Timer & 0x01) << 4) + 4)));
		else
			outp32(CCR0, (inp32(CCR0) & 0xF000F) | (1 << (((u8Timer & 0x01) << 4) + 4)));			
	}
	else
		outp32(PIIR,  inp32(PIIR) & ~(1<<(u8Timer & 0x03)));
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetIntFlag				                                                         	       */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3  			       */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        					   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               0		FALSE                                                                              */
/*               1		TRUE		                                                                       */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get the PWM timer/capture interrupt flag 		                   */
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_GetIntFlag(UINT8 u8Timer)
{
	if(u8Timer & 0x10)
	{
		if(u8Timer & 0x02)
		{	
			if(inp32(CCR1) & (1 << (((u8Timer & 0x01) << 4) + 4)))
				return TRUE;
			else
				return FALSE;
		}
		else
		{  	
	 		if(inp32(CCR0) & (1 << (((u8Timer & 0x01) << 4) + 4)))
				return TRUE;
			else
				return FALSE;
		}		
	}
	else
	{
		if(inp32(PIIR) & (1<<(u8Timer & 0x03)))
			return TRUE;
		else
			return FALSE;
	}		
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetRisingCounter				    	                                                   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Capture 		- [in]		PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3	      			 		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               The value which latches the counter when there¡¦s a rising transition                      */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get value which latches the counter when there¡¦s a rising 	   */		
/*				 transition		                   														   */
/*---------------------------------------------------------------------------------------------------------*/
UINT16 PWM_GetRisingCounter(UINT8 u8Capture)
{
	return inp32(CRLR0 + ((u8Capture & 0x7) << 3));
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetFallingCounter				                     	                                   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Capture 		- [in]		PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3	    			   		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               The value which latches the counter when there¡¦s a falling transition                     */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get value which latches the counter when there¡¦s a falling 	   */		
/*				 transition		                   														   */
/*---------------------------------------------------------------------------------------------------------*/
UINT16 PWM_GetFallingCounter(UINT8 u8Capture)
{
	return inp32(CFLR0 + ((u8Capture & 0x7)<< 3));
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetCaptureIntStatus				                                                       */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Capture 		- [in]		PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3	       					   */
/*               u8IntType 		- [in]		PWM_CAP_RISING_FLAG/PWM_CAP_FALLING_FLAG	       			   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               Check if there¡¦s a rising / falling transition                    				     	   */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to get the rising / falling transition interrupt flag			   */		
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_GetCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType)
{	
	if(u8Capture & 0x02)
	{
		if(inp32(CCR1) &  (1 << (((u8Capture & 0x01) << 4) + u8IntType)))
			return TRUE;
		else 
			return FALSE;
    }
    else
    {
		if(inp32(CCR0) &  (1 << (((u8Capture & 0x01) << 4) + u8IntType)))
			return TRUE;
		else 
			return FALSE;
    }
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_ClearCaptureIntStatus				                                                 	   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Capture 		- [in]		PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3	       		 			   */
/*               u8IntType 		- [in]		PWM_CAP_RISING_FLAG/PWM_CAP_FALLING_FLAG	       			   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               Clear the rising / falling transition interrupt flag	                    		       */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to clear the rising / falling transition interrupt flag		 	   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_ClearCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType)
{
	if(u8Capture & 0x02)
		outp32(CCR1, (inp32(CCR1) & 0xF000F) | (1 << (((u8Capture & 0x01) << 4) + u8IntType)));
	else
		outp32(CCR0, (inp32(CCR0) & 0xF000F) | (1 << (((u8Capture & 0x01) << 4) + u8IntType)));
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Open				                                                   					   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               None             											                               */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None 											                    		       		   */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               Enable PWM engine clock and reset PWM											 	   	   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Open(void)
{ 

	g_u32PwmHz = EXTERNAL_CRYSTAL_CLOCK;
		
	outp32(REG_CLKDIV5, (inp32(REG_CLKDIV5) & ~(PWM_N1|PWM_S|PWM_N0)));	
						
	outp32(REG_APBCLK, inp32(REG_APBCLK)|PWM_CKE);
	outp32(REG_APBIPRST, PWMRST);
	outp32(REG_APBIPRST, inp32(REG_APBIPRST) & ~PWMRST);	
	
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetClockSetting		                                                   				   */
/* Parameters:                                                                                             */
/*               eSrcClk 		- [in]		eSYS_EXT/eSYS_APLL/eSYS_UPLL				     			   */
/*               u32PllDiver 	- [in]		1~8	(Only be valid when eSrcClk is eSYS_APLL or eSYS_UPLL)	   */
/*               u32EngineDiver - [in]		1~256											     		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None											                    		               */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to set PWM engine clock source and divier 						   */		
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_SetClockSetting(E_SYS_SRC_CLK eSrcClk, UINT32 u32PllDiver, UINT32 u32EngineDiver)
{
	UINT32 u32Source, u32Clock;	
	 			
	switch(eSrcClk)
	{
		case eSYS_EXT:
			u32Source = 0;
			break;
		case eSYS_MPLL:
			u32Source = 0x08;
			break;
		case eSYS_APLL:
			u32Source = 0x10;
			break;
		case eSYS_UPLL:
			u32Source = 0x18; 
			break;	
		default:		
			return FALSE;			
	}
	if(u32PllDiver > 8)
		return FALSE;
	if(u32EngineDiver > 256)	
		return FALSE;
		
	if(eSrcClk == eSYS_EXT)
		outp32(REG_CLKDIV5, (inp32(REG_CLKDIV5) & ~(PWM_N1|PWM_S|PWM_N0)) | (u32Source | ((u32EngineDiver -1) << 5)));		
	else
		outp32(REG_CLKDIV5, (inp32(REG_CLKDIV5) & ~(PWM_N1|PWM_S|PWM_N0)) | (u32Source | ((u32EngineDiver -1) << 5) | (u32PllDiver - 1)));	
		
	u32Clock = EXTERNAL_CRYSTAL_CLOCK;
	
	if(eSrcClk == eSYS_EXT)
		g_u32PwmHz = u32Clock / u32EngineDiver;				
	else
	{
		g_u32PwmHz = sysGetPLLOutputHz(eSrcClk, u32Clock) / u32EngineDiver / u32PllDiver;	
	
	}
	return TRUE;
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetEngineClock		                                                   					   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               *eSrcClk 		- [out]		Get the Engine clock source (eSYS_EXT/eSYS_APLL/eSYS_UPLL)	   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               PWM engine Clock (kHz)							                    		       		   */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               Get Current PWM engine clock															   */		
/*---------------------------------------------------------------------------------------------------------*/
UINT32 PWM_GetEngineClock(E_SYS_SRC_CLK* peSrcClk)
{
	UINT32 u32Source = (inp32(REG_CLKDIV5) & PWM_S) >> 3;
	
	switch(u32Source)
	{
		case 0:
			*peSrcClk = eSYS_EXT;
			break;
		case 1:
			*peSrcClk = eSYS_MPLL;
			break;
		case 2:
			*peSrcClk = eSYS_APLL;
			break;
		case 3:
			*peSrcClk = eSYS_UPLL;
			break;	
	}

	return g_u32PwmHz;
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Close				                                                   					   */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               None             											                               */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None 											                    		       		   */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               Disable PWM engine clock and the I/O enable											   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Close(void)
{
	outp32(POE, 0);
	outp32(CAPENR,0x0);
   	sysDisableInterrupt(IRQ_PWM);
	outp32(REG_APBCLK, inp32(REG_APBCLK) & ~PWM_CKE);
	
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_EnableDeadZone				                               		              		       */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3     			   */
/*               u8Length 		- [in]		Dead Zone Length : 0~255				       		   		   */
/*               bEnableDeadZone- [in]		Enable DeadZone (TRUE) / Diasble DeadZone (FALSE)     		   */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None											                    		               */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to set the dead zone length and enable/disable Dead Zone function   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_EnableDeadZone(UINT8 u8Timer, UINT8 u8Length,BOOL bEnableDeadZone)
{
	if(u8Timer & 0x02)
	{
		outp32(PPR, (inp32(PPR) & ~DZI1) | ((u8Length & 0xFF) << 24));
		outp32(PCR, (inp32(PCR) & ~DZEN1) | (bEnableDeadZone?DZEN1:0));			
	}
	else
	{
		outp32(PPR, (inp32(PPR) & ~DZI0) | ((u8Length & 0xFF) << 16));				
		outp32(PCR, (inp32(PCR) & ~DZEN0) | (bEnableDeadZone?DZEN0:0));		
	}	
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Enable				                            		                 			       */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3     			   */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        					   */
/*               bEnable		- [in]		Enable  (TRUE) / Disable  (FALSE)     					       */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None											                    		               */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to enable PWM timer / capture function					 		   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Enable(UINT8 u8Timer,BOOL bEnable)
{
	outp32(PCR, (inp32(PCR)& ~(1 << ((u8Timer & 0x07) << 3) )) | (bEnable?(1 << ((u8Timer & 0x07) << 3) ):0) );
	
	if(u8Timer & 0x10)
	{
		if(u8Timer & 0x02)
			outp32(CCR1, (inp32(CCR1)& ~(1 << (((u8Timer & 0x01) << 4) + 3))) | (bEnable?(1 << (((u8Timer & 0x01) << 4) + 3)):0));	
		else
			outp32(CCR0, (inp32(CCR0)& ~(1 << (((u8Timer & 0x01) << 4) + 3))) | (bEnable?(1 << (((u8Timer & 0x01) << 4) + 3)):0));
	}
}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerClk					                                             		       */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 						PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3   	  		   */
/*         										PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        				   */
/*				 PWM_TIME_DATA_T *sPt																	   */
/*               	u8Frequency					Frequency   					       					   */
/*               	u8HighPulseRatio			High Pulse Ratio    					       			   */
/*               	u8Mode						PWM_ONE_SHOT_MODE / PWM_TOGGLE_MODE 					   */
/*               	bInverter					Inverter Enable  (TRUE) / Inverter Disable  (FALSE)        */
/*               	u8ClockSelector				Clock Selector											   */
/*              								PWM_CLOCK_DIV_1/PWM_CLOCK_DIV_2/PWM_CLOCK_DIV_4   		   */
/*              								PWM_CLOCK_DIV_8/PWM_CLOCK_DIV_16						   */
/*												(The parameter takes effect when u8Frequency = 0)		   */
/*               	u16PreScale					Prescale (2 ~ 256)										   */ 
/*												(The parameter takes effect when u8Frequency = 0)		   */
/*               	u32Duty						Pulse duty										           */                             
/*												(The parameter takes effect when u8Frequency = 0 or		   */
/*												u8Timer = PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3)			   */	
/*              											                                        	   */
/* Returns:                                                                                                */
/*               The actual frequency											                           */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to configure the frequency/pulse/mode/inverter function		       */		
/*---------------------------------------------------------------------------------------------------------*/

FLOAT PWM_SetTimerClk(UINT8 u8Timer, PWM_TIME_DATA_T *sPt)
{
	FLOAT 	fFrequency;
	UINT16	u16Duty;
						
	if(u8Timer & 0x10)	
	{
		if(u8Timer & 0x02)
			outp32(CCR1, (inp32(CCR1) & ~(1 << (((u8Timer & 0x01) << 4)))) | (sPt->bInverter?(1 << ((u8Timer & 0x01) << 4)):0));
		else
			outp32(CCR0, (inp32(CCR0) & ~(1 << (((u8Timer & 0x01) << 4)))) | (sPt->bInverter?(1 << ((u8Timer & 0x01) << 4)):0));
	}
	else
		outp32(PCR, (inp32(PCR) & ~(1 << ((((u8Timer & 0x07)) << 3) + 2) )) |(sPt->bInverter?(1 << (((u8Timer & 0x07) << 3) + 2)):0));	
	
	outp32(PCR, (inp32(PCR) & ~(1 <<(((u8Timer & 0x07) << 3) + 3))) | ( sPt->u8Mode? (1 <<(((u8Timer & 0x07) << 3) + 3)):0));
	
	if(sPt->fFrequency == 0)
	{	
		UINT8	u8Divider;
		
		if(u8Timer & 0x02)	
			outp32(PPR, (inp32(PPR) & ~CP1) | (((sPt->u16PreScale - 1) & 0xFF) << 8));
		else	
			outp32(PPR, (inp32(PPR) & ~CP0) | ((sPt->u16PreScale - 1) & 0xFF));
			
		u8Divider = 1;	
		switch(sPt->u8ClockSelector)
		{
			case PWM_CLOCK_DIV_1:
				u8Divider = 4;
				break;
			case PWM_CLOCK_DIV_2:
				u8Divider = 0;			
				break;			
			case PWM_CLOCK_DIV_4:
				u8Divider = 1;			
				break;			
			case PWM_CLOCK_DIV_8:
				u8Divider = 2;			
				break;			
			case PWM_CLOCK_DIV_16: 
				u8Divider = 3;			
				break;		
		}				
			
		outp32(PWM_CSR, (inp32(PWM_CSR) & ~(0x7 << ((u8Timer & 0x07)<<2) )) | ((u8Divider & 0x7) << ((u8Timer & 0x07)<<2)));	

		
		outp32(CNR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty - 1));			
		outp32(CMR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty * sPt->u8HighPulseRatio / 100 - 1));			
				
		fFrequency = (FLOAT)g_u32PwmHz / sPt->u16PreScale / sPt->u8ClockSelector / sPt->u32Duty;
	}
	else
	{
		UINT8	u8Divider;
		UINT16	u16PreScale;
		
		fFrequency = (FLOAT)  g_u32PwmHz / sPt->fFrequency;		
		
		if(fFrequency > 0x10000000)
			return 0;
			
		u8Divider = 1;			
			
		if(fFrequency < 0x20000)
			u16PreScale = 2;	
		else
		{
			u16PreScale = fFrequency / 65536;	
							
			if(fFrequency / u16PreScale > 65536)
				u16PreScale++;
			
			if(u16PreScale > 256)
			{
				UINT8 u8i;
				u16PreScale = 256;
				fFrequency = fFrequency / u16PreScale;
				
				u8Divider = fFrequency / 65536;				
				
				if(fFrequency / u8Divider > 65536)
					u8Divider++;				
				
				u8i = 0;
				while(1)	
				{
					if((1 << u8i++) > u8Divider)
						break;
				}
				
				u8Divider = 1 << (u8i - 1);
				
				if(u8Divider > 16)
					return 0;	
					
				fFrequency = fFrequency * u16PreScale;						
			}		
					
		}
		u16Duty = (UINT16 )(fFrequency/u16PreScale/u8Divider);
		
		fFrequency = ((FLOAT) g_u32PwmHz / u16PreScale / u8Divider) / u16Duty;	
				
		if(u8Timer & 0x02)	
			outp32(PPR, (inp32(PPR) & ~CP1) | (((u16PreScale - 1) & 0xFF) << 8));
		else	
			outp32(PPR, (inp32(PPR) & ~CP0) | ((u16PreScale - 1) & 0xFF));	
				
		sPt->u8ClockSelector = u8Divider;	
				
		switch(u8Divider)
		{
			case 1:
				u8Divider = 4;
				break;
			case 2:
				u8Divider = 0;			
				break;			
			case 4:
				u8Divider = 1;			
				break;			
			case 8:
				u8Divider = 2;			
				break;			
			case 16:
				u8Divider = 3;			
				break;		
		}		
		
		sPt->u16PreScale = u16PreScale;		
							
		outp32(PWM_CSR, (inp32(PWM_CSR) & ~(0x7 << ((u8Timer & 0x07)<<2) )) | ((u8Divider & 0x7) << ((u8Timer & 0x07)<<2)));	
		
		if(u8Timer & 0x10)
		{			
			if(sPt->u32Duty != 0)
			{
				outp32(CNR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty - 1));
				outp32(CMR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty * sPt->u8HighPulseRatio / 100 - 1));			
			}
			else
			{
				outp32(CNR0 + (u8Timer & 0x07) * 12, (u16Duty - 1));
				outp32(CMR0 + (u8Timer & 0x07) * 12, (u16Duty * sPt->u8HighPulseRatio / 100 - 1));				
			}
		}
		else
		{	
			outp32(CNR0 + (u8Timer & 0x07) * 12, (u16Duty - 1));	
			sPt->u32Duty = u16Duty;		
			outp32(CMR0 + (u8Timer & 0x07) * 12, (u16Duty * sPt->u8HighPulseRatio / 100 - 1));			
		}
	}
	
	return fFrequency;

}


/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerIO					                                             		           */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*               u8Timer 		- [in]		PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3   				   */
/*         									PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3        		 			   */
/*               bEnable		- [in]		Enable  (TRUE) / Diasble  (FALSE)     					       */
/*              											                                        	   */
/* Returns:                                                                                                */
/*               None											                    		               */
/*               							                                                               */
/* Side effects:                                                                                           */
/* Description:                                                                                            */
/*               This function is used to enable/disable PWM timer / capture I/O function				   */		
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_SetTimerIO(UINT8 u8Timer, BOOL bEnable)
{
	
	if(bEnable)
	{
		if(u8Timer & 0x10)
			outp32(CAPENR, inp32(CAPENR)  | (1 << (u8Timer & 0x07)));			
		else
			outp32(POE, inp32(POE)  | (1 << (u8Timer & 0x07)));	
			
		outp32(REG_GPDFUN0, (inp32(REG_GPDFUN0) & ~(0xF << ((u8Timer & 0x07) * 4))) | (0x2 << ((u8Timer & 0x07) * 4)));
			
	}
	else
	{
		if(u8Timer & 0x10)			
			outp32(CAPENR, inp32(CAPENR) & ~(1 << (u8Timer & 0x07)));			
		else
			outp32(POE, inp32(POE) & ~(1 << (u8Timer & 0x07)));
		outp32(REG_GPDFUN0, (inp32(REG_GPDFUN0) & ~(0xF << ((u8Timer & 0x07) * 4))));	
	}
}

