/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/


//#include "x_debug.h"
#include "x_hal_io.h"
#include "x_ckgen.h"
#include "pdwnc_pwm.h"

#include "hw_pdwnc.h"

#if defined(CC_SUPPORT_PDWNC_PWM)

#define PDWNC_PD_PWMC0(X) ((X==0)?PDWNC_PD_PWM0C0:((X==1)?PDWNC_PD_PWM1C0:((X==2)?PDWNC_PD_PWM2C0:PDWNC_PD_PWM3C0)))
#define PDWNC_PD_PWMC1(X) ((X==0)?PDWNC_PD_PWM0C1:((X==1)?PDWNC_PD_PWM1C1:((X==2)?PDWNC_PD_PWM2C1:PDWNC_PD_PWM3C1)))


void PDWNC_PwmSetResolution(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC0(u4Path) ,u4Arg,FLD_PWM0RSN);
}

void PDWNC_PwmSetHightPeriod(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC0(u4Path) ,u4Arg,FLD_PWM0H);
}

void PDWNC_PwmSetRepeatCycle(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC0(u4Path) ,u4Arg,FLD_PWM0CYC);
}

void PDWNC_PwmSetAutoEnable(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC0(u4Path) ,u4Arg,FLD_PWM0AUTO);
}

void PDWNC_PwmSetPwmEnable(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC0(u4Path) ,u4Arg,FLD_PWM0E);
}

void PDWNC_PwmSetPwmPrescaler(UINT32 u4Path, UINT32 u4Arg)
{
    vIO32WriteFldAlign(PDWNC_PD_PWMC1(u4Path) ,u4Arg,FLD_PWM0P);
}


//-----------------------------------------------------------------------------
/** PDWNC_PwmSetPwm() set pwm agrument
 *  @param u4Path  pwm0 or pwm1
 *  @param u4Enable enable or disable pwm
 *  @param u4Frequence  pwm frequence, (1hz)
 *  @param u4DutyCycle  pdwm u4DutyCycle, it will be set as u4DutyCycle% high (0~99)
 */
//-----------------------------------------------------------------------------
UINT32 PDWNC_PwmSetPwm(UINT32 u4Path, UINT32 u4Enable,UINT32 u4Frequence, UINT32 u4DutyCycle)
{
	UINT32 u4Factor;
    if(u4Path > PWM_PATH3 )
    {
		return FALSE;
	}
	if(FALSE == u4Enable)
	{
		PDWNC_PwmSetPwmEnable(u4Path,FALSE);
		return TRUE;
	}
	PDWNC_PwmSetResolution(u4Path,255); //fix resolution as 99
	PDWNC_PwmSetHightPeriod(u4Path,(u4DutyCycle));
	// system_clock/(1 + pwmrsn)*(1 + pwmp)  = frequence
	if(IO32ReadFldAlign(PDWNC_PDMODE, FLD_DEEP_SLEEP))// 3Mhz
	{
		u4Factor = 3000000/(100 * u4Frequence) - 1;
	}
	else
	{
		if(IS_XTAL_27MHZ())
		{
			u4Factor = 27000000/(256 * u4Frequence) - 1;
		}
		else if(IS_XTAL_24MHZ())
		{
			u4Factor = 24000000/(256 * u4Frequence) - 1;
		}
		else
		{
			//printf("Set pwm get system clock error \n");
			return FALSE;
		}
	}
	PDWNC_PwmSetPwmPrescaler(u4Path,u4Factor);
	PDWNC_PwmSetPwmEnable(u4Path,TRUE);
	return TRUE;
}


//-----------------------------------------------------------------------------
/** PDWNC_PwmSetPwm() set pwm agrument
 *  @param u4Path  pwm0 or pwm1 use for breathlight
 *  @param u4Enable enable or disable pwm breathlight
 *  @param u4Cycle  breathlight cycle, set unit as 100 ms
 */
//-----------------------------------------------------------------------------
UINT32 PDWNC_PwmSetBreathLight(UINT32 u4Path, UINT32 u4Enable,UINT32 u4Cycle)
{	
    if(u4Path > PWM_PATH3 )
    {
		return FALSE;
	}
	if(FALSE == u4Enable)
	{
		PDWNC_PwmSetPwmEnable(u4Path,FALSE);
		return TRUE;
	}
	PDWNC_PwmSetRepeatCycle(u4Path,(u4Cycle-1));
	PDWNC_PwmSetPwm(u4Path,u4Enable,1000,50);
	PDWNC_PwmSetAutoEnable(u4Path,TRUE);
	return TRUE;
}

#endif


