/*
 * File:        ccm.c
 * Purpose:     Provide common CCM support
 *
 * Notes:       
 *              
 */

#include "ccm.h"

/***************************************************************************************************/
/* Function: 		set_ccgr_register
 * Input:			clock_gate_index (0-191), clk_gate_value (0, 1, 2, 3)
 * Return:			none
 * Description:
 *
 * Example Usage:
 * set_ccgr_register(ADC0_CCGR_INDEX, CLK_ON_ALL_MODES);	//Enable ADC0
 *
 * Define for translating CCM CCGRx index into bit positions for respective CCGRx register
 * Two bits define the clock gating for each module.  16 per register.
 * There are 12 CCGR registers, CCGR[0-11]
 * For example
 * CCGR0.CG0 ----> CGR0.CG15 are index 0-16
 * CCGR0.CG16 ----> CCGR1.CG31 are index 17-31
 * ... etc ...
 * CCGR11.CG176 -> CCGR11.CG191 are index 176-191
 *
 * Possible clk_gate_value values:
 * #define CLK_OFF_ALL_MODES               0x0
 * #define CLK_ON_RUN_OFF_WAIT_STOP_MODES  0x1
 * #define CLK_ON_ALL_MODES                0x2
 * #define CLK_ON_ALL_MODES_EXCEPT_STOP    0x3
 *
 ***************************************************************************************************/
void set_ccgr_register(uint32_t clock_gate_index, uint32_t clk_gate_value)
{
	/* Check that input parameters are in range */
	if ((clock_gate_index > 191) || (clk_gate_value > 3))
	{
		return;
	}

	/* Now assign CCGRx register based on index.  Clear the bitfield (two bits - 0x3) then set it */
	if (clock_gate_index < 16)
	{
		CCM->CCGR0 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR0 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 32)
	{
		clock_gate_index = clock_gate_index - 16;
		CCM->CCGR1 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR1 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 48)
	{
		clock_gate_index = clock_gate_index - 32;
		CCM->CCGR2 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR2 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 64)
	{
		clock_gate_index = clock_gate_index - 48;
		CCM->CCGR3 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR3 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 80)
	{
		clock_gate_index = clock_gate_index - 64;
		CCM->CCGR4 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR4 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 96)
	{
		/* Skip 80-95 - CCGR5 is reserved */
	}
	else if (clock_gate_index < 112)
	{
		clock_gate_index = clock_gate_index - 96;
		CCM->CCGR6 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR6 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 128)
	{
		clock_gate_index = clock_gate_index - 112;
		CCM->CCGR7 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR7 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 144)
	{
		clock_gate_index = clock_gate_index - 128;
		CCM->CCGR8 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR8 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 160)
	{
		clock_gate_index = clock_gate_index - 144;
		CCM->CCGR9 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR9 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 176)
	{
		clock_gate_index = clock_gate_index - 160;
		CCM->CCGR10 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR10 |= (clk_gate_value << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 191)
	{
		clock_gate_index = clock_gate_index - 176;
		CCM->CCGR11 &= ~(0x3 << (clock_gate_index * 2));
		CCM->CCGR11 |= (clk_gate_value << (clock_gate_index * 2));
	}
}

/***************************************************************************************************/
/* Function: 		clear_ccgr_register
 * Input:			clock gate index
 * Return:			none
 * Description:
 *
 * Turns OFF clock to module
 * Based on index of CCM->CCGRx registers
 * Simply pass in the index and the clock will be disabled by writing 0b00 to the bit position
 *
 ***************************************************************************************************/
void clear_ccgr_register(uint32_t clock_gate_index)
{
	if (clock_gate_index > 191)
	{
		/* expecting 0-191 */
		return;
	}

	/* Now assign CCGRx register based on index */
	/* No bit fields in header definition so we are doing it this way for ease of use */
	if (clock_gate_index < 16)
	{
		CCM->CCGR0 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 32)
	{
		clock_gate_index = clock_gate_index - 16;
		CCM->CCGR1 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 48)
	{
		clock_gate_index = clock_gate_index - 32;
		CCM->CCGR2 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 64)
	{
		clock_gate_index = clock_gate_index - 48;
		CCM->CCGR3 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 80)
	{
		clock_gate_index = clock_gate_index - 64;
		CCM->CCGR4 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 96)
	{
		/* Skip 80-95 - CCGR5 is reserved */
	}
	else if (clock_gate_index < 112)
	{
		clock_gate_index = clock_gate_index - 96;
		CCM->CCGR6 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 128)
	{
		clock_gate_index = clock_gate_index - 112;
		CCM->CCGR7 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 144)
	{
		clock_gate_index = clock_gate_index - 128;
		CCM->CCGR8 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 160)
	{
		clock_gate_index = clock_gate_index - 144;
		CCM->CCGR9 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 176)
	{
		clock_gate_index = clock_gate_index - 160;
		CCM->CCGR10 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
	else if (clock_gate_index < 191)
	{
		clock_gate_index = clock_gate_index - 176;
		CCM->CCGR11 &= (uint32_t)~(0x3 << (clock_gate_index * 2));
	}
}

/***************************************************************************************************/
/* Function: 		read_ccgr_value
 * Input:			clock gate index
 * Return:			two bit clock setting for that module
 *  				Possible clk_gate_value values:
 * 					#define CLK_OFF_ALL_MODES               0x0
 * 					#define CLK_ON_RUN_OFF_WAIT_STOP_MODES  0x1
 * 					#define CLK_ON_ALL_MODES                0x2
 * 					#define CLK_ON_ALL_MODES_EXCEPT_STOP    0x3
 * Description:
 *
 * Returns two bits for clock gate configuration
 * Based on index of CCM->CCGRx registers
 * The function will return the two bits, just pass in the clock gate index (see CCM CCGRx definition)
 *
 ***************************************************************************************************/
uint32_t read_ccgr_value(uint32_t clock_gate_index)
{
	uint32_t clk_setting;

	if (clock_gate_index > 191)
	{
		/* expecting 0-191 */
		return 0xFAFAFAFA;
	}

	/* Now assign CCGRx register based on index */
	/* No bit fields in header definition so we are doing it this way for ease of use */
	if (clock_gate_index < 16)
	{
		clk_setting = (((uint32_t)(CCM->CCGR0)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 32)
	{
		clock_gate_index = clock_gate_index - 16;
		clk_setting = (((uint32_t)(CCM->CCGR1)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 48)
	{
		clock_gate_index = clock_gate_index - 32;
		clk_setting = (((uint32_t)(CCM->CCGR2)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 64)
	{
		clock_gate_index = clock_gate_index - 48;
		clk_setting = (((uint32_t)(CCM->CCGR3)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 80)
	{
		clock_gate_index = clock_gate_index - 64;
		clk_setting = (((uint32_t)(CCM->CCGR4)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 96)
	{
		/* Skip 80-95 - CCGR5 is reserved */
	}
	else if (clock_gate_index < 112)
	{
		clock_gate_index = clock_gate_index - 96;
		clk_setting = (((uint32_t)(CCM->CCGR6)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 128)
	{
		clock_gate_index = clock_gate_index - 112;
		clk_setting = (((uint32_t)(CCM->CCGR7)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 144)
	{
		clock_gate_index = clock_gate_index - 128;
		clk_setting = (((uint32_t)(CCM->CCGR8)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 160)
	{
		clock_gate_index = clock_gate_index - 144;
		clk_setting = (((uint32_t)(CCM->CCGR9)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 176)
	{
		clock_gate_index = clock_gate_index - 160;
		clk_setting = (((uint32_t)(CCM->CCGR10)) & (~0x3 << (clock_gate_index * 2)));
	}
	else if (clock_gate_index < 191)
	{
		clock_gate_index = clock_gate_index - 176;
		clk_setting = (((uint32_t)(CCM->CCGR11)) & (~0x3 << (clock_gate_index * 2)));
	}

	return (clk_setting);
}
