chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/drivers/mk_clock.c
对比新文件
@@ -0,0 +1,256 @@
/*
 * 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));
}