//
#ifndef GCLOCKS_LIB
#define GCLOCKS_LIB

#include "SPI_lib.h"


void set32kClk(){
	OSC32KCTRL->OSC32K.bit.STARTUP = 0x5;
	OSC32KCTRL->OSC32K.bit.EN1K = 0;
	OSC32KCTRL->OSC32K.bit.EN32K = 1;
	OSC32KCTRL->OSC32K.bit.ONDEMAND = 0;
	uint32_t calib = (*(uint32_t*)(0x806020)>>6);
	calib &= 0x7F;
	OSC32KCTRL->OSC32K.bit.CALIB = calib;
	OSC32KCTRL->OSC32K.bit.ENABLE = 1;
	
	while(!OSC32KCTRL->STATUS.bit.OSC32KRDY);
	//GCLK
}

void enableGCLK1(){
	GCLK->GENCTRL[1].bit.DIV = 1;
	GCLK->GENCTRL[1].bit.DIVSEL = 0;
	GCLK->GENCTRL[1].bit.SRC = 0x04;
	GCLK->GENCTRL[1].bit.RUNSTDBY = 1;
	//GCLK->GENCTRL[1].bit.OE = 1;
	//GCLK->GENCTRL[1].bit.OOV = 1;
	GCLK->GENCTRL[1].bit.GENEN = 1;
	
	while (GCLK->SYNCBUSY.bit.GENCTRL1);
}

void updateBouncerOsc(uint32_t desiredFrequency){
	PORT->Group[0].DIRCLR.reg = PORT_PA16;
	PORT->Group[0].PMUX[8].bit.PMUXE = 0x7;
	PORT->Group[0].PINCFG[16].reg = 0x00;	// DRVSTR - - - - PULLEN INEN PMUXEN
	
	
	uint32_t value = 100000/desiredFrequency;
	
	GCLK->GENCTRL[1].bit.DIV = (uint8_t)value;	
}

void enableBouncerOsc(uint32_t desiredFrequency){
	PORT->Group[0].DIRCLR.reg = PORT_PA16;
	PORT->Group[0].PMUX[8].bit.PMUXE = 0x7;
	PORT->Group[0].PINCFG[16].reg = 0x01;	// DRVSTR - - - - PULLEN INEN PMUXEN
	
	
	uint32_t value = 100000/desiredFrequency;
	uint8_t val8 = (uint8_t)value;
	while (GCLK->SYNCBUSY.bit.GENCTRL2);
	GCLK->GENCTRL[2].bit.GENEN = 0;
	while (GCLK->SYNCBUSY.bit.GENCTRL2);
	
	//GCLK->GENCTRL[2].bit.DIVSEL = 0;
	//GCLK->GENCTRL[2].bit.DIV = (uint8_t)value;			//if DIVSEL == 0 -> fout = fsrc / DIV		8bit DIV for GCLK2-8
	
	//GCLK->GENCTRL[2].bit.SRC = 0x02;		//GCLK 1 - 0x02
	//GCLK->GENCTRL[2].bit.RUNSTDBY = 1;
	//GCLK->GENCTRL[1].bit.OE = 1;
	//GCLK->GENCTRL[1].bit.OOV = 1;
	//GCLK->GENCTRL[2].bit.GENEN = 1;		
	
	if(((value % 2) == 1)){
		GCLK->GENCTRL[2].reg = GCLK_GENCTRL_DIV(val8)
		| GCLK_GENCTRL_OE// | GCLK_GENCTRL_OOV
		| GCLK_GENCTRL_SRC(0x02) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN;	
	} else {
		GCLK->GENCTRL[2].reg = GCLK_GENCTRL_DIV(val8)
		| GCLK_GENCTRL_OE// | GCLK_GENCTRL_OOV
		| GCLK_GENCTRL_SRC(0x02) | GCLK_GENCTRL_GENEN;
	}
	
	while (GCLK->SYNCBUSY.bit.GENCTRL2);
}


void enableGCLK3_32k(){
	GCLK->GENCTRL[3].bit.DIV = 1;
	GCLK->GENCTRL[3].bit.DIVSEL = 0;
	GCLK->GENCTRL[3].bit.SRC = 0x04;
	GCLK->GENCTRL[3].bit.RUNSTDBY = 1;
	//GCLK->GENCTRL[1].bit.OE = 1;
	//GCLK->GENCTRL[1].bit.OOV = 1;
	GCLK->GENCTRL[3].bit.GENEN = 1;
	
	while (GCLK->SYNCBUSY.bit.GENCTRL3);
}

void io_GCLK(){
	PORT->Group[0].DIRSET.reg = PORT_PA15;
	PORT->Group[0].OUTSET.reg = PORT_PA15;
	PORT->Group[0].PINCFG[15].bit.PMUXEN = 0;
	PORT->Group[0].PINCFG[15].bit.PULLEN = 0;
	//PORT->Group[0].PMUX[7].bit.PMUXO = 0x7;
	//PORT->Group[0].PINCFG[15].bit.PMUXEN = 1;
	PORT->Group[0].DIRSET.reg = PORT_PA16;
	PORT->Group[0].OUTSET.reg = PORT_PA16;
	//PORT->Group[0].PMUX[8].bit.PMUXE = 0x7;
	PORT->Group[0].PINCFG[16].bit.PMUXEN = 0;
	PORT->Group[0].PINCFG[16].bit.PULLEN = 0;
}
void enableDFLLctrl(){
	OSCCTRL->DFLLCTRL.bit.WAITLOCK = 0;
	OSCCTRL->DFLLCTRL.bit.BPLCKC = 1;
	OSCCTRL->DFLLCTRL.bit.QLDIS = 0;
	OSCCTRL->DFLLCTRL.bit.CCDIS = 1;
	OSCCTRL->DFLLCTRL.bit.ONDEMAND = 0;
	OSCCTRL->DFLLCTRL.bit.RUNSTDBY = 0;
	OSCCTRL->DFLLCTRL.bit.USBCRM = 0;
	OSCCTRL->DFLLCTRL.bit.LLAW = 0;
	OSCCTRL->DFLLCTRL.bit.STABLE = 0;
	OSCCTRL->DFLLCTRL.bit.MODE = 1;
	OSCCTRL->DFLLCTRL.bit.ENABLE = 0;
	while(!OSCCTRL->STATUS.bit.DFLLRDY);
}

void enableDFLL(){
	uint32_t coarse = (*(uint32_t*)(0x806020)) >> 26;
	uint32_t fine = 512;
	OSCCTRL->DFLLVAL.bit.COARSE = coarse;
	OSCCTRL->DFLLVAL.bit.FINE = fine;
	OSCCTRL->DFLLMUL.bit.CSTEP = coarse >> 1;
	OSCCTRL->DFLLMUL.bit.FSTEP = 0xA;
	OSCCTRL->DFLLMUL.bit.MUL = 46875;
	OSCCTRL->DFLLCTRL.bit.ENABLE = 1;
	while(!OSCCTRL->STATUS.bit.DFLLRDY);
	
	
}
void workaround(){
	GCLK->PCHCTRL[0].bit.WRTLOCK = 0;
	GCLK->PCHCTRL[0].reg = (GCLK_PCHCTRL_CHEN|GCLK_PCHCTRL_GEN(1));
	OSCCTRL->DFLLCTRL.bit.ONDEMAND = 0;
	while(!OSCCTRL->STATUS.bit.DFLLRDY);
}


void XOSC_init(){
	OSCCTRL->XOSCCTRL.bit.GAIN = 0x3;
	OSCCTRL->XOSCCTRL.bit.XTALEN = 1;
	OSCCTRL->XOSCCTRL.bit.STARTUP = 0;
	OSCCTRL->XOSCCTRL.bit.ONDEMAND = 0;
	OSCCTRL->XOSCCTRL.bit.RUNSTDBY = 1;
	OSCCTRL->XOSCCTRL.bit.ENABLE = 1;

	while(!OSCCTRL->STATUS.bit.XOSCRDY);
}

void enableGCLK1XTAL(){
	GCLK->GENCTRL[1].reg = GCLK_GENCTRL_DIV(160)
		| GCLK_GENCTRL_SRC(0x00) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN;
	
	/*
	GCLK->GENCTRL[1].bit.DIV = 160;
	GCLK->GENCTRL[1].bit.DIVSEL = 0;
	GCLK->GENCTRL[1].bit.SRC = 0x00;	//0x00 XOSC
	GCLK->GENCTRL[1].bit.RUNSTDBY = 1;
	*/
	//GCLK->GENCTRL[1].bit.OE = 1;
	//GCLK->GENCTRL[1].bit.OOV = 1;
	//GCLK->GENCTRL[1].bit.GENEN = 1;
	
	while (GCLK->SYNCBUSY.bit.GENCTRL1);
}

void USB_DPLLclkInit(){
	OSCCTRL->DPLLCTRLA.bit.ONDEMAND = 0;
	OSCCTRL->DPLLCTRLA.bit.RUNSTDBY = 1;
	OSCCTRL->DPLLCTRLB.bit.REFCLK = 0x1;	//XOSC 0x1
	OSCCTRL->DPLLCTRLB.bit.DIV = 3;			//fOsc / 2 x ( DIV + 1)  10bit DIV
	OSCCTRL->DPLLRATIO.bit.LDRFRAC = 0;
	OSCCTRL->DPLLRATIO.bit.LDR = 23;			//fOsc = fsrc * (LDR + 1 + LDRFRAC/....)
	OSCCTRL->DPLLPRESC.bit.PRESC = 0x0;
	OSCCTRL->DPLLCTRLA.bit.ENABLE = 1;
	while(!OSCCTRL->DPLLSTATUS.bit.CLKRDY);
}

void enableGCLK4_DPLL(){
	GCLK->GENCTRL[4].bit.DIV = 1;
	GCLK->GENCTRL[4].bit.DIVSEL = 0;
	GCLK->GENCTRL[4].bit.SRC = 0x08;
	GCLK->GENCTRL[4].bit.RUNSTDBY = 1;
	//GCLK->GENCTRL[2].bit.OE = 1;
	//GCLK->GENCTRL[2].bit.OOV = 1;
	GCLK->GENCTRL[4].bit.GENEN = 1;
	
	while (GCLK->SYNCBUSY.bit.GENCTRL4);
}

void switchTo16MHz(){
	GCLK->GENCTRL[0].bit.DIV = 0;
	GCLK->GENCTRL[0].bit.DIVSEL = 1;
	GCLK->GENCTRL[0].bit.SRC = 0x00;
	while (GCLK->SYNCBUSY.bit.GENCTRL0);
}

void DPLL_init(){
	XOSC_init();
	enableGCLK1XTAL();
	USB_DPLLclkInit();
	enableGCLK4_DPLL();
	switchTo16MHz();
	//TC0_init();
}
#endif