|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2015 PHYTEC Messtechnik GmbH |
|
|
|
|
* Copyright (C) 2017 Eistec AB |
|
|
|
|
* |
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General |
|
|
|
|
* Public License v2.1. See the file LICENSE in the top level directory for more |
|
|
|
@ -14,7 +15,8 @@
|
|
|
|
|
* @brief Implementation of the Kinetis Multipurpose Clock Generator |
|
|
|
|
* |
|
|
|
|
* @author Johann Fischer <j.fischer@phytec.de> |
|
|
|
|
* @} |
|
|
|
|
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se> |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <stdint.h> |
|
|
|
@ -23,8 +25,24 @@
|
|
|
|
|
|
|
|
|
|
#if KINETIS_CPU_USE_MCG |
|
|
|
|
|
|
|
|
|
/* MCG neighbor modes matrix */ |
|
|
|
|
static uint8_t mcg_pm[8] = {0x02, 0x15, 0x12, 0x20, 0xe6, 0xd8, 0xb0, 0xf0}; |
|
|
|
|
#if defined(MCG_C6_PLLS_MASK) |
|
|
|
|
#define KINETIS_HAVE_PLL 1 |
|
|
|
|
#else |
|
|
|
|
#define KINETIS_HAVE_PLL 0 |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* Pathfinding for the clocking modes, this table lists the next mode in the
|
|
|
|
|
* chain when moving from mode <first> to mode <second> */ |
|
|
|
|
static const uint8_t mcg_mode_routing[8][8] = { |
|
|
|
|
{0, 1, 1, 1, 1, 1, 1, 1}, /* from PEE */ |
|
|
|
|
{0, 1, 2, 4, 4, 4, 4, 4}, /* from PBE */ |
|
|
|
|
{1, 1, 2, 4, 4, 4, 4, 4}, /* from BLPE */ |
|
|
|
|
{5, 5, 5, 3, 5, 5, 5, 5}, /* from BLPI */ |
|
|
|
|
{1, 1, 2, 5, 4, 5, 6, 7}, /* from FBE */ |
|
|
|
|
{4, 4, 4, 3, 4, 5, 6, 7}, /* from FBI */ |
|
|
|
|
{4, 4, 4, 5, 4, 5, 6, 7}, /* from FEE */ |
|
|
|
|
{4, 4, 4, 5, 4, 5, 6, 7}, /* from FEI */ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static uint8_t current_mode = KINETIS_MCG_FEI; |
|
|
|
|
|
|
|
|
@ -97,6 +115,7 @@ static uint8_t current_mode = KINETIS_MCG_FEI;
|
|
|
|
|
#error "KINETIS_MCG_ERC_RANGE not defined in periph_conf.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if KINETIS_HAVE_PLL |
|
|
|
|
#ifndef KINETIS_MCG_PLL_PRDIV |
|
|
|
|
#error "KINETIS_MCG_PLL_PRDIV not defined in periph_conf.h" |
|
|
|
|
#endif |
|
|
|
@ -118,6 +137,9 @@ static inline void kinetis_mcg_disable_pll(void)
|
|
|
|
|
MCG->C5 = (uint8_t)0; |
|
|
|
|
MCG->C6 = (uint8_t)0; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
static inline void kinetis_mcg_disable_pll(void) {} |
|
|
|
|
#endif /* KINETIS_HAVE_PLL */ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Set Frequency Locked Loop (FLL) factor. |
|
|
|
@ -161,7 +183,7 @@ static void kinetis_mcg_enable_osc(void)
|
|
|
|
|
MCG->C2 |= (uint8_t)(MCG_C2_EREFS0_MASK); |
|
|
|
|
|
|
|
|
|
/* wait fo OSC initialization */ |
|
|
|
|
while ((MCG->S & MCG_S_OSCINIT0_MASK) == 0); |
|
|
|
|
while ((MCG->S & MCG_S_OSCINIT0_MASK) == 0) {} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -182,10 +204,10 @@ static void kinetis_mcg_set_fei(void)
|
|
|
|
|
MCG->C2 = (uint8_t)0; |
|
|
|
|
|
|
|
|
|
/* source of the FLL reference clock shall be internal reference clock */ |
|
|
|
|
while ((MCG->S & MCG_S_IREFST_MASK) == 0); |
|
|
|
|
while ((MCG->S & MCG_S_IREFST_MASK) == 0) {} |
|
|
|
|
|
|
|
|
|
/* Wait until output of the FLL is selected */ |
|
|
|
|
while (MCG->S & (MCG_S_CLKST_MASK)); |
|
|
|
|
while (MCG->S & (MCG_S_CLKST_MASK)) {} |
|
|
|
|
|
|
|
|
|
kinetis_mcg_disable_pll(); |
|
|
|
|
current_mode = KINETIS_MCG_FEI; |
|
|
|
@ -207,7 +229,7 @@ static void kinetis_mcg_set_fee(void)
|
|
|
|
|
MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); |
|
|
|
|
|
|
|
|
|
/* Wait until output of FLL is selected */ |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(0)); |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(0)) {} |
|
|
|
|
|
|
|
|
|
kinetis_mcg_disable_pll(); |
|
|
|
|
current_mode = KINETIS_MCG_FEE; |
|
|
|
@ -237,10 +259,10 @@ static void kinetis_mcg_set_fbi(void)
|
|
|
|
|
MCG->C1 = (uint8_t)(MCG_C1_CLKS(1) | MCG_C1_IREFS_MASK); |
|
|
|
|
|
|
|
|
|
/* Wait until output of IRC is selected */ |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)); |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)) {} |
|
|
|
|
|
|
|
|
|
/* source of the FLL reference clock shall be internal reference clock */ |
|
|
|
|
while ((MCG->S & MCG_S_IREFST_MASK) == 0); |
|
|
|
|
while ((MCG->S & MCG_S_IREFST_MASK) == 0) {} |
|
|
|
|
|
|
|
|
|
kinetis_mcg_disable_pll(); |
|
|
|
|
current_mode = KINETIS_MCG_FBI; |
|
|
|
@ -266,7 +288,7 @@ static void kinetis_mcg_set_fbe(void)
|
|
|
|
|
MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); |
|
|
|
|
|
|
|
|
|
/* Wait until ERC is selected */ |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)); |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {} |
|
|
|
|
|
|
|
|
|
kinetis_mcg_disable_pll(); |
|
|
|
|
current_mode = KINETIS_MCG_FBE; |
|
|
|
@ -299,6 +321,7 @@ static void kinetis_mcg_set_blpe(void)
|
|
|
|
|
current_mode = KINETIS_MCG_BLPE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if KINETIS_HAVE_PLL |
|
|
|
|
/**
|
|
|
|
|
* @brief Initialize the PLL Bypassed External Mode. |
|
|
|
|
* |
|
|
|
@ -315,7 +338,7 @@ static void kinetis_mcg_set_pbe(void)
|
|
|
|
|
MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); |
|
|
|
|
|
|
|
|
|
/* Wait until ERC is selected */ |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)); |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {} |
|
|
|
|
|
|
|
|
|
/* PLL is not disabled in bypass mode */ |
|
|
|
|
MCG->C2 &= ~(uint8_t)(MCG_C2_LP_MASK); |
|
|
|
@ -330,10 +353,10 @@ static void kinetis_mcg_set_pbe(void)
|
|
|
|
|
MCG->C6 |= (uint8_t)(MCG_C6_PLLS_MASK); |
|
|
|
|
|
|
|
|
|
/* Wait until the source of the PLLS clock is PLL */ |
|
|
|
|
while ((MCG->S & MCG_S_PLLST_MASK) == 0); |
|
|
|
|
while ((MCG->S & MCG_S_PLLST_MASK) == 0) {} |
|
|
|
|
|
|
|
|
|
/* Wait until PLL locked */ |
|
|
|
|
while ((MCG->S & MCG_S_LOCK0_MASK) == 0); |
|
|
|
|
while ((MCG->S & MCG_S_LOCK0_MASK) == 0) {} |
|
|
|
|
|
|
|
|
|
current_mode = KINETIS_MCG_PBE; |
|
|
|
|
} |
|
|
|
@ -350,135 +373,52 @@ static void kinetis_mcg_set_pee(void)
|
|
|
|
|
MCG->C1 &= ~(uint8_t)(MCG_C1_CLKS_MASK); |
|
|
|
|
|
|
|
|
|
/* Wait until output of the PLL is selected */ |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)); |
|
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) {} |
|
|
|
|
|
|
|
|
|
current_mode = KINETIS_MCG_PEE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* KINETIS_HAVE_PLL */ |
|
|
|
|
|
|
|
|
|
int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode) |
|
|
|
|
{ |
|
|
|
|
if (mode > KINETIS_MCG_FEI) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mcg_pm[current_mode] & (1 << mode)) { |
|
|
|
|
if (mode == KINETIS_MCG_FEI) { |
|
|
|
|
kinetis_mcg_set_fei(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_FBI) { |
|
|
|
|
kinetis_mcg_set_fbi(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_FEE) { |
|
|
|
|
kinetis_mcg_set_fee(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_FBE) { |
|
|
|
|
kinetis_mcg_set_fbe(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_BLPI) { |
|
|
|
|
kinetis_mcg_set_blpi(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_BLPE) { |
|
|
|
|
kinetis_mcg_set_blpe(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_PBE) { |
|
|
|
|
kinetis_mcg_set_pbe(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mode == KINETIS_MCG_PEE) { |
|
|
|
|
kinetis_mcg_set_pee(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (mode) { |
|
|
|
|
case KINETIS_MCG_PEE: |
|
|
|
|
/* cppcheck-suppress duplicateExpression */ |
|
|
|
|
if (!(KINETIS_MCG_USE_ERC || KINETIS_MCG_USE_PLL)) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_FEI) { |
|
|
|
|
/* set FBE -> PBE -> PEE */ |
|
|
|
|
kinetis_mcg_set_fbe(); |
|
|
|
|
kinetis_mcg_set_pbe(); |
|
|
|
|
while (current_mode != mode) { |
|
|
|
|
switch(mcg_mode_routing[current_mode][mode]) { |
|
|
|
|
#if KINETIS_HAVE_PLL |
|
|
|
|
case KINETIS_MCG_PEE: |
|
|
|
|
kinetis_mcg_set_pee(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_BLPE) { |
|
|
|
|
/* set PBE -> PEE */ |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_PBE: |
|
|
|
|
kinetis_mcg_set_pbe(); |
|
|
|
|
kinetis_mcg_set_pee(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case KINETIS_MCG_BLPE: |
|
|
|
|
if (!KINETIS_MCG_USE_ERC) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_PEE) { |
|
|
|
|
/* set PBE -> BLPE */ |
|
|
|
|
kinetis_mcg_set_pbe(); |
|
|
|
|
kinetis_mcg_set_blpe(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_FEE) { |
|
|
|
|
/* set FBE -> BLPE */ |
|
|
|
|
kinetis_mcg_set_fbe(); |
|
|
|
|
break; |
|
|
|
|
#endif /* KINETIS_HAVE_PLL */ |
|
|
|
|
case KINETIS_MCG_BLPE: |
|
|
|
|
kinetis_mcg_set_blpe(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case KINETIS_MCG_BLPI: |
|
|
|
|
if (current_mode == KINETIS_MCG_FEE) { |
|
|
|
|
/* set FBI -> BLPI */ |
|
|
|
|
kinetis_mcg_set_fbi(); |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_BLPI: |
|
|
|
|
kinetis_mcg_set_blpi(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case KINETIS_MCG_FEE: |
|
|
|
|
if (!KINETIS_MCG_USE_ERC) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_BLPE) { |
|
|
|
|
/* set FBE -> FEE */ |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_FBE: |
|
|
|
|
kinetis_mcg_set_fbe(); |
|
|
|
|
kinetis_mcg_set_fee(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (current_mode == KINETIS_MCG_BLPI) { |
|
|
|
|
/* set FBI -> FEE */ |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_FBI: |
|
|
|
|
kinetis_mcg_set_fbi(); |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_FEE: |
|
|
|
|
kinetis_mcg_set_fee(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
break; |
|
|
|
|
case KINETIS_MCG_FEI: |
|
|
|
|
kinetis_mcg_set_fei(); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* KINETIS_CPU_USE_MCG */ |
|
|
|
|
/** @} */ |
|
|
|
|