// #####   HEADER FILE INCLUDES   ################################################### 

//#include "/vobs/vb_tortola/tortola_projectdir/validation/EVB/src/ccm/hdr/evb_functions.h"
#include "functions.h"
#include "evb_functions.h"

/*
#define MPLL 0x01
#define SPLL 0x02
#define UPLL 0x03
#define FPM_SOURCE_CLK  0x04
#define CKIH_SOURCE_CLK 0x05
#define REF  0x06
#define AHB  0x07
#define ARM  0x08
#define EMI  0x09
#define IPU  0x0a
#define NFC  0x0b
#define HSP  0x0c
#define PER  0x0d
#define CIR1 0x0e
#define CIR2 0x0f
#define CIR3 0x10
#define IPG  0x11
*/



// Enable all 3 PLLs
void plls_enable ()
{
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x00000308);
}

// Enable MPLL
void mpll_enable (){
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x00000008);
}


// Enable SPLL
void spll_enable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x00000100);
}


// Enable UPLL
void upll_enable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x00000200);
}


// Enable FPM
void fpm_enable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x00000001);
}

// Disable MPLL
void mpll_disable (){
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffff7);
}


// Disable SPLL
void spll_disable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffeff);
}


// Disable UPLL
void upll_disable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffdff);
}


// Disable FPM
void fpm_disable (){  
  reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffffe);
}


int set_mpll_to_freq(WORD freq_base){
  int flag = 1;
  WORD freq;

  if ((freq_base > 129) & ( freq_base < 137)) freq = 133;
  else if ((freq_base > 258) & (freq_base < 274)) freq = 266;
       else if ((freq_base > 387) & (freq_base < 411)) freq = 399;
            else if ((freq_base > 516) & (freq_base < 548)) freq = 532;
                 else flag = 0;
  if (flag == 0) {
     #ifdef USE_PRINTF
     printf("\nERROR: freq is out of permitted range - set_mpll_to_freq=0\n");
     #endif
     return flag;
  }
   //Fref=30.5 (32.78)
   //Fref * 2 / PD * (mfi + (mfn/mfd)) = freq
   //0x03162002 : 3 --> PD = 3+1; 16 --> mfd = 22+1; 2 --> mfi = 1000 = 8; 2 --> mfn = 00_0000_0010 = 2
   switch (freq) {
      case 133 :
         reg32_write(CCM_MPCTL,0x0C6E1C67); //pd = 0x11-->4 (0c = 00-00_1100)
         break;
      case 266 :
         reg32_write(CCM_MPCTL,0x046E1C67); //pd = 0x1-->2  (06 = 00-00_0100)
         break;
      case 399 :
         reg32_write(CCM_MPCTL,0x00C714BD);//pd=2, mfi=12(00110000=30), mfn=3, mfd=23(0x16, as always)
         break;
      case 532 :
         reg32_write(CCM_MPCTL,0x006E1C67); // freq == 532
         break;
      default :
         #ifdef USE_PRINTF
         printf("\nERROR: freq is out of permitted range - set_mpll_to_freq=0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}

  

int set_upll_to_freq(WORD freq_base){
  int flag = 1;
  WORD freq;

  if ((freq_base > 129) & ( freq_base < 137)) freq = 133;
  else if ((freq_base > 258) & (freq_base < 274)) freq = 266;
       else if ((freq_base > 387) & (freq_base < 411)) freq = 399;
            else if ((freq_base > 516) & (freq_base < 548)) freq = 532;
                 else if ((freq_base > 465) & (freq_base < 494)) freq = 480;
                      else if ((freq_base > 233) & (freq_base < 247)) freq = 240;
                           else flag = 0;
  if (flag == 0)  {
     #ifdef USE_PRINTF
     printf("\nERROR: freq is out of permitted range - set_upll_to_freq=0\n");
     #endif
     return flag;
  }               
   //Fref=30.5 (32.78)
   //Fref * 2 / PD * (mfi + (mfn/mfd)) = freq
   //0x03162002 : 3 --> PD = 3+1; 16 --> mfd = 22+1; 2 --> mfi = 1000 = 8; 2 --> mfn = 00_0000_0010 = 2
   switch (freq) {
      case 133 :
         reg32_write(CCM_UPCTL,0x0C6E1C67); //pd = 0x11-->4
         break;
      case 266 :
         reg32_write(CCM_UPCTL,0x046E1C67); //pd = 0x1-->2
         break;
      case 399 :
         reg32_write(CCM_UPCTL,0x00C714BD);//pd=2, mfi=12(00110000=30), mfn=3, mfd=23(0x16, as always)
         break;
      case 532 :
         reg32_write(CCM_UPCTL,0x006E1C67); // freq == 532
         break;
      case 480 :
         reg32_write(CCM_UPCTL,0x018F1C3D); //pd=1, mfi=7, mfn=61, mfd=400(0x18f+1)
         break;
      case 240 :
         reg32_write(CCM_UPCTL,0x058F1C3D); //pd=2, mfi=7, mfn=61, mfd=400(0x18f+1)
      default :
         #ifdef USE_PRINTF
         printf("\nERROR: freq is out of permitted range - set_upll_to_freq=0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int set_spll_to_freq(WORD freq_base){  // 3% is permitted
  int flag = 1;
  WORD freq;

  if ((freq_base > 129) & ( freq_base < 137)) freq = 133;
  else if ((freq_base > 258) & (freq_base < 274)) freq = 266;
       else if ((freq_base > 387) & (freq_base < 411)) freq = 399;
            else if ((freq_base > 516) & (freq_base < 548)) freq = 532;
                 else flag = 0;;
  if (flag == 0)  {
     #ifdef USE_PRINTF
     printf("\nERROR: freq is out of permitted range - set_spll_to_freq=0\n");
     #endif
     return flag;
  }
   //Fref=30.5 (32.78)
   //Fref * 2 / PD * (mfi + (mfn/mfd)) = freq
   //0x03162002 : 3 --> PD = 3+1; 16 --> mfd = 22+1; 2 --> mfi = 1000 = 8; 2 --> mfn = 00_0000_0010 = 2
   switch (freq) {
      case 133 :
         //reg32_write(CCM_SPCTL,0x0C6E1C67); //pd = 0x11-->4
         reg32_write(CCM_SPCTL,0x0C6E1C67); //pd = 0x11-->4
         break;
      case 266 :
         //reg32_write(CCM_SPCTL,0x046E1C67); //pd = 0x1-->2
         reg32_write(CCM_SPCTL,0x046E1C67); //pd = 0x1-->2
         break;
      case 399 :
         //reg32_write(CCM_SPCTL,0x00C714BD); //pd=2, mfi=12(00110000=30), mfn=3, mfd=23(0x16, as always)
         reg32_write(CCM_SPCTL,0x00C714BD); //mfd=200, mfn=189, mfi=5
         break;
      case 532 :
         //reg32_write(CCM_SPCTL,0x006E1C67); // freq == 532]
         reg32_write(CCM_SPCTL,0x006E1C67); // freq == 532, mfd=111, mfn=103, mfi=7
         break;
      default :
         #ifdef USE_PRINTF
         printf("\nERROR: freq is out of permitted range - set_spll_to_freq=0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}
  

//Writing to MPCTL/SPCTL/UPCTL register (programming PLL) when the frequency parameters are known.
int write_to_N_pctl(WORD pd, WORD mfd, WORD mfi, WORD mfn, int pll_source){
   WORD input;
   int flag = 1;
   if ((pd>16) || (mfd>1024) || (mfi>16) || (mfn>511)) {
      #ifdef USE_PRINTF
      printf("\nERROR: one of the freq parameters is out of permitted range - write_to_N_pctl = 0\n");
      #endif
      flag = 0;
   }
   if (get_source_for_ref_clk() != FPM_SOURCE_CLK) {
      #ifdef USE_PRINTF
      printf("\nERROR: not FPM is the source clock - write_to_N_pctl = 0\n");
      #endif
      flag = 0;
   }
   if (flag == 0) return flag;
   input = (pd - 1) << 26; 
   pd    = input;
   input = (mfd - 1) <<16;
   mfd   = input;
   input = mfi << 10;
   if (input < 5) mfi = 5;
   else mfi = input;
   
   if (mfn/mfd != 0) mfn = mfd - 1;
   input = pd+mfd+mfi+mfn;
   
   switch (pll_source) {
      case MPLL :
         reg32_write(CCM_MPCTL,input);
         break;
      case SPLL :
         reg32_write(CCM_SPCTL,input);
         break;
      case UPLL :
         reg32_write(CCM_UPCTL,input);
         break;
      default : 
         #ifdef USE_PRINTF
         printf("\nERROR: pll_source is not correct - write_to_N_pctl = 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}



//Reading from MPCTL/SPCTL/UPCTL register relevant frequency parameter
WORD get_pd_from_pll(int pll_source)
{
   WORD pll_reg;
   switch (pll_source) {
      case MPLL :
           pll_reg = ((reg32_read(CCM_MPCTL) & 0x3c000000)>>26) + 1;
           break;
      case SPLL :
           pll_reg = ((reg32_read(CCM_SPCTL) & 0x3c000000)>>26) + 1;
           break;
      case UPLL :
           pll_reg = ((reg32_read(CCM_UPCTL) & 0x3c000000)>>26) + 1;
           break;
      default : 
           #ifdef USE_PRINTF
           printf("\nERROR: pll_source is not correct - get_pd_from_pll = 0\n");
           #endif
           pll_reg = 0;
           break;
   }
   return pll_reg;
}



WORD get_mfd_from_pll(int pll_source){
   WORD pll_reg;
   switch (pll_source) {
      case MPLL :
           pll_reg = ((reg32_read(CCM_MPCTL) & 0x03ff0000)>>16) + 1;
           break;
      case SPLL :
           pll_reg = ((reg32_read(CCM_SPCTL) & 0x03ff0000)>>16) + 1;
           break;
      case UPLL :
           pll_reg = ((reg32_read(CCM_UPCTL) & 0x03ff0000)>>16) + 1;
           break;
      default : 
           #ifdef USE_PRINTF
           printf("\nERROR: pll_source is not correct - get_mfd_from_pll = 0\n");
           #endif
           pll_reg = 0;
           break;
   }
   return pll_reg;
}



WORD get_mfi_from_pll(int pll_source){
   WORD pll_reg;
   switch (pll_source) {
      case MPLL :
           pll_reg = ((reg32_read(CCM_MPCTL) & 0x00003c00)>>10);
           break;
      case SPLL :
           pll_reg = ((reg32_read(CCM_SPCTL) & 0x00003c00)>>10);
           break;
      case UPLL :
           pll_reg = ((reg32_read(CCM_UPCTL) & 0x00003c00)>>10);
           break;
      default : 
           #ifdef USE_PRINTF
           printf("\nERROR: pll_source is not correct - get_mfi_from_pll = 0\n");
           #endif
           pll_reg = 0;
           break;
   }
   return pll_reg;
}




WORD get_mfn_from_pll(int pll_source){
   WORD pll_reg;
   switch (pll_source) {
      case MPLL :
           pll_reg = (reg32_read(CCM_MPCTL) & 0x000003ff);
           break;
      case SPLL :
           pll_reg = (reg32_read(CCM_SPCTL) & 0x000003ff);
           break;
      case UPLL :
           pll_reg = (reg32_read(CCM_UPCTL) & 0x000003ff);
           break;
      default : 
           #ifdef USE_PRINTF
           printf("\nERROR: pll_source is not correct - get_mfn_from_pll = 0\n");
           #endif
           pll_reg = 0;
           break;
   }
   return pll_reg;
}

//Calculating MPLL/SPLL/UPLL frequency relying on freq parameters in MPCTL/SPCTL/UPCTL register.
int get_freq_from_pll(int pll_source){
   int freq = 0;
   int f_ref = 3355443;
   WORD mfn_neg,pd,mfd,mfi,mfn;
   if ((pll_source==MPLL)||(pll_source==SPLL)||(pll_source==UPLL)) freq = 1;
   if (get_source_for_ref_clk() == FPM_SOURCE_CLK) freq = 1;// if FPM is the source - return 1, else - 0
   if (freq == 0) {
      #ifdef USE_PRINTF
      printf("\nERROR: flag = 0 - get_freq_from_pll = 0\n");
      #endif
      return freq;
   }
   
   pd  = get_pd_from_pll(pll_source); //printf ("pd = %d\n", (int) pd);
   mfd = get_mfd_from_pll(pll_source);//printf ("mfd = %d\n", (int) mfd);
   mfi = get_mfi_from_pll(pll_source);//printf ("mfi = %d\n", (int) mfi);
   mfn = get_mfn_from_pll(pll_source);//printf ("mfn = %d\n", (int) mfn);
   if (mfi < 5) mfi = 5;
   if (mfn > 511) {
      mfn_neg = mfn & 0x01ff ; // neutralyzing the first "1" which comes from 2's complement number
      mfn = 512 - mfn_neg;
      freq   = (f_ref*2*mfi - ((f_ref*2*mfn)/mfd))/(pd*100); // -
   }
   else freq = (f_ref*2*mfi + ((f_ref*2*mfn)/mfd))/(pd*100); // +
   //if ((f_ref*2*(mfi + (mfn/mfd))) == 40217) verilog_trigger(arm_vt_event2);
  // if ((f_ref*2*mfi) == 39324) verilog_trigger(arm_vt_event2);
  // verilog_trigger(arm_vt_event1);
  // if (((f_ref*2*mfn)/mfd) == 893) verilog_trigger(arm_vt_event3);
  // verilog_trigger(arm_vt_event1);
  // if ((pd*100) == 1600) verilog_trigger(arm_vt_event2);
  // if((f_ref*2*mfi + ((f_ref*2*mfn)/mfd)) == 40217) verilog_trigger(arm_vt_event3);
  // verilog_trigger(arm_vt_event1);
  // if((f_ref*2*mfi + ((f_ref*2*mfn)/mfd))/(pd*100) == 25) verilog_trigger(arm_vt_event4);
   //freq = (f_ref*2*(mfi + (mfn/mfd)))/(pd*100);
   
   return freq;
}



int get_pll_status (int pll_source){
   int flag;
   switch (pll_source) {
      case MPLL :
         if (reg32_read(CCM_CCMR) & 0x00000008) flag = 1; // mpll is enabled
         else  flag = 2; // mpll is disabled
         break;
      case SPLL :
         if (reg32_read(CCM_CCMR) & 0x00000100) flag = 1; // spll is enabled
         else  flag = 2; // spll is disabled
         break;
      case UPLL :
         if (reg32_read(CCM_CCMR) & 0x00000200) flag = 1; // upll is enabled
         else  flag = 2; // upll is disabled
         break;
      default : 
           #ifdef USE_PRINTF
           printf("\nERROR: pll_source is not correct - get_pll_status = 0\n");
           #endif
         flag = 0;
   }
   return flag;
}


//Writing suitable set of freq parameters to MPCTL/SPCTL/UPCTL register
int set_pll_to_given_freq(int freq, int pll_source){
   int flag=1,interval, f_ref=33554432, divide_up, divide_down, flag_mfn_bigger_511;
   WORD pd, mfd, mfi, mfn;
   int div_result;
   if (freq<21)   {
       flag=0;//   if ((freq<21)|| (freq>532))   flag=0;
       #ifdef USE_PRINTF
       printf ("freq < 21 MHz - set_pll_to_given_freq return 0\n");
       #endif
   }
   if (!((pll_source==MPLL)||(pll_source==SPLL)||(pll_source==UPLL))) {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("source should be MPLL/SPLL/UPLL - set_pll_to_given_freq return 0\n");
      #endif
   }
   if (get_source_for_ref_clk() != FPM_SOURCE_CLK) {
      #ifdef USE_PRINTF
      printf("\nERROR: not FPM is the source clock - set_pll_to_given_freq = 0\n");
      #endif
      flag = 0;
   }
   
   if (flag == 0) return flag;
   if ((freq>=21)&(freq<=69))   interval=1; //pd = 16
   if ((freq>=70)&(freq<=200))  interval=2; //pd = 5
   if ((freq>=201)&(freq<=260)) interval=3; //pd = 4
   if ((freq>=261)&(freq<=340)) interval=4; //pd = 3
   if ((freq>=341)&(freq<=520)) interval=5; //pd = 2
   if (freq>=521) interval=6;//if ((freq>=521)&(freq<=532)) interval=6; //pd = 1
   switch (interval){
      case 1:
         pd=16;
         divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
   //}
         flag=1;
         break;
      case 2:
         pd=5;
         divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
         //}
         flag=1;
         break;
      case 3:
         pd=4;
         divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
         //}
         flag=1;
         break;
      case 4:
         pd=3;
         divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
         //}
         flag=1;
         break;
      case 5:
         pd=2;
         divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
         //}
         flag=1;
         break;
      case 6:
         pd=1;divide_up = freq*pd*1000000;
         divide_down = 2*f_ref;
         div_result=divide_up/divide_down;
         mfi = div_result;
         div_result=(divide_up%divide_down)/10;
         while (div_result > 511){
            div_result=div_result/10;
            divide_down=divide_down/10;
         }
         //if (div_result > 511) flag_mfn_bigger_511 = 1;
         //else flag_mfn_bigger_511 = 0;
         //if (flag_mfn_bigger_511) {
         //   mfn = div_result/10;
         //   mfd = divide_down/100;}
         //else {
            mfn = div_result;
            mfd = divide_down/10;
         //}
         flag=1;
         break;
         
      default :
         flag=0;
         break;
   }
   switch (pll_source) {
      case MPLL :
         write_to_N_pctl(pd, mfd, mfi, mfn, MPLL);
         break;
      case SPLL :
         write_to_N_pctl(pd, mfd, mfi, mfn, SPLL);
         break;
      case UPLL :
         write_to_N_pctl(pd, mfd, mfi, mfn, UPLL);
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_pll_to_given_freq return 0\n");
         #endif
         flag=0;
         break;
   }
   return flag;
}


// set MPLL to freq = 133MHz (7.525 nsec).
void set_mpll_to_133 (void){ reg32_write(CCM_MPCTL,0x0C6E1C67); }


// set MPLL to freq = 266MHz (3.77 nsec)
void set_mpll_to_266 (){ reg32_write(CCM_MPCTL,0x046E1C67); }


// set MPLL to freq = 399MHz (2.514 nsec)
void set_mpll_to_399 (){ reg32_write(CCM_MPCTL,0x00C714BD); }


// set MPLL to freq = 532MHz (1.887 nsec)
void set_mpll_to_532 (){ reg32_write(CCM_MPCTL,0x006E1C67); }

// set UPLL to freq = 133MHz (7.525 nsec).
void set_upll_to_133 (){ reg32_write(CCM_UPCTL,0x0C6E1C67); }


// set UPLL to freq = 266MHz (3.77 nsec)
void set_upll_to_266 (){ reg32_write(CCM_UPCTL,0x046E1C67); }


// set UPLL to freq = 399MHz (2.514 nsec)
void set_upll_to_399 (){ reg32_write(CCM_UPCTL,0x00C714BD); }


// set UPLL to freq = 532MHz (1.887 nsec)
void set_upll_to_532 (){ reg32_write(CCM_UPCTL,0x006E1C67); }


// set UPLL to freq = 480MHz (2.083 nsec)
void set_upll_to_480 (){ reg32_write(CCM_UPCTL,0x018F1C3D); }


// set UPLL to freq = 240MHz (4.167 nsec)
void set_upll_to_240 (){ reg32_write(CCM_UPCTL,0x058F1C3D); }


// set SPLL to freq = 133MHz (7.525 nsec).
void set_spll_to_133 (){ reg32_write(CCM_SPCTL,0x0C6E1C67); }


// set SPLL to freq = 266MHz (3.77 nsec)
void set_spll_to_266 (){ reg32_write(CCM_SPCTL,0x046E1C67); }


// set SPLL to freq = 399MHz (2.514 nsec)
void set_spll_to_399 (){ reg32_write(CCM_SPCTL,0x00C714BD); }


// set SPLL to freq = 532MHz (1.887 nsec)
void set_spll_to_532 (){ reg32_write(CCM_SPCTL,0x006E1C67); }


int set_pll_source_for_ssi1_clk(int pll_source){
   int flag;
   switch (pll_source) {
      case MPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfff3ffff); //[19:18] = 00
         flag = 1;
         break;
      case UPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfff3ffff | 0x00040000); //[19:18] = 01
         flag = 1;
         break;
      case SPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfff3ffff | 0x00080000); //[19:18] = 10 - SPLL - default
         flag = 1;
         break;
      default:
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_pll_source_for_ssi1_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int get_pll_source_for_ssi1_clk(){
   int flag;
   int reg = (reg32_read(CCM_CCMR) & 0x000c0000)>>18;
   switch (reg) {
      case 0 :
         flag = MPLL;
         break;
      case 2 :
         flag = SPLL;
         break;
      case 1 :
         flag = UPLL;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_pll_source_for_ssi1_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}




int set_pll_source_for_ssi2_clk(int pll_source){
   int flag;
   switch (pll_source) {
      case MPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xff0fffff); //[22:21] = 00 - (23, 20 - reserved)
         flag = 1;
         break;
      case UPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xff0fffff | 0x00200000); //[22:21] = 01
         flag = 1;
         break;
      case SPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xff0fffff | 0x00400000); //[22:21] = 10 - SPLL - default
         flag = 1;
         break;
      default:
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_pll_source_for_ssi2_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int get_pll_source_for_ssi2_clk(){
   int flag;
   WORD reg = (reg32_read(CCM_CCMR) & 0x00600000)>>21;
   switch (reg) {
      case 0 :
         flag = MPLL;
         break;
      case 2 :
         flag = SPLL;
         break;
      case 1 :
         flag = UPLL;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_pll_source_for_ssi2_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}




int set_pll_source_for_firi_clk(int pll_source){
   int flag;
   switch (pll_source) {
      case MPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xffffe7ff); //[12:11] = 00
         flag = 1;
         break;
      case SPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xffffe7ff | 0x00001000); //[12:11] = 10
         flag = 1;
         break;
      case UPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xffffe7ff | 0x00000800); //[12:11] = 01 - UPLL - default
         flag = 1;
         break;
      default:
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_pll_source_for_firi_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int get_pll_source_for_firi_clk(){
   int flag;
   WORD reg = (reg32_read(CCM_CCMR) & 0x00001800)>>11;
   switch (reg) {
      case 0 :
         flag = MPLL;
         break;
      case 2 :
         flag = SPLL;
         break;
      case 1 :
         flag = UPLL;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_pll_source_for_firi_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}




int set_pll_source_for_csi_clk(int pll_source){
   int flag;
   switch (pll_source) {
      case UPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfdffffff); //[25] = 0 (1101)
         flag = 1;
         break;
      case SPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x02000000); //[25] = 1 - SPLL - default
         flag = 1;
         break;
      default:
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_pll_source_for_csi_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int get_pll_source_for_csi_clk(){
   int flag;
   WORD reg = (reg32_read(CCM_CCMR) & 0x02000000)>>25;
   switch (reg) {
      case 0 :
         flag = UPLL;
         break;
      case 1 :
         flag = SPLL;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_pll_source_for_csi_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}




int set_source_for_per_clk(int clk_source){  // AFTER PER_DIV for per_clk source
   int flag;
   switch (clk_source) {
      case UPLL :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfeffffff); //[24] = 0 (1101)
         flag = 1;
         break;
      case IPG :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) | 0x01000000); //[24] = 1 - ipg_clk - default
         flag = 1;
         break;
      default:
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_source_for_per_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}


int get_source_for_per_clk(){
   int flag;
   WORD reg = (reg32_read(CCM_CCMR) & 0x01000000)>>24;
   switch (reg) {
      case 0 :
         flag = UPLL;
         break;
      case 1 :
         flag = IPG;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_source_for_per_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}




int set_source_for_ref_clk(int clk_source){
   int flag, mpll_status, spll_status, upll_status;
   if (reg32_read(CCM_CCMR) & 0x00000008) mpll_status = 1;
   else mpll_status = 0;
   if (reg32_read(CCM_CCMR) & 0x00000100) spll_status = 1;
   else spll_status = 0;
   if (reg32_read(CCM_CCMR) & 0x00000200) upll_status = 1;
   else upll_status = 0;
   if (mpll_status) mpll_disable();
   if (spll_status) spll_disable();
   if (upll_status) upll_disable();
   
   switch (clk_source) {
      case FPM_SOURCE_CLK :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffff9 | 0x00000002); //[2:1] = 01 
         flag = 1;
         break;
      case CKIH_SOURCE_CLK :
         reg32_write(CCM_CCMR,reg32_read(CCM_CCMR) & 0xfffffff9 | 0x00000004); //[2:1] = 10 
         flag = 1;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - set_source_for_ref_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   if (mpll_status) mpll_enable();
   if (spll_status) spll_enable();
   if (upll_status) upll_enable();
   return flag;
}



int get_source_for_ref_clk(){
   int flag;
   WORD reg = (reg32_read(CCM_CCMR) & 0x00000006)>>1;
   switch (reg) {
      case 1 :
         flag = FPM_SOURCE_CLK;
         break;
      case 2 :
         flag = CKIH_SOURCE_CLK;
         break;
      default :
         #ifdef USE_PRINTF
         printf ("source should be MPLL/SPLL/UPLL - get_source_for_ref_clk return 0\n");
         #endif
         flag = 0;
         break;
   }
   return flag;
}



int set_mcu_div(WORD divider){ // 1 < divider < 8
   int flag;
   WORD divide_by = divider - 0x001;
   if ((divider==1) || (divider==2) || (divider==3) || (divider==4) || (divider==5) || (divider==6) || (divider==7) || (divider==8)){
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xfffffff8 | divide_by); // [2:0]
        flag = 1;
   }
   else {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_mcu_div return 0\n");
      #endif
   }
   return flag;
}
      


int get_mcu_div(){ 
   int divider = (reg32_read(CCM_PDR0) & 0x00000007) + 1; // [2:0]
   return divider;
}


int set_hclk_div(WORD divider){ // 1 < divider < 8
   int flag;
   WORD divide_by = ((divider - 0x0001) << 3);
   
   if ((divider==1) || (divider==2) || (divider==3) || (divider==4) || (divider==5) || (divider==6) || (divider==7) || (divider==8)){
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xffffffc7 | divide_by); // [5:3]
        flag = 1;
   }
   else {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_hclk_div return 0\n");
      #endif
   }
   return flag;
}


int get_hclk_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x00000038)>>3) + 1; // [5:3]
   return divider;
}



int set_hsp_div(WORD divider){ // 1 < divider < 8
   int flag;
   WORD divide_by = ((divider - 0x0001) << 11);
   
   if ((divider==1) || (divider==2) || (divider==3) || (divider==4) || (divider==5) || (divider==6) || (divider==7) || (divider==8)){
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xffffc7ff | divide_by); // [13:11]
        flag = 1;
   }
   else {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_hsp_div return 0\n");
      #endif
   }
   return flag;
}


int get_hsp_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x00003800)>>11) + 1; // [13:11]
   return divider;
}


int set_ipg_div(WORD divider){ // 1 < divider < 4 - AFTER HCLK_DIV
   int flag;
   WORD divide_by = ((divider - 0x001) << 6);
   
   if ((divider==1) || (divider==2) || (divider==3) || (divider==4)){
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xffffff3f | divide_by); // [7:6]
        flag = 1;
   }
   else {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 4 - set_ipg_div return 0\n");
      #endif
   }
   return flag;
}


int get_ipg_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x000000c0)>>6) + 1; // [7:6]
   return divider;
}


int set_nfc_div(WORD divider){ // 1 < divider < 8 - AFTER HCLK_DIV
   int flag;
   WORD divide_by = ((divider - 0x0001) << 8);
   
   if ((divider==1) || (divider==2) || (divider==3) || (divider==4) || (divider==5) || (divider==6) || (divider==7) || (divider==8)){
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xfffff8ff | divide_by); // [10:8]
        flag = 1;
   }
   else {
      flag = 0;
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_nfc_div return 0\n");
      #endif
   }
   return flag;
}



int get_nfc_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x00000700)>>8) + 1; // [10:8]
   return divider;
}



int set_ssi1_pre_div(WORD predivider){ // 1 < predivider < 8
   int flag;
   WORD predivide_by  = ((predivider - 0x0001) << 6);
   
   if ((predivider<1) || (predivider>8)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_ssi1_pre_div return 0\n");
      #endif
      flag = 0;}
   else {
      if ((get_freq_from_pll(UPLL)/predivider)>133) {
         #ifdef USE_PRINTF
         printf ("predivider should be smaller number for freq to be less than 133MHz - set_ssi1_pre_div return 0\n");
         #endif
         flag = 0;
      }
      else {
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xffffff3f | predivide_by); // [6:8]
        flag = 1;
      }
   }
   return flag;
}


int set_ssi1_post_div(WORD postdivider){ // 1 < postdivider < 64
   int flag;
   WORD postdivide_by = (postdivider - 0x0000001);

   if ((postdivider<1) || (postdivider>64)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 64 - set_ssi1_post_div return 0\n");
      #endif
      flag = 0;}
   else {   
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xffffffc0 | postdivide_by); // [5:0]
        flag = 1;
   }
   return flag;
}


int get_ssi1_pre_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x000001c0)>>6) + 1; // [8:6]
   return divider;
}


int get_ssi1_post_div(){
   int divider = (reg32_read(CCM_PDR1) & 0x0000003f) + 1; // [5:0]
   return divider;
}


int set_ssi2_pre_div(WORD predivider){ // 1 < predivider < 8
   int flag;
   WORD predivide_by  = ((predivider  - 0x0001) << 15);
   
   if ((predivider<1) || (predivider>8)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_ssi2_pre_div return 0\n");
      #endif
      flag = 0;}
   else {
      if ((get_freq_from_pll(UPLL)/predivider)>133) {
         #ifdef USE_PRINTF
         printf ("predivider should be smaller number for freq to be less than 133MHz - set_ssi2_pre_div return 0\n");
         #endif
         flag = 0;
      }
      else {
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xfffc7fff | predivide_by); // [17:15]
        flag = 1;
      }
   }
   return flag;
}


int set_ssi2_post_div(WORD postdivider){ // 1 < postdivider < 64
   int flag;
   WORD postdivide_by = ((postdivider - 0x0000001) << 9);

   if ((postdivider<1) || (postdivider>64)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 64 - set_ssi2_post_div return 0\n");
      #endif
      flag = 0;}
   else {   
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xffff81ff | postdivide_by); // [14:9]
        flag = 1;
   }
   return flag;
}


int get_ssi2_pre_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x00038000)>>15) + 1; // [17:15]
   return divider;
}


int get_ssi2_post_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x00007e00)>>9) + 1; // [14:9]
   return divider;
}



int set_firi_pre_div(WORD predivider){ // 1 < predivider < 8
   int flag;
   WORD predivide_by  = ((predivider  - 0x0001) << 24);
   
   if ((predivider<1) || (predivider>8)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_firi_pre_div return 0\n");
      #endif
      flag = 0;}
   else {
      if ((get_freq_from_pll(UPLL)/predivider)>133) {
         #ifdef USE_PRINTF
         printf ("predivider should be smaller number for freq to be less than 133MHz - set_firi_pre_div return 0\n");
         #endif
         flag = 0;
      }
      else {
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xf8ffffff | predivide_by); // [26:24]
        flag = 1;
      }
   }
   return flag;
}


int set_firi_post_div(WORD postdivider){ //1 < postdivider < 64
   int flag;
   WORD postdivide_by = ((postdivider - 0x0000001) << 18);
   
   if ((postdivider<1) || (postdivider>64)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 64 - set_firi_post_div return 0\n");
      #endif
      flag = 0;
   }
   else {   
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xff03ffff | postdivide_by); // [23:18]
        flag = 1;
   }
   return flag;
}



int get_firi_pre_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x07000000)>>24) + 1; // [26:24]
   return divider;
}


int get_firi_post_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x00fc0000)>>18) + 1; // [23:18]
   return divider;
}



int set_usb_pre_div(WORD predivider){ // 1 < predivider < 4
   int flag;
   WORD predivide_by  = ((predivider  - 0x001) << 30);
   
   if ((predivider==1) || (predivider==2) || (predivider==3) || (predivider==4)){
      if ((get_freq_from_pll(UPLL)/predivider)>133) {
         #ifdef USE_PRINTF
         printf ("predivider should be smaller number for freq to be less than 133MHz - set_usb_pre_div return 0\n");
         #endif
         flag = 0;}
      else {
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0x3fffffff | predivide_by); // [31:30]
        flag = 1;
      }
   }
   else {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 4 - set_usb_pre_div return 0\n");
      #endif
      flag = 0;}
   return flag;
}


int set_usb_post_div(WORD postdivider){ // 1 < postdivider < 8
   int flag;
   WORD postdivide_by = ((postdivider - 0x0001) << 27);

   if ((postdivider==1) || (postdivider==2) || (postdivider==3) || (postdivider==4) || (postdivider==5) || (postdivider==6) || (postdivider==7) || (postdivider==8)) {
        reg32_write(CCM_PDR1,reg32_read(CCM_PDR1) & 0xc7ffffff | postdivide_by); // [29:27]
        flag = 1;
   }
   else {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_usb_post_div return 0\n");
      #endif
      flag = 0;}
   return flag;
}



int get_usb_pre_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0xc0000000)>>30) + 1; // [31:30]
   return divider;
}


int get_usb_post_div(){
   int divider = ((reg32_read(CCM_PDR1) & 0x38000000)>>27) + 1; // [29:27]
   return divider;
}



int set_mstick1_div(WORD divider){ // 1 < divider < 64  // UPLL
   int flag;
   WORD divide_by = divider - 0x0000001;
   
   if ((divider<1) || (divider>64)) { flag = 0;}
   else {
        reg32_write(CCM_PDR2,reg32_read(CCM_PDR2) & 0xffffffc0 | divide_by); // [5:0]
        flag = 1;
   }
   return flag;
}



int get_mstick1_div(){
   int divider = (reg32_read(CCM_PDR2) & 0x0000003f) + 1; // [5:0]
   return divider;
}





int set_mstick2_div(WORD divider){ // 1 < postdivider < 64  // UPLL
   int flag;
   WORD divide_by = ((divider - 0x0000001) << 7);
   
   if ((divider<1) || (divider>64)) { flag = 0;}
   else {
        reg32_write(CCM_PDR2,reg32_read(CCM_PDR2) & 0xffff007f | divide_by); // [12:7], 15,14,13,6 - reserved
        flag = 1;
   }
   return flag;
}



int get_mstick2_div(){
   int divider = ((reg32_read(CCM_PDR2) & 0x00001f80)>>7) + 1; // [12:7]
   return divider;
}




int set_csi_pre_div(WORD predivider){ // 1 < predivider < 8 - UPLL
   int flag;
   WORD predivide_by  = ((predivider  - 0x001) << 23);
   
   if ((predivider<1) || (predivider>8)){
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 8 - set_csi_pre_div return 0\n");
      #endif
      flag = 0;}
   else {
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xfc7fffff | predivide_by); // [25:23]
        flag = 1;
   }
   return flag;
}



int set_csi_post_div(WORD postdivider){ // 1 < postdivider < 64  - UPLL
   int flag;
   WORD postdivide_by = ((postdivider - 0x0001) << 26);

   if ((postdivider<1) || (postdivider>64)) {
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 64 - set_csi_post_div return 0\n");
      #endif
      flag = 0;}
   else {
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0x03ffffff | postdivide_by); // [31:26]
        flag = 1;
   }
   return flag;
}



int get_csi_pre_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x03800000)>>23) + 1; // [25:23]
   return divider;
}


int get_csi_post_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0xfc000000)>>26) + 1; // [31:26]
   return divider;
}



int set_per_div(WORD divider){ // 1 < divider < 32 - AFTER UPLL
   int flag;
   WORD divide_by = ((divider - 0x00001) << 16);
   
   if ((divider<1) || (divider>32)){
      #ifdef USE_PRINTF
      printf ("divider out of range, should be 1 < divider < 32 - set_per_div return 0\n");
      #endif
      flag = 0;}
   else {
        reg32_write(CCM_PDR0,reg32_read(CCM_PDR0) & 0xffe0ffff | divide_by); // [20:16]
        flag = 1;
   }
   return flag;
}



int get_per_div(){
   int divider = ((reg32_read(CCM_PDR0) & 0x001f0000)>>16) + 1; // [20:16]
   return divider;
}


int get_mcu_clk_freq (){
   int freq = (int)get_freq_from_pll(MPLL)/(int)get_mcu_div();
   return freq;
}

int get_hsp_clk_freq (){
   int freq = (int)get_freq_from_pll(MPLL)/(int)get_hsp_div();
   return freq;
}

int get_hclk_clk_freq (){
   int freq = (int)get_freq_from_pll(MPLL)/(int)get_hclk_div();
   return freq;
}

int get_ipg_clk_freq (){
   int freq = get_freq_from_pll(MPLL)/(get_hclk_div()*get_ipg_div());
   return freq;
}

int get_nfc_clk_freq (){
   int freq = get_freq_from_pll(MPLL)/(get_hclk_div()*get_nfc_div());
   return freq;
}

int get_ssi1_clk_freq (){
    int source = get_pll_source_for_ssi1_clk(); 
    int source_freq = get_freq_from_pll(source);
    int freq = source_freq / (get_ssi1_pre_div()*get_ssi1_post_div());
    return freq; 
}

int get_ssi2_clk_freq (){
    int source = get_pll_source_for_ssi2_clk();
    int source_freq = get_freq_from_pll(source);
    int freq = source_freq / (get_ssi2_pre_div()*get_ssi2_post_div());
    return freq;
}
    
    
int get_firi_clk_freq (){
    int source = get_pll_source_for_firi_clk();
    int source_freq = get_freq_from_pll(source);
    int freq = source_freq / (get_firi_pre_div()*get_firi_post_div());
    return freq;
}

int get_usb_clk_freq (){
   int freq = get_freq_from_pll(UPLL)/(get_usb_pre_div()*get_usb_post_div());
   return freq;
}


int get_mstick1_clk_freq (){
   int freq = get_freq_from_pll(UPLL)/(get_mstick1_div());
   return freq;
}


int get_mstick2_clk_freq (){
   int freq = get_freq_from_pll(UPLL)/(get_mstick2_div());
   return freq;
}


int get_csi_clk_freq (){
    int source = get_pll_source_for_csi_clk();
    int source_freq = get_freq_from_pll(source);
    int freq = source_freq / (get_csi_pre_div()*get_csi_post_div());
    return freq;
}


int get_per_clk_freq (){
    int source = get_source_for_per_clk();
    int source_freq, freq;
    if (source == IPG) {source_freq = get_ipg_clk_freq();
                        freq = source_freq;
                       }
    else if (source == UPLL) {source_freq = get_freq_from_pll(source);
                              freq = source_freq / get_per_div();
                             }
         else {
               #ifdef USE_PRINTF
               printf ("source should be IPG/UPLL - get_per_clk_freq return 0\n");
               #endif
               freq = 0;
               return freq;
              }
    return freq;
}



// Monitoring one of the clocks via CKO pad
// setmem /32 0x53F8001C = 0x00000200  ;CLKOEN=1, CLKOUTDIV=000
// setmem /32 0x53F8001C = 0x00000240  ;CLKOEN=1, CLKOUTDIV=001
// setmem /32 0x53F8001C = 0x00000280  ;CLKOEN=1, CLKOUTDIV=010  - default
// setmem /32 0x53F8001C = 0x000002C0  ;CLKOEN=1, CLKOUTDIV=011
// setmem /32 0x53F8001C = 0x00000300  ;CLKOEN=1, CLKOUTDIV=100
int set_cko_source(int source){
   int flag = 1;
   switch (source) {
      case MPLL :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0);//0000 - mpl_dpdgck_clk
           break;
      case IPG :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x1);//0001 - ipg_clk_ccm
           break;
      case UPLL :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x2);//0010 - upl_dpdgck_clk
           break;
      case REF :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x3);//0011 - pll_ref_clk
           break;
      case FPM_SOURCE_CLK :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x4);//0100 - fpm_ckil512_clk
           break;
      case AHB :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x5);//0101 - ipg_clk_ahb_arm                      
           break;
      case ARM :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x6);//0110 - ipg_clk_arm                      
           break;
      case SPLL :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x7);//0111 - spl_dpdgck_clk                      
           break;
      case CKIH_SOURCE_CLK :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x8);//1000 - ckih                      
           break;
      case EMI :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0x9);//1001 - ipg_clk_ahb_emi_clk                      
           break;     
      case IPU :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xa);//1010 - ipg_clk_ipu_hsp                      
           break;
      case NFC :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xb);//1011 - ipg_clk_nfc_20m                      
           break;     
      case PER :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xc);//1100 - ipg_clk_perclk_uart1                      
           break;
      case CIR1 :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xd);//1101 - ref_cir1                      
           break;
      case CIR2 :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xe);//1110 - ref_cir2                      
           break;
      case CIR3 :
           reg32_write(CCM_COSR,reg32_read(CCM_COSR) & 0xfffffff0 | 0xf);//1111 - ref_cir3                      
           break;     
      default :
           #ifdef USE_PRINTF
           printf ("source is not allowed - set_cko_source return 0\n");
           #endif
           flag = 0;
           break;
   }
   return flag;
}


// Checking which clock is monitored via CKO pad
int get_cko_source(){
   WORD read_reg;
   int source;
   read_reg = reg32_read(CCM_COSR) & 0x0000000f;
   switch (read_reg) {
      case 0x0 :
           source = MPLL;//0000 - mpl_dpdgck_clk
           break;
      case 0x1 :
           source = IPG ;//0001 - ipg_clk_ccm
           break;
      case 0x2 :
           source = UPLL ;//0010 - upl_dpdgck_clk
           break;
      case 0x3 :
           source = REF ;//0011 - pll_ref_clk
           break;
      case 0x4 :
           source = FPM_SOURCE_CLK ;//0100 - fpm_ckil512_clk
           break;
      case 0x5 :
           source = AHB ;//0101 - ipg_clk_ahb_arm                      
           break;
      case 0x6 :
           source = ARM ;//0110 - ipg_clk_arm                      
           break;
      case 0x7 :
           source = SPLL ;//0111 - spl_dpdgck_clk                      
           break;
      case 0x8 :
           source = CKIH_SOURCE_CLK ;//1000 - ckih                      
           break;
      case 0x9 :
           source = EMI ;//1001 - ipg_clk_ahb_emi_clk                      
           break;     
      case 0xa :
           source = IPU ;//1010 - ipg_clk_ipu_hsp                      
           break;
      case 0xb :
           source = NFC ;//1011 - ipg_clk_nfc_20m                      
           break;     
      case 0xc :
           source = PER ;//1100 - ipg_clk_perclk_uart1                      
           break;
      case 0xd :
           source = CIR1 ;//1101 - ref_cir1                      
           break;
      case 0xe :
           source = CIR2 ;//1110 - ref_cir2                      
           break;
      case 0xf :
           source = CIR3 ;//1111 - ref_cir3                      
           break;     
      default :
           #ifdef USE_PRINTF
           printf ("source is not allowed - get_cko_source return 0\n");
           #endif
           source = 0;
           break;
   }
   return source;
}
   

// writing into COSR[CLKOUTDIV] 0 < power_divider < 4
int set_clkoutdiv (int power_divider){
   int flag = 1;
   WORD write_reg;
   if ((power_divider!=0)&(power_divider!=1)&(power_divider!=2)&(power_divider!=3)&(power_divider!=4)) {
      #ifdef USE_PRINTF
      printf ("power_divider is out of range, should be between 0 and 4 - set_clkoutdiv return 0\n");
      #endif
      flag = 0;
      return flag;
   }
   write_reg = power_divider<<6;
   reg32_write(CCM_COSR, reg32_read(CCM_COSR) & 0xfffffe3f | write_reg); //COSR[8:6]
   return flag;
}



// Reading from COSR[CLKOUTDIV] power of divider for CKO source clock
WORD get_clkoutdiv(){
   WORD read_reg;
   read_reg = (reg32_read(CCM_COSR) & 0x1c0) >> 6;
   return read_reg;
}
   

// Check COSR[CLKOEN], if 0 - CKO is disabled
int check_if_cko_enabled (){
   int flag = 1;
   if ((reg32_read(CCM_COSR) & 0x200) == 0)  
      flag = 0;
   return flag;
}


// Write "1" into COSR[CLKOEN] (bit 9)
void enable_cko (){
   reg32_write(CCM_COSR, reg32_read(CCM_COSR) | 0x200);
}


// Write "0" into COSR[CLKOEN] (bit 9)
void disable_cko (){
   reg32_write(CCM_COSR, reg32_read(CCM_COSR) & 0xfffffdff);
}



// base freq = 532, configuring post dividers
void init_ccm(){
   plls_enable();// 074b0b7d // plls_enable(308) + ckih //CCM_CCMR=53F80000
   reg32_write(IPU_CONF,0x040); //enable ipu di, to get acknowledge for max_podf value change//IPU_CONF=53FC0000
   // reconfigure Post Dividers
   // mcu_podf=0(1), max_podf=3(4), ipg_podf=1(2), nfc_podf=5(6)
   // other post dividers get their spec default value
   reg32_write(CCM_PDR0,0xFF871D58);// CCM_PDR0=53F80004
   set_mpll_to_532(); // reg32_write(CCM_MPCTL,0x006E1C67);//CCM_MPCTL=53F80010
}

/*
// base freq = 532, configuring post dividers
void init_ccm(){
// plls_enable();// 074b0b7d // plls_enable(308) + ckih //CCM_CCMR=53F80000
   setmem /32 0x53F80000 = 0x074b0b7d
   
// reg32_write(IPU_CONF,0x040); //enable ipu di, to get acknowledge for max_podf value change//IPU_CONF=53FC0000
   setmem /32 0x53FC0000 = 0x040
   
   // reconfigure Post Dividers
   // mcu_podf=0(1), max_podf=3(4), ipg_podf=1(2), nfc_podf=5(6)
   // other post dividers get their spec default value
// reg32_write(CCM_PDR0,0xFF871D58);// CCM_PDR0=53F80004
   setmem /32 0x53F80004 = 0xFF871D58
      
// set_mpll_to_532(); // reg32_write(CCM_MPCTL,0x006E1C67);//CCM_MPCTL=53F80010
   setmem /32 0x53F80010 = 0x006E1C67
}
*/



// Writing "1" to all the enable bits - AVIC_INTENABLEH and AVIC_INTENABLEL
void enable_all_interrupts(){
   reg32_write(AVIC_INTENABLEH,0xFFFFFFFF);
   reg32_write(AVIC_INTENABLEL,0xFFFFFFFF);
}


// clear SCC memory and the interrupts
void init_scc(){
   int zeroing_started = 0;
   while (zeroing_started == 0){  // WAIT_FOR_MEMORY_ZEROIZING:
      if ((reg32_read(SCM_STATUS) & 0x00000200) == 0x00000200)
         zeroing_started == 0x1;
   }
   //clear the SCM's interrupt and the SCMIntStatus, ZeroizeDone, CipheringDone,
   //BlockAccessRemoved, and LengthError bits in the SCM Status register 
   reg32_write(SCM_INT_CONTROL,reg32_read(SCM_INT_CONTROL) | 0x00000002);
}



// Presence of the peritherals (0:14)
void init_spba_for_arm(){
   reg32_write(SPBA_PRR0, 0x1);
   reg32_write(SPBA_PRR1, 0x1);
   reg32_write(SPBA_PRR2, 0x1);
   reg32_write(SPBA_PRR3, 0x1);
   reg32_write(SPBA_PRR4, 0x1);
   reg32_write(SPBA_PRR5, 0x1);
   reg32_write(SPBA_PRR6, 0x1);
   reg32_write(SPBA_PRR7, 0x1);
   reg32_write(SPBA_PRR8, 0x1);
   reg32_write(SPBA_PRR9, 0x1);
   reg32_write(SPBA_PRR10,0x1);
   reg32_write(SPBA_PRR11,0x1);
   reg32_write(SPBA_PRR12,0x1);
   reg32_write(SPBA_PRR13,0x1);
   reg32_write(SPBA_PRR14,0x1);
}


// init_weim and init_sram_stack
void init_emi(){
   // init_weim();
   // init_sram_stack();
}



//setup task for the chip; base freq = 532
void init_default_1(){
   init_emi();
//   init_arm();
//   init_scc();
   enable_all_interrupts();
   init_ccm();
   init_spba_for_arm();
}
