1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/qn908x/vendor/fsl_clock.c
iosabi 21fd1f9258 Add vendor files for the NXP QN908x cpu
In preparation for adding support for the QN908x cpus, this patch adds
a pristine copy of the vendor SDK files needed for initial support.
The only modification to these files is to add '#ifdef __cplusplus'
guards to all the header files, even if not needed or already
present as '#if defined(__cplusplus)', to make sure
./dist/tools/externc/check.sh check passes.

These files are located under vendor/ directories (both
cpu/qn908x/include/vendor/ and cpu/qn908x/vendor/) and are part of NXP's
SDK for the QN908x family available for download from:
  https://mcuxpresso.nxp.com/en/builder

The files included in these vendor/ directories are released by NXP
under an Open Source license as described in each file, but only the
files used by the next patch are included here.
2020-12-02 02:45:53 +00:00

335 lines
9.7 KiB
C

/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright (c) 2016 - 2017 , NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_clock.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define getSysconClkMux() ((SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK) >> SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT)
/*******************************************************************************
* Variables
******************************************************************************/
typedef union
{
struct
{
uint8_t crcClkRefCnt;
uint8_t dmaClkRefCnt;
} ref_cnt_t;
uint8_t clkRefCnt[2];
} clock_ref_cnt_t;
/** Clock reference count */
static clock_ref_cnt_t clk_ref_cnt;
/*******************************************************************************
* Code
******************************************************************************/
static void Clk32KConfig(uint8_t choice)
{
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_CLK_32K_SEL_MASK) | SYSCON_CLK_CTRL_CLK_32K_SEL(choice);
}
static void ClkSysConfig(uint8_t choice)
{
if (choice == 0)
{
/* RCO 32MHz ,wait for ready */
while (!(SYSCON->SYS_MODE_CTRL & SYSCON_SYS_MODE_CTRL_OSC32M_RDY_MASK))
{
}
}
/* Switch to the clock source */
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK) | SYSCON_CLK_CTRL_SYS_CLK_SEL(choice);
}
static void ClkWdtConfig(uint8_t choice)
{
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_CLK_WDT_SEL_MASK) | SYSCON_CLK_CTRL_CLK_WDT_SEL(choice);
}
static void ClkBleConfig(uint8_t choice)
{
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_CLK_BLE_SEL_MASK) | SYSCON_CLK_CTRL_CLK_BLE_SEL(choice);
}
static void ClkXTALConfig(uint8_t choice)
{
switch (choice)
{
/* 16M XTAL */
case 0:
SYSCON->CLK_CTRL &= ~SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK;
break;
/* 32M XTAL */
case 1:
SYSCON->CLK_CTRL |= SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK;
break;
default:
break;
}
/* wait for ready */
while (!(SYSCON->SYS_MODE_CTRL & SYSCON_SYS_MODE_CTRL_XTAL_RDY_MASK))
{
}
}
void CLOCK_EnableClock(clock_ip_name_t clk)
{
uint32_t regPrimask = 0U;
if ((clk == kCLOCK_Crc) || (clk == kCLOCK_Dma))
{
regPrimask = DisableGlobalIRQ();
clk_ref_cnt.clkRefCnt[clk - kCLOCK_Crc] += 1U;
EnableGlobalIRQ(regPrimask);
}
SYSCON->CLK_EN = (1U << clk);
}
void CLOCK_DisableClock(clock_ip_name_t clk)
{
uint32_t regPrimask = 0U;
if (((clk == kCLOCK_Crc) || (clk == kCLOCK_Dma)) && (clk_ref_cnt.clkRefCnt[clk - kCLOCK_Crc] > 0))
{
regPrimask = DisableGlobalIRQ();
clk_ref_cnt.clkRefCnt[clk - kCLOCK_Crc] -= 1U;
EnableGlobalIRQ(regPrimask);
if (clk_ref_cnt.clkRefCnt[clk - kCLOCK_Crc] > 0)
{
return;
}
}
SYSCON->CLK_DIS = (1U << clk);
}
void CLOCK_AttachClk(clock_attach_id_t connection)
{
uint8_t mux, choice;
mux = (uint8_t)connection;
choice = (uint8_t)(((connection & 0xf00) >> 8) - 1);
switch (mux)
{
case CM_32KCLKSEL:
Clk32KConfig(choice);
break;
case CM_SYSCLKSEL:
ClkSysConfig(choice);
break;
case CM_WDTCLKSEL:
ClkWdtConfig(choice);
break;
case CM_BLECLKSEL:
ClkBleConfig(choice);
break;
case CM_XTALCLKSEL:
ClkXTALConfig(choice);
break;
default:
break;
}
}
void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value)
{
switch (div_name)
{
case kCLOCK_DivXtalClk:
/* F(XTAL) = F(XTAL) / (divided_by_value + 1), occupy 1 bit, take effect only when k32M_to_XTAL_CLK attached */
SYSCON->XTAL_CTRL =
(SYSCON->XTAL_CTRL & ~SYSCON_XTAL_CTRL_XTAL_DIV_MASK) | SYSCON_XTAL_CTRL_XTAL_DIV(divided_by_value);
break;
case kCLOCK_DivOsc32mClk:
/* F(OSC32M) = F(OSC32M) / (divided_by_value + 1), occupy 1 bit */
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK) |
SYSCON_CLK_CTRL_CLK_OSC32M_DIV(divided_by_value);
break;
case kCLOCK_DivAhbClk:
/* F(AHB) = F(SYS) / (divided_by_value + 1), occupy 13 bits
* Note: If ble core's clock is enabled by setting SYSCON_CLK_EN_CLK_BLE_EN to 1, ahb clock can only be 8M,
* 16M or 32M.
*/
SYSCON->CLK_CTRL =
(SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_AHB_DIV_MASK) | SYSCON_CLK_CTRL_AHB_DIV(divided_by_value);
break;
case kCLOCK_DivApbClk:
/* F(APB) = F(AHB) / (divided_by_value + 1), occupy 4 bits */
SYSCON->CLK_CTRL =
(SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_APB_DIV_MASK) | SYSCON_CLK_CTRL_APB_DIV(divided_by_value);
break;
case kCLOCK_DivFrg0:
/* F(Flexcomm0) = F(AHB) / (1 + MULT/DIV), DIV = 0xFF */
SYSCON->FC_FRG = (SYSCON->FC_FRG & ~SYSCON_FC_FRG_FRG_MULT0_MASK) |
SYSCON_FC_FRG_FRG_MULT0(divided_by_value) | SYSCON_FC_FRG_FRG_DIV0_MASK;
break;
case kCLOCK_DivFrg1:
/* F(Flexcomm1) = F(AHB) / (1 + MULT/DIV), DIV = 0xFF */
SYSCON->FC_FRG = (SYSCON->FC_FRG & ~SYSCON_FC_FRG_FRG_MULT1_MASK) |
SYSCON_FC_FRG_FRG_MULT1(divided_by_value) | SYSCON_FC_FRG_FRG_DIV1_MASK;
break;
case kCLOCK_DivClkOut:
/* F(ClkOut) = F(XTAL) / (2 * divided_by_value), occupy 4bits, take effect only when clock out source is
* XTAL */
SYSCON->CLK_CTRL = (SYSCON->CLK_CTRL & ~SYSCON_CLK_CTRL_XTAL_OUT_DIV_MASK) |
SYSCON_CLK_CTRL_XTAL_OUT_DIV(divided_by_value);
break;
default:
break;
}
}
static uint32_t CLOCK_GetRco32MFreq(void)
{
return (SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK) ? CLK_OSC_32MHZ / 2 : CLK_OSC_32MHZ;
}
static uint32_t CLOCK_GetXinFreq(void)
{
return ((SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK) &&
(!(SYSCON->XTAL_CTRL & SYSCON_XTAL_CTRL_XTAL_DIV_MASK))) ?
CLK_XTAL_32MHZ :
CLK_XTAL_16MHZ;
}
static uint32_t CLOCK_Get32KFreq(void)
{
return (SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_CLK_32K_SEL_MASK) ? CLK_RCO_32KHZ : CLK_XTAL_32KHZ;
}
static uint32_t CLOCK_GetCoreSysClkFreq(void)
{
return (getSysconClkMux() == 0) ? CLOCK_GetRco32MFreq() : (getSysconClkMux() == 1) ?
CLOCK_GetXinFreq() :
(getSysconClkMux() == 2) ? CLOCK_Get32KFreq() : 0;
}
static uint32_t CLOCK_GetAhbClkFreq(void)
{
return CLOCK_GetCoreSysClkFreq() /
(((SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_AHB_DIV_MASK) >> SYSCON_CLK_CTRL_AHB_DIV_SHIFT) + 1);
}
static uint32_t CLOCK_GetApbClkFreq(void)
{
return CLOCK_GetAhbClkFreq() /
(((SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_APB_DIV_MASK) >> SYSCON_CLK_CTRL_APB_DIV_SHIFT) + 1);
}
static uint32_t CLOCK_GetWdtFreq(void)
{
return (SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_CLK_WDT_SEL_MASK) ? CLOCK_GetApbClkFreq() : CLOCK_Get32KFreq();
}
uint32_t CLOCK_GetFreq(clock_name_t clk)
{
uint32_t freq;
switch (clk)
{
case kCLOCK_CoreSysClk:
freq = CLOCK_GetCoreSysClkFreq();
break;
case kCLOCK_BusClk:
freq = CLOCK_GetAhbClkFreq();
break;
case kCLOCK_ApbClk:
freq = CLOCK_GetApbClkFreq();
break;
case kCLOCK_WdtClk:
freq = CLOCK_GetWdtFreq();
break;
case kCLOCK_FroHf:
freq = CLOCK_GetRco32MFreq();
break;
case kCLOCK_Xin:
freq = CLOCK_GetXinFreq();
break;
case kCLOCK_32KClk:
freq = CLOCK_Get32KFreq();
break;
default:
freq = 0;
break;
}
return freq;
}
bool CLOCK_EnableUsbfs0DeviceClock(clock_usb_src_t src, uint32_t freq)
{
CLOCK_EnableClock(kCLOCK_Usbd0);
return true;
}
void CLOCK_EnableClkoutSource(uint32_t mask, bool enable)
{
if (enable)
{
SYSCON->CLK_CTRL |= mask;
}
else
{
SYSCON->CLK_CTRL &= ~mask;
}
}
void CLOCK_EnableClkoutPin(uint32_t mask, bool enable)
{
if (enable)
{
SYSCON->PIO_WAKEUP_EN1 |= mask;
}
else
{
SYSCON->PIO_WAKEUP_EN1 &= ~mask;
}
}
uint32_t CLOCK_GetFRGInputClock(void)
{
return CLOCK_GetFreq(kCLOCK_BusClk);
}
uint32_t CLOCK_SetFRGClock(clock_div_name_t div_name, uint32_t freq)
{
uint32_t input = CLOCK_GetFRGInputClock();
uint32_t mul;
if ((freq > 32000000) || (freq > input) || (input / freq >= 2))
{
/* FRG output frequency should be less than equal to 32MHz */
return 0;
}
else
{
mul = ((uint64_t)(input - freq) * 256) / ((uint64_t)freq);
if (div_name == kCLOCK_DivFrg0)
{
SYSCON->FC_FRG = (SYSCON->FC_FRG & ~SYSCON_FC_FRG_FRG_MULT0_MASK) | SYSCON_FC_FRG_FRG_MULT0(mul) |
SYSCON_FC_FRG_FRG_DIV0_MASK;
}
else if (div_name == kCLOCK_DivFrg1)
{
SYSCON->FC_FRG = (SYSCON->FC_FRG & ~SYSCON_FC_FRG_FRG_MULT1_MASK) | SYSCON_FC_FRG_FRG_MULT1(mul) |
SYSCON_FC_FRG_FRG_DIV1_MASK;
}
else
{
/* Add for avoid the misra 2004 rule 14.10 */
}
return 1;
}
}