diff --git a/cpu/kinetis_common/include/mcg.h b/cpu/kinetis_common/include/mcg.h index 2c17c179c541d7b687eb30610680989e16959cc5..70eb2f6b16a4f68d5b4aed03ec1786fac4204805 100644 --- a/cpu/kinetis_common/include/mcg.h +++ b/cpu/kinetis_common/include/mcg.h @@ -10,7 +10,8 @@ * @defgroup cpu_kinetis_common_mcg Kinetis MCG * @ingroup cpu_kinetis_common * @brief Implementation of the Kinetis Multipurpose Clock Generator - * (MCG) driver. + * (MCG) driver + * * Please add mcg.h in cpu conf.h * and MCG configuration to periph_conf.h * @@ -37,6 +38,30 @@ * - BLPE -> FEE * - BLPI -> FEE * + * \dot + * digraph states { + * layout=dot + * nodesep=0.5 + * {rank=same Reset [shape=none] FEI FEE} + * {rank=same FBI FBE} + * {rank=same BLPI BLPE} + * Reset -> FEI + * FEI -> FEE [dir="both"] + * FEI -> FBE [dir="both"] + * FEI -> FBI [dir="both"] + * FEE -> FBI [dir="both"] + * FEE -> FBE [dir="both"] + * FBI -> FBE [dir="both"] + * FBI -> BLPI [dir="both"] + * FBE -> BLPE [dir="both"] + * PBE + * PEE + * FBE -> PBE [dir="both"] + * BLPE -> PBE [dir="both"] + * PBE -> PEE [dir="both"] + * } + * \enddot + * * ### MCG Configuration Examples (for periph_conf.h) ### * * Example for FEI Mode (MCGOUTCLK = 20MHz ... 25MHz): diff --git a/cpu/kinetis_common/periph/mcg.c b/cpu/kinetis_common/periph/mcg.c index b567b348e4102cfb16987e2e4807529ac9fd426e..cb757f6f74a2afdcce103e042efbe98159619015 100644 --- a/cpu/kinetis_common/periph/mcg.c +++ b/cpu/kinetis_common/periph/mcg.c @@ -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 */ +/** @} */