/*! Sets up the clock out of RESET
 *!
 */
void clock_initialise(void) {
#ifdef ENABLE_CLKOUT
   showClocks();
#endif

#if (CLOCK_MODE == CLOCK_MODE_RESET)
   // No clock setup
#else
   // XTAL/EXTAL Pins
   SIM_SCGC6 |= SIM_SCGC6_PORTB_MASK;
   MXC_PTBPF1 = (MXC_PTBPF1&~MXC_PTBPF1_B6_MASK)|MXC_PTBPF1_B6(0);
   MXC_PTBPF2 = (MXC_PTBPF2&~MXC_PTBPF2_B5_MASK)|MXC_PTBPF2_B5(0);

   // Configure OSC2 (XTAL1/EXTAL1
   OSC1_CR = OSC1_CR_ERCLKEN_M|OSC1_CR_EREFSTEN_M|OSC1_CR_SCP_M;

   // Configure OSC2 (XTAL2/EXTAL2
   OSC2_CR = OSC2_CR_ERCLKEN_M|OSC2_CR_EREFSTEN_M|OSC2_CR_SCP_M;

   // Configure OSC1 (XTAL1/EXTAL1
   SIM_OSC1 = SIM_OSC1_OSC1EN_M|SIM_OSC1_OSC1RANGE_M|SIM_OSC1_OSC1HGO_M|SIM_OSC1_OSC1EREFS_M;

   // Out of reset MCG is in FEI mode
   // =============================================================

   // Switch from FEI -> FEI/FBI/FEE/FBE
   // =============================================================

   // Set up crystal or external clock source
   MCG_C2 = MCG_C2_RANGE_M     | // RANGE = 0,1,2 -> Oscillator low/high/very high clock range
            MCG_C2_HGO_M       | // HGO   = 0,1   -> Oscillator low power/high gain
            MCG_C2_EREFS_M     | // EREFS = 0,1   -> Select external clock/crystal oscillator
            MCG_C2_IRCS_M;       // IRCS  = 0,1   -> Select slow/fast internal clock for internal reference

   SIM_CLKDIV0 = SIM_CLKDIV0_OUTDIV(3);

#if ((CLOCK_MODE == CLOCK_MODE_FEI) || (CLOCK_MODE == CLOCK_MODE_FBI) || (CLOCK_MODE == CLOCK_MODE_BLPI) )
   // Transition via FBI
   //=====================================
#define BYPASS (1) // CLKS value used while FLL locks
   MCG_C1 =  MCG_C1_CLKS(BYPASS)     | // CLKS     = 1     -> Internal reference source while PLL locks
             MCG_C1_FRDIV_M          | // FRDIV    = N     -> XTAL/2^n ~ 31.25 kHz
             MCG_C1_IREFS_M          | // IREFS    = 0,1   -> External/Slow IRC for FLL source
             MCG_C1_IRCLKEN_M        | // IRCLKEN  = 0,1   -> IRCLK disable/enable
             MCG_C1_IREFSTEN_M;        // IREFSTEN = 0,1   -> Internal reference enabled in STOP mode

   // Wait for S_IREFST to indicate FLL Reference has switched
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_IREFST_MASK) != (MCG_C1_IREFS_V<<MCG_S_IREFST_SHIFT));

   // Wait for S_CLKST to indicating that OUTCLK has switched to bypass PLL/FLL
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(BYPASS));

   // Set FLL Parameters
   MCG_C4 = (MCG_C4&~(MCG_C4_DMX32_MASK|MCG_C4_DRST_DRS_MASK))|MCG_C4_DMX32_M|MCG_C4_DRST_DRS_M;
#endif

#if ((CLOCK_MODE == CLOCK_MODE_FBE) || (CLOCK_MODE == CLOCK_MODE_FEE) || (CLOCK_MODE == CLOCK_MODE_PLBE) || (CLOCK_MODE == CLOCK_MODE_PBE) || (CLOCK_MODE == CLOCK_MODE_PEE))

   // Transition via FBE
   //=====================================
#define BYPASS (2) // CLKS value used while PLL locks
   MCG_C1 =  MCG_C1_CLKS(BYPASS)     | // CLKS     = 2     -> External reference source while PLL locks
             MCG_C1_FRDIV_M          | // FRDIV    = N     -> XTAL/2^n ~ 31.25 kHz
             MCG_C1_IREFS_M          | // IREFS    = 0,1   -> External/Slow IRC for FLL source
             MCG_C1_IRCLKEN_M        | // IRCLKEN  = 0,1   -> IRCLK disable/enable
             MCG_C1_IREFSTEN_M;        // IREFSTEN = 0,1   -> Internal reference enabled in STOP mode

#if (MCG_C2_EREFS_V != 0)
   // Wait for oscillator stable (if used)
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_OSCINIT_MASK) == 0);
#endif

   // Wait for S_IREFST to indicate FLL Reference has switched
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_IREFST_MASK) != (MCG_C1_IREFS_V<<MCG_S_IREFST_SHIFT));

   // Wait for S_CLKST to indicating that OUTCLK has switched to bypass PLL/FLL
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(BYPASS));

   // Set FLL Parameters
   MCG_C4 = (MCG_C4&~(MCG_C4_DMX32_MASK|MCG_C4_DRST_DRS_MASK))|MCG_C4_DMX32_M|MCG_C4_DRST_DRS_M;
#endif

#if ((CLOCK_MODE == CLOCK_MODE_PBE) || (CLOCK_MODE == CLOCK_MODE_PEE))

   // Configure PLL Reference Frequency
   // =============================================================
   MCG_C5 =  MCG_C5_PLLCLKEN_M    |  // PLLCLKEN = 0,1 -> PLL -/enabled (irrespective of PLLS)
             MCG_C5_PLLSTEN_M     |  // PLLSTEN0 = 0,1 -> disabled/enabled in normal stop mode
             MCG_C5_PRDIV_M;         // PRDIV0   = N   -> PLL divider so PLL Ref. Freq. = 2-4 MHz

   // Transition via PBE
   // =============================================================
   MCG_C6 = MCG_C6_LOLIE_M    |
            MCG_C6_PLLS_M      |  // PLLS  = 0,1 -> Enable PLL
            MCG_C6_CME_M      |  // CME0  = 0,1 -> Disable/enable clock monitor
            MCG_C6_VDIV_M;       // VDIV0 = N   -> PLL Multiplication factor

   // Wait for PLL to lock
   do {
      __asm__("nop");
   } while((MCG_S & MCG_S_LOCK_MASK) == 0);

   // Wait until PLLS clock source changes to the PLL clock out
   do {
      __asm__("nop");
   } while((MCG_S & MCG_S_PLLST_MASK) == 0);

#endif

#if ((CLOCK_MODE == CLOCK_MODE_FEI) || (CLOCK_MODE == CLOCK_MODE_FEE))
   // Wait for FLL to lock
   do {
      __asm__("nop");
   } while ((MCG_C4&MCG_C4_DRST_DRS_MASK) != MCG_C4_DRST_DRS_M);
#endif


   // Select FEI/FBI/FEE/FBE/PBE/PEE clock mode
   MCG_C1 =  MCG_C1_CLKS_M       | // CLKS     = 0,1,2 -> Select FLL/IRCSCLK/ERCLK
             MCG_C1_FRDIV_M      | // FRDIV    = N     -> XTAL/2^n ~ 31.25 kHz
             MCG_C1_IREFS_M      | // IREFS    = 0,1   -> External/Slow IRC for FLL source
             MCG_C1_IRCLKEN_M    | // IRCLKEN  = 0,1   -> IRCLK disable/enable
             MCG_C1_IREFSTEN_M;    // IREFSTEN = 0,1   -> Internal reference enabled in STOP mode

   // Wait for mode change
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_IREFST_MASK) != (MCG_C1_IREFS_V<<MCG_S_IREFST_SHIFT));

#if defined (MCG_C6_PLLS_V) && (MCG_C1_CLKS_V == 0) // FLL or PLL
#define MCG_S_CLKST_M MCG_S_CLKST(MCG_C6_PLLS_V?3:0)
#else
   #define MCG_S_CLKST_M MCG_S_CLKST(MCG_C1_CLKS_V)
#endif

   // Wait for S_CLKST to indicating that OUTCLK has switched
   do {
      __asm__("nop");
   } while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST_M);

#if (CLOCK_MODE == CLOCK_MODE_BLPE) || (CLOCK_MODE == CLOCK_MODE_BLPI)
   // Select BLPE/BLPI clock mode
   MCG_C2 =
            MCG_C2_LOCRE_M      | // LOCRE0 = 0,1   -> Loss of clock reset
            MCG_C2_RANGE_M      | // RANGE0 = 0,1,2 -> Oscillator low/high/very high clock range
            MCG_C2_HGO_M        | // HGO0   = 0,1   -> Oscillator low power/high gain
            MCG_C2_EREFS_M      | // EREFS0 = 0,1   -> Select external clock/crystal oscillator
            MCG_C2_LP_M         | // LP     = 0,1   -> Select FLL enabled/disabled in bypass mode
            MCG_C2_IRCS_M;        // IRCS   = 0,1   -> Select slow/fast internal clock for internal reference

#endif // (CLOCK_MODE == CLOCK_MODE_BLPE) || (CLOCK_MODE == CLOCK_MODE_BLPI)
#endif // (CLOCK_MODE == CLOCK_MODE_RESET)

   // Basic clock multiplexing
#if defined(MCU_mcf51jf128)
//   SIM_SOPT2 = SIM_SOPT2_UART0SRC_M      | // UART0 clock - 0,1,2,3 -> Disabled, (MCGFLLCLK, MCGPLLCLK/2),  OSCERCLK, MCGIRCLK
//               SIM_SOPT2_TPMSRC_M ;        // TPM2 source
#else
   #error "CPU not set"
#endif

#ifdef SIM_CLKDIV1_USBFRAC_MASK
   SIM_CLKDIV1 = SIM_CLKDIV1_USBDIV_M | SIM_CLKDIV1_USBFRAC_M | SIM_CLKDIV1_USBSRC_M;
#endif

   SIM_CLKDIV0 = SIM_CLKDIV0_M;

   SystemCoreClockUpdate();
}
/*****************************************************************************
 * @name     MCG_Init
 *
 * @brief:   Initialization of the Multiple Clock Generator.
 *
 * @param  : None
 *
 * @return : None
 *****************************************************************************
 * Provides clocking options for the device, including a phase-locked
 * loop(PLL) and frequency-locked loop (FLL) for multiplying slower reference
 * clock sources
 ****************************************************************************/
static void 
MCG_Init()
{
	SIM_SCGC5 |= SIM_SCGC5_MCG_MASK;

#ifndef EXTERNAL_OSC
	SIM_SCGC5 |= SIM_SCGC5_OSC2_MASK;
#endif
    
    /* First move to FBE mode */
    /* Enable external oscillator, RANGE=1, HGO=1, EREFS=1, LP=0, IRCS=0 */
#ifdef EXTERNAL_OSC
    MCG_C2 = 0;
#else
    MCG_C2 = MCG_C2_RANGE(1) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK;
#endif
    /* Select external oscillator and Reference Divider and clear IREFS to start ext. osc. */
    // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
    MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); 
    /* Wait for oscillator to initialize */
#ifndef EXTERNAL_OSC
    while (!(MCG_S & MCG_S_OSCINIT_MASK))
    {;}
#endif
    /* Wait for Reference clock Status bit to clear */
    while (MCG_S & MCG_S_IREFST_MASK)
    {;} 
    /* Wait for clock status bits to show clock source is ext. ref. clk. */
    while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2)
    {;}    
 
    /* Configure PLL Ref Divider, PLLCLKEN=0, PLLSTEN=0, PRDIV=5
       The crystal frequency is used to select the PRDIV value. Only even frequency crystals are supported
       that will produce a 2MHz reference clock to the PLL. */
    MCG_C5 = MCG_C5_PRDIV(BSP_REF_CLOCK_DIV); // Set PLL ref. divider to match the crystal used
    
    /* Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk. monitor disabled, PLL VCO divider is clear */
    MCG_C6 = 0x0;   
 
    /* Set system options dividers
       MCG=PLL, core = MCG  */ 
	SIM_CLKDIV0 =  SIM_CLKDIV0_OUTDIV(0);
    /* Set the VCO divider and enable the PLL for 48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0 */
    MCG_C6 = MCG_C6_PLLS_MASK; //VDIV = 0 (x24)    
    
    /* Wait for PLL status bit to set */
    while (!(MCG_S & MCG_S_PLLST_MASK))
    {;} 
    /* Wait for LOCK bit to set */
    while (!(MCG_S & MCG_S_LOCK_MASK))
    {;}    
 
    /* Now running PBE Mode */
    /* Transition into PEE by setting CLKS to 0
       CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 */
    MCG_C1 &= ~MCG_C1_CLKS_MASK;

    /* Wait for clock status bits to update */
    while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3)
    {;}

    /* Now running PEE Mode */            
    SIM_SOPT3 |= SIM_SOPT3_RWE_MASK; 
    SIM_SOPT1 |= SIM_SOPT1_REGE_MASK;
    SIM_SOPT7 |= 0x80;
    
    /* Ensure PLL is selected as USB CLK source */
    SIM_CLKDIV1 = 0x00;            
}