#include "rcc.h"

const uint32_t	Nominal_HS_InternalFrequency	= 16000000UL;
const uint32_t	External_XTAL_Frequency			= 25000000UL;
const uint32_t  SYSCLK_Prescalars[4]			= { 2, 4, 6, 8 };
const uint32_t  AHB_Prescalars[16] 				= { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 };
const uint32_t  APB_Prescalars[8] 				= { 0, 0, 0, 0, 1, 2, 3, 4 };

// Bit definitions for RCC_CR register
enum RCC_CR_Bits {
	RCC_CR_HSI_ON		= REG_BIT_DEFN(  0,  0),
	RCC_CR_HSI_RDY     	= REG_BIT_DEFN(  1,  1),
	RCC_CR_HSI_TRIM		= REG_BIT_DEFN(  3,  7),
	RCC_CR_HSI_CAL		= REG_BIT_DEFN(  8, 15),
	RCC_CR_HSE_ON		= REG_BIT_DEFN( 16, 16),
	RCC_CR_HSE_RDY		= REG_BIT_DEFN( 17, 17),
	RCC_CR_HSE_BYP	    = REG_BIT_DEFN( 18, 18),
	RCC_CR_HSE_CLOCKS	= REG_BIT_DEFN( 16, 18),
	RCC_CR_CSS_ON		= REG_BIT_DEFN( 19, 19),
	RCC_CR_PLL_ON		= REG_BIT_DEFN( 24, 24),
	RCC_CR_PLL_RDY		= REG_BIT_DEFN( 25, 25),
	RCC_CR_PLL_I2S_ON	= REG_BIT_DEFN( 26, 26),
	RCC_CR_PLL_I2S_RDY	= REG_BIT_DEFN( 27, 27)
};

// Bit definitions for RCC_PLLCFGR
enum RCC_PLLCFGR_Bits {
	RCC_PLLCFGR_PLL_M	= REG_BIT_DEFN(  0,  5),
	RCC_PLLCFGR_PLL_N	= REG_BIT_DEFN(  6, 14),
	RCC_PLLCFGR_PLL_P	= REG_BIT_DEFN( 16, 17),
	RCC_PLLCFGR_PLL_SRC	= REG_BIT_DEFN( 22, 22),
	RCC_PLLCFGR_PLL_Q	= REG_BIT_DEFN( 24, 27)
};

// Bit definitions for RCC_CFGR register
enum RCC_CFGR_Bits {
	RCC_CFGR_SW			= REG_BIT_DEFN(  0,  1),
	RCC_CFGR_SWS		= REG_BIT_DEFN(  2,  3),
	RCC_CFGR_H_PRE		= REG_BIT_DEFN(  4,  7),
	RCC_CFGR_P_PRE1		= REG_BIT_DEFN( 10, 12),
	RCC_CFGR_P_PRE2		= REG_BIT_DEFN( 13, 15),
	RCC_CFGR_RTC_PRE	= REG_BIT_DEFN( 16, 20),
	RCC_CFGR_MCO1		= REG_BIT_DEFN( 21, 22),
	RCC_CFGR_I2S_SRC	= REG_BIT_DEFN( 23, 23),
	RCC_CFGR_MCO1_PRE	= REG_BIT_DEFN( 24, 26),
	RCC_CFGR_MCO2_PRE	= REG_BIT_DEFN( 27, 29),
	RCC_CFGR_MCO2		= REG_BIT_DEFN( 30, 31)
};

// Bit definitions for RCC_CIR register
enum RCC_CIR_Bits {
	RCC_CIR_LSI_RDYF		= (1 <<  0),
	RCC_CIR_LSE_RDYF        = (1 <<  1),
	RCC_CIR_HSI_RDYF		= (1 <<  2),
	RCC_CIR_HSE_RDYF		= (1 <<  3),
	RCC_CIR_PLL_RDYF		= (1 <<  4),
	RCC_CIR_PLL_I2S_RDYF	= (1 <<  5),
	RCC_CIR_CSSF            = (1 <<  7),
	RCC_CIR_LSI_RDY_IE      = (1 <<  8),
	RCC_CIR_LSE_RDY_IE		= (1 <<  9),
	RCC_CIR_HSI_RDY_IE      = (1 << 10),
	RCC_CIR_HSE_RDY_IE      = (1 << 11),
	RCC_CIR_PLL_RDY_IE      = (1 << 12),
	RCC_CIR_PLL_I2S_RDY_IE  = (1 << 13),
	RCC_CIR_LSI_RDYC        = (1 << 16),
	RCC_CIR_LSE_RDYC        = (1 << 17),
	RCC_CIR_HSI_RDYC        = (1 << 18),
	RCC_CIR_HSE_RDYC		= (1 << 19),
	RCC_CIR_PLL_RDYC		= (1 << 20),
	RCC_CIR_PLL_I2S_RDYC    = (1 << 21),
	RCC_CIR_CSSC            = (1 << 23)
};

// Bit definitions for RCC_BDCR register
enum RCC_BDCR_Bits {
	RCC_BDCR_LSE_ON			= REG_BIT_DEFN(  0,  0),
	RCC_BDCR_LSE_RDY		= REG_BIT_DEFN(  1,  1),
	RCC_BDCR_LSE_BYP		= REG_BIT_DEFN(  2,  2),
	RCC_BDCR_LSE_CLOCKS		= REG_BIT_DEFN(  0,  2),
	RCC_BDCR_RTC_SEL		= REG_BIT_DEFN(  8,  9),
	RCC_BDCR_RTC_EN			= REG_BIT_DEFN( 15, 15),
	RCC_BDCR_BD_RST			= REG_BIT_DEFN( 16, 16)
};

// Bit definitions for RCC_CSR register
enum RCC_CSR_Bits {
	RCC_CSR_LSI_ON			= (1 <<  0),
	RCC_CSR_LSI_RDY			= (1 <<  1),
	RCC_CSR_RMVF			= (1 << 24),
	RCC_CSR_BORRSTF			= (1 << 25),
	RCC_CSR_PADRSTF			= (1 << 26),
	RCC_CSR_PORRSTF			= (1 << 27),
	RCC_CSR_SFTRSTF			= (1 << 28),
	RCC_CSR_WDGRSTF			= (1 << 29),
	RCC_CSR_WWDGRSTF		= (1 << 30),
	RCC_CSR_LPWRRSTF		= (1 << 31)
};

typedef bitwise_enum<RCC_CSR_Bits> CSR_Bits;

// Bit definitions for RCC_SSCGR register
enum RCC_SSCGR_Bits {
	RCC_SSCGR_MODPER		= REG_BIT_DEFN(  0, 12),
	RCC_SSCGR_INCSTEP		= REG_BIT_DEFN( 13, 27),
	RCC_SSCGR_SPREADSEL		= REG_BIT_DEFN( 30, 30),
	RCC_SSCGR_SSCGEN		= REG_BIT_DEFN( 31, 31)
};

// Bit definitions for RCC_PLLI2SCFGR register
enum RCC_PLLI2SCFGR_Bits {
	RCC_PLLI2SCFGR_PLLI2SN	= REG_BIT_DEFN(  6, 13),
	RCC_PLLI2SCFGR_PLLI2SR	= REG_BIT_DEFN( 28, 30)
};

RCC::~RCC(void)
{
  // Set HSION bit
  CR |= (uint32_t)0x00000001;

  // Reset CFGR register
  CFGR = 0x00000000;

  // Reset HSEON, CSSON and PLLON bits
  CR &= (uint32_t)0xFEF6FFFF;

  // Reset PLLCFGR register
  PLLCFGR = 0x24003010;

  // Reset HSEBYP bit
  CR &= (uint32_t)0xFFFBFFFF;

  // Disable all interrupts
  CIR = 0x00000000;
}

void RCC::Configure_HS_ExternalOscillator(HS_ExternalOscillatorState state)
{
	bitWrite(CR, RCC_CR_HSE_CLOCKS, HSE_OFF);	// Disable the H/S external oscillator
	bitWrite(CR, RCC_CR_HSE_CLOCKS, state);    // Configure it as specified
}

bool RCC::Is_HS_ExternalOscillatorReady(uint32_t timeout)
{
	uint32_t counter = 0;
	uint32_t clockReady;
	do {
		clockReady = bitRead(CR, RCC_CR_HSE_RDY);
	} while ((counter++ != timeout) && (!clockReady));
	return (clockReady) ? true : false;
}

void RCC::Configure_HS_InternalOscillator(HS_InternalOscillatorState state)
{
	bitWrite(CR, RCC_CR_HSI_ON, state);
}

void RCC::Adjust_HS_InternalOscillatorTrim(uint32_t trim)
{
	bitWrite(CR, RCC_CR_HSI_TRIM, trim);
}

bool RCC::Is_HS_InternalOscillatorReady(uint32_t timeout)
{
	uint32_t counter = 0;
	uint32_t clockReady;
	do {
		clockReady = bitRead(CR, RCC_CR_HSI_RDY);
	} while ((counter++ != timeout) && (!clockReady));
	return (clockReady) ? true : false;
}

void RCC::Configure_LS_ExternalOscillator(LS_ExternalOscillatorState state)
{
	bitWrite(BDCR, RCC_BDCR_LSE_CLOCKS, 0);
	bitWrite(BDCR, RCC_BDCR_LSE_CLOCKS, state);
}
bool RCC::Is_LS_ExternalOscillatorReady(uint32_t timeout)
{
	uint32_t counter = 0;
	uint32_t clockReady;
	do {
		clockReady = bitRead(BDCR, RCC_BDCR_LSE_RDY);
	} while ((counter++ != timeout) && (!clockReady));
	return (clockReady) ? true : false;
}

void RCC::Initialize_PLL(PLL_ClockSources clksrc, uint32_t prescalar_M, uint32_t multiplier_N,
		                 PLL_Divisor pll_P, uint32_t  OTG_FS_SDIO_RNG_divisor_Q)
{
	uint32_t temp = PLLCFGR;
	bitWrite(temp, RCC_PLLCFGR_PLL_SRC, clksrc);
	bitWrite(temp, RCC_PLLCFGR_PLL_M,   prescalar_M);
	bitWrite(temp, RCC_PLLCFGR_PLL_N,   multiplier_N);
	bitWrite(temp, RCC_PLLCFGR_PLL_P,   pll_P);
	bitWrite(temp, RCC_PLLCFGR_PLL_Q,   OTG_FS_SDIO_RNG_divisor_Q);
	PLLCFGR = temp;
}

void RCC::Configure_PLL(PLL_State state)
{
	bitWrite(CR, RCC_CR_PLL_ON, state);
}
bool RCC::Is_PLL_Ready(uint32_t timeout)
{
	uint32_t counter = 0;
	uint32_t clockReady;
	do {
		clockReady = bitRead(CR, RCC_CR_PLL_RDY);
	} while ((counter++ != timeout) && (!clockReady));
	return (clockReady) ? true : false;
}

void RCC::Configure_I2S_PLL(I2S_PLL_State state)
{
	bitWrite(CR, RCC_CR_PLL_I2S_ON, state);
}

bool RCC::Is_I2S_PLL_Ready(uint32_t timeout)
{
	uint32_t counter = 0;
	uint32_t clockReady;
	do {
		clockReady = bitRead(CR, RCC_CR_PLL_I2S_RDY);
	} while ((counter++ != timeout) && (!clockReady));
	return (clockReady) ? true : false;

}

void RCC::ConfigureClockSecurity(ClockSecurityState css)
{
	bitWrite(CR, RCC_CR_CSS_ON, css);
}

void RCC::ConfigureMCO1(MCO1_ClockSource clksrc, uint32_t divisor)
{
	uint32_t temp;
	temp = CFGR;
	bitWrite(temp, RCC_CFGR_MCO1, clksrc);
	bitWrite(temp, RCC_CFGR_MCO1_PRE, divisor);
	CFGR = temp;
}

void RCC::ConfigureMCO2(MCO2_ClockSource clksrc, uint32_t divisor)
{
	uint32_t temp;
	temp = CFGR;
	bitWrite(temp, RCC_CFGR_MCO2, clksrc);
	bitWrite(temp, RCC_CFGR_MCO2_PRE, divisor);
	CFGR = temp;

}

void RCC::SetSystemClockSource(SystemClockSources clksrc)
{
	bitWrite(CFGR, RCC_CFGR_SW, clksrc);
}

RCC::SystemClockSources RCC::GetSystemClockSource(void)
{
	return static_cast<SystemClockSources>(bitRead(CFGR, RCC_CFGR_SWS));
}

void RCC::Select_AHB_ClockDivider(SYSCLK_Divisor divisor)
{
	bitWrite(CFGR, RCC_CFGR_H_PRE, divisor);
}

void RCC::Select_APB1_ClockDivider(uint32_t divisor)
{
	bitWrite(CFGR, RCC_CFGR_P_PRE1, divisor);
}

void RCC::Select_APB2_ClockDivider(uint32_t divisor)
{
	bitWrite(CFGR, RCC_CFGR_P_PRE2, divisor);
}

void RCC::GetClocks(uint32_t& SYSCLK_InHz , uint32_t& AHB_ClockInHz,
		            uint32_t& APB1_ClockInHz, uint32_t& APB2_ClockInHz)
{
	uint32_t pllsource, pllvco, pllm, plln, pllp;
	SystemClockSources sc;
	sc = GetSystemClockSource();
	switch (sc) {
		case Internal :
			SYSCLK_InHz = Nominal_HS_InternalFrequency;
			break;

		case External :
			SYSCLK_InHz = External_XTAL_Frequency;
			break;

		case PhaseLockedLoop :
			pllsource = bitRead(PLLCFGR, RCC_CFGR_SW);
			pllvco = (pllsource == Internal) ? Nominal_HS_InternalFrequency : External_XTAL_Frequency;
			pllm = bitRead(PLLCFGR, RCC_PLLCFGR_PLL_M);
			plln = bitRead(PLLCFGR, RCC_PLLCFGR_PLL_N);
			pllp = bitRead(PLLCFGR, RCC_PLLCFGR_PLL_P);
			pllvco = pllvco / pllm;
			pllvco = pllvco * plln;
			SYSCLK_InHz = pllvco / SYSCLK_Prescalars[pllp];
			break;

		default :
			SYSCLK_InHz = Nominal_HS_InternalFrequency;
			break;
	}

	AHB_ClockInHz	= SYSCLK_InHz   >> AHB_Prescalars[bitRead(CFGR, RCC_CFGR_H_PRE)];
	APB1_ClockInHz	= AHB_ClockInHz >> APB_Prescalars[bitRead(CFGR, RCC_CFGR_P_PRE1)];
	APB2_ClockInHz	= AHB_ClockInHz >> APB_Prescalars[bitRead(CFGR, RCC_CFGR_P_PRE2)];

}

void RCC::ResetPeripherals(AHB1_PERIPHERALS_RESET bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB1RSTR |=  bits.value();
	} else {
		AHB1RSTR &= ~bits.value();
	}
}

void RCC::ResetPeripherals(AHB2_PERIPHERALS_RESET bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB2RSTR |=  bits.value();
	} else {
		AHB2RSTR &= ~bits.value();
	}
}

void RCC::ResetPeripherals(AHB3_PERIPHERALS_RESET bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB3RSTR |=  bits.value();
	} else {
		AHB3RSTR &= ~bits.value();
	}
}

void RCC::ResetPeripherals(APB1_PERIPHERALS_RESET bits, BitOperation op)
{
	if (op == ASSERT) {
		APB1RSTR |=  bits.value();
	} else {
		APB1RSTR &= ~bits.value();
	}
}

void RCC::ResetPeripherals(APB2_PERIPHERALS_RESET bits, BitOperation op)
{
	if (op == ASSERT) {
		APB2RSTR |=  bits.value();
	} else {
		APB2RSTR &= ~bits.value();
	}
}

void RCC::EnableClocks(AHB1_PERIPHERALS_ENABLED bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB1ENR |=  bits.value();
	} else {
		AHB1ENR &= ~bits.value();
	}
}

void RCC::EnableClocks(AHB2_PERIPHERALS_ENABLED bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB2ENR |=  bits.value();
	} else {
		AHB2ENR &= ~bits.value();
	}
}

void RCC::EnableClocks(APB3_PERIPHERALS_ENABLED bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB3ENR |=  bits.value();
	} else {
		AHB3ENR &= ~bits.value();
	}
}

void RCC::EnableClocks(APB1_PERIPHERALS_ENABLED bits, BitOperation op)
{
	if (op == ASSERT) {
		APB1ENR |=  bits.value();
	} else {
		APB1ENR &= ~bits.value();
	}
}

void RCC::EnableClocks(APB2_PERIPHERALS_ENABLED bits, BitOperation op)
{
	if (op == ASSERT) {
		APB2ENR |=  bits.value();
	} else {
		APB2ENR &= ~bits.value();
	}
}

void RCC::EnableClocksInSleepMode(AHB1_PERIPHERALS_ENABLED_DURING_SLEEP bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB1LPENR |=  bits.value();
	} else {
		AHB1LPENR &= ~bits.value();
	}
}

void RCC::EnableClocksInSleepMode(AHB2_PERIPHERALS_ENABLED_DURING_SLEEP bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB2LPENR |=  bits.value();
	} else {
		AHB2LPENR &= ~bits.value();
	}
}

void RCC::EnableClocksInSleepMode(AHB3_PERIPHERALS_ENABLED_DURING_SLEEP bits, BitOperation op)
{
	if (op == ASSERT) {
		AHB3LPENR |=  bits.value();
	} else {
		AHB3LPENR &= ~bits.value();
	}
}

void RCC::EnableClocksInSleepMode(APB1_PERIPHERALS_ENABLED_DURING_SLEEP bits, BitOperation op)
{
	if (op == ASSERT) {
		APB1LPENR |=  bits.value();
	} else {
		APB1LPENR &= ~bits.value();
	}
}

void RCC::EnableClocksInSleepMode(APB2_PERIPHERALS_ENABLED_DURING_SLEEP bits, BitOperation op)
{
	if (op == ASSERT) {
		APB2LPENR |=  bits.value();
	} else {
		APB2LPENR &= ~bits.value();
	}
}
