/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* must reproduce the above copyright notice, this list of conditions and
|
* the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
|
#include "mk_clock.h"
|
|
static void clock_32K_clk_config(uint8_t choice)
|
{
|
// 0 - 32KHz RCO
|
// 1 - 32KHz XTAL oscillator
|
// 2 - External sine wave
|
// 3 - External square wave
|
if (choice)
|
{
|
if ((choice == 2) || (choice == 3))
|
{
|
clock_xtal32k_injection_set(choice == 3 ? CLOCK_XTAL_INJECTION_SQUARE : CLOCK_XTAL_INJECTION_SINE);
|
}
|
|
// XTAL, wait for ready
|
while (!(SYSCON->CLK_STATUS & SYSCON_CLK_STATUS_XTAL_32K_REDAY_MSK))
|
{
|
}
|
SYSCON->SYS_CMU |= SYSCON_SYS_CMU_32K_CLK_SEL_MSK;
|
}
|
else
|
{
|
SYSCON->SYS_CMU &= ~SYSCON_SYS_CMU_32K_CLK_SEL_MSK;
|
}
|
}
|
|
static void clock_sys_clk_config(uint8_t choice)
|
{
|
// 0 - 32KHz
|
// 1 - 48MHz RO
|
// 2 - 62.4MHz Clock XTAL38.4M
|
// 3 - 62.4MHz Clock External 38.4M sine wave
|
// 4 - 62.4MHz Clock External 38.4M square wave
|
|
uint32_t sys_cmu = SYSCON->SYS_CMU;
|
|
if (choice == 0)
|
{
|
sys_cmu = (sys_cmu & ~SYSCON_SYS_CMU_SYS_CLK_SEL_MSK);
|
}
|
else if (choice == 1)
|
{
|
sys_cmu = (sys_cmu | SYSCON_SYS_CMU_SYS_CLK_SEL_MSK);
|
sys_cmu = (sys_cmu & ~SYSCON_SYS_CMU_HS_CLK_SEL_MSK);
|
}
|
else
|
{
|
if ((choice == 3) || (choice == 4))
|
{
|
clock_xtal38m4_injection_set(choice == 4 ? CLOCK_XTAL_INJECTION_SQUARE : CLOCK_XTAL_INJECTION_SINE);
|
}
|
|
// XTAL, wait for REFPLL ready
|
while (!(SYSCON->CLK_STATUS & SYSCON_CLK_STATUS_REFPLL_REDAY_MSK))
|
{
|
}
|
sys_cmu = (sys_cmu | SYSCON_SYS_CMU_SYS_CLK_SEL_MSK | SYSCON_SYS_CMU_HS_CLK_SEL_MSK);
|
}
|
|
SYSCON->SYS_CMU = sys_cmu;
|
}
|
|
static void clock_wdt_clk_config(uint8_t choice)
|
{
|
if (choice)
|
{
|
SYSCON->CLK_DIV |= SYSCON_CLK_DIV_WDT_CLK_SEL_MSK;
|
}
|
else
|
{
|
SYSCON->CLK_DIV &= ~SYSCON_CLK_DIV_WDT_CLK_SEL_MSK;
|
}
|
}
|
|
static uint32_t clock_get_sys_clk_freq(void)
|
{
|
uint32_t freq;
|
if (SYSCON->SYS_CMU & SYSCON_SYS_CMU_SYS_CLK_SEL_MSK)
|
{
|
freq = (SYSCON->SYS_CMU & SYSCON_SYS_CMU_HS_CLK_SEL_MSK) ? CLOCK_XTAL38P4M : CLOCK_RO_48M;
|
}
|
else
|
{
|
freq = (SYSCON->SYS_CMU & SYSCON_SYS_CMU_32K_CLK_SEL_MSK) ? CLOCK_XTAL_32K : CLOCK_RCO_32K;
|
}
|
|
return (freq);
|
}
|
|
static uint32_t clock_get_ahb_clk_freq(void)
|
{
|
return (clock_get_sys_clk_freq() / (1 << GET_BIT_FIELD(SYSCON->CLK_DIV, SYSCON_CLK_DIV_HCLK_DIV_MSK, SYSCON_CLK_DIV_HCLK_DIV_POS)));
|
}
|
|
static uint32_t clock_get_apb_clk_freq(void)
|
{
|
return (clock_get_ahb_clk_freq() / (1 << GET_BIT_FIELD(SYSCON->CLK_DIV, SYSCON_CLK_DIV_PCLK_DIV_MSK, SYSCON_CLK_DIV_PCLK_DIV_POS)));
|
}
|
|
static uint32_t clock_get_32k_clk_freq(void)
|
{
|
return ((SYSCON->SYS_CMU & SYSCON_SYS_CMU_32K_CLK_SEL_MSK) ? CLOCK_XTAL_32K : CLOCK_RCO_32K);
|
}
|
|
static uint32_t clock_get_wdt_clk_freq(void)
|
{
|
return ((SYSCON->CLK_DIV & SYSCON_CLK_DIV_WDT_CLK_SEL_MSK) ? clock_get_apb_clk_freq() : clock_get_32k_clk_freq());
|
}
|
|
static uint32_t clock_get_flash_clk_freq(void)
|
{
|
return (clock_get_sys_clk_freq() / (1 << GET_BIT_FIELD(SYSCON->CLK_DIV, SYSCON_CLK_DIV_FLASH_CTRL_DIV_MSK, SYSCON_CLK_DIV_FLASH_CTRL_DIV_POS)));
|
}
|
|
void clock_enable(enum CLOCK_GATE_T clk)
|
{
|
SYSCON->SYS_CMU |= (1U << clk);
|
}
|
|
void clock_disable(enum CLOCK_GATE_T clk)
|
{
|
SYSCON->SYS_CMU &= ~(1U << clk);
|
}
|
|
void clock_attach(enum CLOCK_ATTACH_TYPE_T connection)
|
{
|
uint8_t mux, choice;
|
|
mux = (uint8_t)connection;
|
choice = (uint8_t)(connection >> 8);
|
|
switch (mux)
|
{
|
case CLOCK_32K_CLK_SEL:
|
clock_32K_clk_config(choice);
|
break;
|
case CLOCK_SYS_CLK_SEL:
|
clock_sys_clk_config(choice);
|
break;
|
case CLOCK_WDT_CLK_SEL:
|
clock_wdt_clk_config(choice);
|
break;
|
default:
|
break;
|
}
|
}
|
|
void clock_set_divider(enum CLOCK_DIVIDER_T div_name, uint8_t div_value)
|
{
|
switch (div_name)
|
{
|
case CLOCK_AHB_DIV:
|
SYSCON->CLK_DIV = (SYSCON->CLK_DIV & ~SYSCON_CLK_DIV_HCLK_DIV_MSK) | SYSCON_CLK_DIV_HCLK_DIV(div_value);
|
break;
|
case CLOCK_APB_DIV:
|
SYSCON->CLK_DIV = (SYSCON->CLK_DIV & ~SYSCON_CLK_DIV_PCLK_DIV_MSK) | SYSCON_CLK_DIV_PCLK_DIV(div_value);
|
break;
|
case CLOCK_FLASH_CTRL_DIV:
|
SYSCON->CLK_DIV = (SYSCON->CLK_DIV & ~SYSCON_CLK_DIV_FLASH_CTRL_DIV_MSK) | SYSCON_CLK_DIV_FLASH_CTRL_DIV(div_value);
|
break;
|
case CLOCK_UART1_FDIV:
|
SYSCON->CLK_DIV = (SYSCON->CLK_DIV & ~SYSCON_CLK_DIV_UART1_FDIV_MSK) | SYSCON_CLK_DIV_UART1_FDIV(div_value);
|
break;
|
case CLOCK_UART0_FDIV:
|
SYSCON->CLK_DIV = (SYSCON->CLK_DIV & ~SYSCON_CLK_DIV_UART0_FDIV_MSK) | SYSCON_CLK_DIV_UART0_FDIV(div_value);
|
break;
|
}
|
}
|
|
uint32_t clock_get_frequency(enum CLOCK_TYPE_T clk_name)
|
{
|
uint32_t freq = 0;
|
switch (clk_name)
|
{
|
case CLOCK_SYS_CLK:
|
freq = clock_get_sys_clk_freq();
|
break;
|
case CLOCK_AHB_CLK:
|
freq = clock_get_ahb_clk_freq();
|
break;
|
case CLOCK_APB_CLK:
|
freq = clock_get_apb_clk_freq();
|
break;
|
case CLOCK_WDT_CLK:
|
freq = clock_get_wdt_clk_freq();
|
break;
|
case CLOCK_32K_CLK:
|
freq = clock_get_32k_clk_freq();
|
break;
|
case CLOCK_FLASH_CLK:
|
freq = clock_get_flash_clk_freq();
|
break;
|
}
|
return freq;
|
}
|
|
void clock_xtal38m4_injection_set(enum CLOCK_XTAL_INJECTION_TYPE_T type)
|
{
|
uint32_t tmp_val = REG_READ(0x40000048);
|
tmp_val &= ~((0x3U << 16) | 0x7fU);
|
REG_WRITE(0x40000048, tmp_val | (type << 16));
|
|
REG_WRITE(0x40000210, 0x0);
|
REG_WRITE(0x40000104, 0x0FFF);
|
|
tmp_val = REG_READ(0x40000214);
|
REG_WRITE(0x40000214, tmp_val | (1 << 12) | (2 << 10) | (2 << 8));
|
}
|
|
void clock_xtal32k_injection_set(enum CLOCK_XTAL_INJECTION_TYPE_T type)
|
{
|
uint32_t tmp_val = REG_READ(0x4000004C);
|
tmp_val &= ~(0x3U << 16);
|
REG_WRITE(0x4000004C, tmp_val | (type << 16));
|
}
|