Skip to content
Snippets Groups Projects
Commit 5f0b8e5b authored by Francisco Acosta's avatar Francisco Acosta Committed by GitHub
Browse files

Merge pull request #6978 from gebart/pr/kinetis-mcg

kinetis: MCG improvements
parents 863bda7b 8efb714e
No related branches found
No related tags found
No related merge requests found
......@@ -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):
......
/*
* 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 */
/** @} */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment