/* * 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)); }