|  | /* | 
|  | * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define DT_DRV_COMPAT bflb_bl60x_clock_controller | 
|  |  | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/drivers/clock_control.h> | 
|  | #include <zephyr/drivers/syscon.h> | 
|  | #include <zephyr/sys/util.h> | 
|  | #include <zephyr/dt-bindings/clock/bflb_bl60x_clock.h> | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(clock_control_bl60x, CONFIG_CLOCK_CONTROL_LOG_LEVEL); | 
|  |  | 
|  | #include <bouffalolab/bl60x/bflb_soc.h> | 
|  | #include <bouffalolab/bl60x/aon_reg.h> | 
|  | #include <bouffalolab/bl60x/glb_reg.h> | 
|  | #include <bouffalolab/bl60x/hbn_reg.h> | 
|  | #include <bouffalolab/bl60x/pds_reg.h> | 
|  | #include <bouffalolab/bl60x/l1c_reg.h> | 
|  | #include <bouffalolab/bl60x/extra_defines.h> | 
|  |  | 
|  | #define CLK_SRC_IS(clk, src)                                                                       \ | 
|  | DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0),                \ | 
|  | DT_INST_CLOCKS_CTLR_BY_NAME(0, src)) | 
|  |  | 
|  | #define CLOCK_TIMEOUT               1024 | 
|  | #define EFUSE_RC32M_TRIM_OFFSET     0x0C | 
|  | #define EFUSE_RC32M_TRIM_EN_POS     19 | 
|  | #define EFUSE_RC32M_TRIM_PARITY_POS 18 | 
|  | #define EFUSE_RC32M_TRIM_POS        10 | 
|  | #define EFUSE_RC32M_TRIM_MSK        0x3FC00 | 
|  |  | 
|  | #define CRYSTAL_ID_FREQ_32000000 0 | 
|  | #define CRYSTAL_ID_FREQ_24000000 1 | 
|  | #define CRYSTAL_ID_FREQ_38400000 2 | 
|  | #define CRYSTAL_ID_FREQ_40000000 3 | 
|  | #define CRYSTAL_ID_FREQ_26000000 4 | 
|  |  | 
|  | #define CRYSTAL_FREQ_TO_ID(freq) CONCAT(CRYSTAL_ID_FREQ_, freq) | 
|  |  | 
|  | enum bl60x_clkid { | 
|  | bl60x_clkid_clk_root = BL60X_CLKID_CLK_ROOT, | 
|  | bl60x_clkid_clk_rc32m = BL60X_CLKID_CLK_RC32M, | 
|  | bl60x_clkid_clk_crystal = BL60X_CLKID_CLK_CRYSTAL, | 
|  | bl60x_clkid_clk_pll = BL60X_CLKID_CLK_PLL, | 
|  | bl60x_clkid_clk_bclk = BL60X_CLKID_CLK_BCLK, | 
|  | }; | 
|  |  | 
|  | struct clock_control_bl60x_pll_config { | 
|  | enum bl60x_clkid source; | 
|  | bool overclock; | 
|  | }; | 
|  |  | 
|  | struct clock_control_bl60x_root_config { | 
|  | enum bl60x_clkid source; | 
|  | uint8_t pll_select; | 
|  | uint8_t divider; | 
|  | }; | 
|  |  | 
|  | struct clock_control_bl60x_bclk_config { | 
|  | uint8_t divider; | 
|  | }; | 
|  |  | 
|  | struct clock_control_bl60x_config { | 
|  | uint32_t crystal_id; | 
|  | }; | 
|  |  | 
|  | struct clock_control_bl60x_data { | 
|  | bool crystal_enabled; | 
|  | bool pll_enabled; | 
|  | struct clock_control_bl60x_pll_config pll; | 
|  | struct clock_control_bl60x_root_config root; | 
|  | struct clock_control_bl60x_bclk_config bclk; | 
|  | }; | 
|  |  | 
|  | const static uint32_t clock_control_bl60x_crystal_SDMIN_table[5] = { | 
|  | /* 32M */ | 
|  | 0x3C0000, | 
|  | /* 24M */ | 
|  | 0x500000, | 
|  | /* 38.4M */ | 
|  | 0x320000, | 
|  | /* 40M */ | 
|  | 0x300000, | 
|  | /* 26M */ | 
|  | 0x49D39D, | 
|  | }; | 
|  |  | 
|  | static inline void clock_control_bl60x_clock_settle(void) | 
|  | { | 
|  | __asm__ volatile(".rept 15 ; nop ; .endr"); | 
|  | } | 
|  |  | 
|  | /* 32 Mhz Oscillator: 0 | 
|  | * crystal: 1 | 
|  | * PLL and 32M: 2 | 
|  | * PLL and crystal: 3 | 
|  | */ | 
|  | static void clock_control_bl60x_set_root_clock(uint32_t clock) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | /* invalid value, fallback to internal 32M */ | 
|  | if (clock > 3) { | 
|  | clock = 0; | 
|  | } | 
|  | tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | 
|  | tmp = (tmp & HBN_ROOT_CLK_SEL_UMSK) | (clock << HBN_ROOT_CLK_SEL_POS); | 
|  | sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  | } | 
|  |  | 
|  | static uint32_t clock_control_bl60x_get_root_clock(void) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | 
|  | return (((tmp & HBN_ROOT_CLK_SEL_MSK) >> HBN_ROOT_CLK_SEL_POS) & 0x3); | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_deinit_crystal(void) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | /* unpower crystal */ | 
|  | tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); | 
|  | tmp = tmp & AON_PU_XTAL_AON_UMSK; | 
|  | tmp = tmp & AON_PU_XTAL_BUF_AON_UMSK; | 
|  | sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_init_crystal(void) | 
|  | { | 
|  | uint32_t tmp; | 
|  | int count = CLOCK_TIMEOUT; | 
|  |  | 
|  | /* power crystal */ | 
|  | tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); | 
|  | tmp = (tmp & AON_PU_XTAL_AON_UMSK) | (1U << AON_PU_XTAL_AON_POS); | 
|  | tmp = (tmp & AON_PU_XTAL_BUF_AON_UMSK) | (1U << AON_PU_XTAL_BUF_AON_POS); | 
|  | sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); | 
|  |  | 
|  | /* wait for crystal to be powered on */ | 
|  | do { | 
|  | clock_control_bl60x_clock_settle(); | 
|  | tmp = sys_read32(AON_BASE + AON_TSEN_OFFSET); | 
|  | count--; | 
|  | } while (!(tmp & AON_XTAL_RDY_MSK) && count > 0); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  | if (count < 1) { | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* HCLK is the core clock */ | 
|  | static int clock_control_bl60x_set_root_clock_dividers(uint32_t hclk_div, uint32_t bclk_div) | 
|  | { | 
|  | uint32_t tmp; | 
|  | uint32_t old_rootclk; | 
|  |  | 
|  | old_rootclk = clock_control_bl60x_get_root_clock(); | 
|  |  | 
|  | /* security RC32M */ | 
|  | if (old_rootclk > 1) { | 
|  | clock_control_bl60x_set_root_clock(0); | 
|  | } | 
|  |  | 
|  | /* set dividers */ | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_HCLK_DIV_UMSK) | (hclk_div << GLB_REG_HCLK_DIV_POS); | 
|  | tmp = (tmp & GLB_REG_BCLK_DIV_UMSK) | (bclk_div << GLB_REG_BCLK_DIV_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  |  | 
|  | /* do something undocumented, probably acknowledging clock change by disabling then | 
|  | * reenabling bclk | 
|  | */ | 
|  | sys_write32(0x00000001, 0x40000FFC); | 
|  | sys_write32(0x00000000, 0x40000FFC); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | /* enable clocks */ | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_BCLK_EN_UMSK) | (1U << GLB_REG_BCLK_EN_POS); | 
|  | tmp = (tmp & GLB_REG_HCLK_EN_UMSK) | (1U << GLB_REG_HCLK_EN_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_set_root_clock(old_rootclk); | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_set_machine_timer_clock_enable(bool enable) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); | 
|  | if (enable) { | 
|  | tmp = (tmp & GLB_CPU_RTC_EN_UMSK) | (1U << GLB_CPU_RTC_EN_POS); | 
|  | } else { | 
|  | tmp = (tmp & GLB_CPU_RTC_EN_UMSK) | (0U << GLB_CPU_RTC_EN_POS); | 
|  | } | 
|  | sys_write32(tmp, GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); | 
|  | } | 
|  |  | 
|  | /* clock: | 
|  | * 0: BCLK | 
|  | * 1: 32Khz Oscillator (RC32*K*) | 
|  | */ | 
|  | static void clock_control_bl60x_set_machine_timer_clock(bool enable, uint32_t clock, | 
|  | uint32_t divider) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | if (divider > 0x1FFFF) { | 
|  | divider = 0x1FFFF; | 
|  | } | 
|  | if (clock > 1) { | 
|  | clock = 1; | 
|  | } | 
|  |  | 
|  | /* disable first, then set div */ | 
|  | clock_control_bl60x_set_machine_timer_clock_enable(false); | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); | 
|  | tmp = (tmp & GLB_CPU_RTC_SEL_UMSK) | (clock << GLB_CPU_RTC_SEL_POS); | 
|  | tmp = (tmp & GLB_CPU_RTC_DIV_UMSK) | (divider << GLB_CPU_RTC_DIV_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_set_machine_timer_clock_enable(enable); | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_deinit_pll(void) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | /* PLL Off */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_PU_CLKPLL_SFREG_UMSK) | (0U << PDS_PU_CLKPLL_SFREG_POS); | 
|  | tmp = (tmp & PDS_PU_CLKPLL_UMSK) | (0U << PDS_PU_CLKPLL_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | /* needs 2 steps ? */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_CP_UMSK) | (0U << PDS_CLKPLL_PU_CP_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_PFD_UMSK) | (0U << PDS_CLKPLL_PU_PFD_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_FBDV_UMSK) | (0U << PDS_CLKPLL_PU_FBDV_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_POSTDIV_UMSK) | (0U << PDS_CLKPLL_PU_POSTDIV_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | } | 
|  |  | 
|  | /* RC32M : 0 | 
|  | * XTAL : 1 | 
|  | */ | 
|  | static void clock_control_bl60x_set_pll_source(uint32_t source) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); | 
|  | if (source > 0) { | 
|  | tmp = (tmp & PDS_CLKPLL_REFCLK_SEL_UMSK) | (1U << PDS_CLKPLL_REFCLK_SEL_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_XTAL_RC32M_SEL_UMSK) | | 
|  | (0U << PDS_CLKPLL_XTAL_RC32M_SEL_POS); | 
|  | } else { | 
|  | tmp = (tmp & PDS_CLKPLL_REFCLK_SEL_UMSK) | (0U << PDS_CLKPLL_REFCLK_SEL_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_XTAL_RC32M_SEL_UMSK) | | 
|  | (1U << PDS_CLKPLL_XTAL_RC32M_SEL_POS); | 
|  | } | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_init_pll(enum bl60x_clkid source, uint32_t crystal_id) | 
|  | { | 
|  | uint32_t tmp; | 
|  | uint32_t old_rootclk; | 
|  |  | 
|  | old_rootclk = clock_control_bl60x_get_root_clock(); | 
|  |  | 
|  | /* security RC32M */ | 
|  | if (old_rootclk > 1) { | 
|  | clock_control_bl60x_set_root_clock(0); | 
|  | } | 
|  |  | 
|  | clock_control_bl60x_deinit_pll(); | 
|  |  | 
|  | if (source == BL60X_CLKID_CLK_CRYSTAL) { | 
|  | clock_control_bl60x_set_pll_source(1); | 
|  | } else { | 
|  | clock_control_bl60x_set_pll_source(0); | 
|  | } | 
|  |  | 
|  | /* 26M special treatment */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_CP_OFFSET); | 
|  | if (crystal_id == CRYSTAL_ID_FREQ_26000000) { | 
|  | tmp = (tmp & PDS_CLKPLL_ICP_1U_UMSK) | (1U << PDS_CLKPLL_ICP_1U_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_ICP_5U_UMSK) | (0U << PDS_CLKPLL_ICP_5U_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_INT_FRAC_SW_UMSK) | (1U << PDS_CLKPLL_INT_FRAC_SW_POS); | 
|  | } else { | 
|  | tmp = (tmp & PDS_CLKPLL_ICP_1U_UMSK) | (0U << PDS_CLKPLL_ICP_1U_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_ICP_5U_UMSK) | (2U << PDS_CLKPLL_ICP_5U_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_INT_FRAC_SW_UMSK) | (0U << PDS_CLKPLL_INT_FRAC_SW_POS); | 
|  | } | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_CP_OFFSET); | 
|  |  | 
|  | /* More 26M special treatment */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_RZ_OFFSET); | 
|  | if (crystal_id == CRYSTAL_ID_FREQ_26000000) { | 
|  | tmp = (tmp & PDS_CLKPLL_C3_UMSK) | (2U << PDS_CLKPLL_C3_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_CZ_UMSK) | (2U << PDS_CLKPLL_CZ_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_RZ_UMSK) | (5U << PDS_CLKPLL_RZ_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_R4_SHORT_UMSK) | (0U << PDS_CLKPLL_R4_SHORT_POS); | 
|  | } else { | 
|  | tmp = (tmp & PDS_CLKPLL_C3_UMSK) | (3U << PDS_CLKPLL_C3_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_CZ_UMSK) | (1U << PDS_CLKPLL_CZ_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_RZ_UMSK) | (1U << PDS_CLKPLL_RZ_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_R4_SHORT_UMSK) | (1U << PDS_CLKPLL_R4_SHORT_POS); | 
|  | } | 
|  | tmp = (tmp & PDS_CLKPLL_R4_UMSK) | (2U << PDS_CLKPLL_R4_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_RZ_OFFSET); | 
|  |  | 
|  | /* set pll dividers */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_POSTDIV_UMSK) | ((uint32_t)(0x14) << PDS_CLKPLL_POSTDIV_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_REFDIV_RATIO_UMSK) | (2U << PDS_CLKPLL_REFDIV_RATIO_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); | 
|  |  | 
|  | /* set SDMIN */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_SDM_OFFSET); | 
|  | if (source == BL60X_CLKID_CLK_CRYSTAL) { | 
|  | tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) | | 
|  | (clock_control_bl60x_crystal_SDMIN_table[crystal_id] | 
|  | << PDS_CLKPLL_SDMIN_POS); | 
|  | } else { | 
|  | tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) | | 
|  | (clock_control_bl60x_crystal_SDMIN_table[CRYSTAL_ID_FREQ_32000000] | 
|  | << PDS_CLKPLL_SDMIN_POS); | 
|  | } | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_SDM_OFFSET); | 
|  |  | 
|  | /* phase comparator settings? */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_FBDV_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_SEL_FB_CLK_UMSK) | (1U << PDS_CLKPLL_SEL_FB_CLK_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_SEL_SAMPLE_CLK_UMSK) | (1U << PDS_CLKPLL_SEL_SAMPLE_CLK_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_FBDV_OFFSET); | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_PU_CLKPLL_SFREG_UMSK) | (1U << PDS_PU_CLKPLL_SFREG_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | /* enable PPL clock actual? */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_PU_CLKPLL_UMSK) | (1U << PDS_PU_CLKPLL_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | /* More power up sequencing*/ | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_CP_UMSK) | (1U << PDS_CLKPLL_PU_CP_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_PFD_UMSK) | (1U << PDS_CLKPLL_PU_PFD_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_FBDV_UMSK) | (1U << PDS_CLKPLL_PU_FBDV_POS); | 
|  | tmp = (tmp & PDS_CLKPLL_PU_POSTDIV_UMSK) | (1U << PDS_CLKPLL_PU_POSTDIV_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | /* reset couple things one by one? */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_SDM_RESET_UMSK) | (1U << PDS_CLKPLL_SDM_RESET_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_RESET_FBDV_UMSK) | (1U << PDS_CLKPLL_RESET_FBDV_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_RESET_FBDV_UMSK) | (0U << PDS_CLKPLL_RESET_FBDV_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  | tmp = (tmp & PDS_CLKPLL_SDM_RESET_UMSK) | (0U << PDS_CLKPLL_SDM_RESET_POS); | 
|  | sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_set_root_clock(old_rootclk); | 
|  | clock_control_bl60x_clock_settle(); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 0: 48M | 
|  | * 1: 120M | 
|  | * 2: 160M | 
|  | * 3: 192M | 
|  | */ | 
|  | static void clock_control_bl60x_select_PLL(uint8_t pll) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_PLL_SEL_UMSK) | (pll << GLB_REG_PLL_SEL_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_clock_trim_32M(void) | 
|  | { | 
|  | uint32_t tmp; | 
|  | int err; | 
|  | uint32_t trim, trim_parity; | 
|  | const struct device *efuse = DEVICE_DT_GET_ONE(bflb_efuse); | 
|  |  | 
|  | err = syscon_read_reg(efuse, EFUSE_RC32M_TRIM_OFFSET, &trim); | 
|  | if (err < 0) { | 
|  | LOG_ERR("Error: Couldn't read efuses: err: %d.\n", err); | 
|  | return err; | 
|  | } | 
|  | if (!((trim >> EFUSE_RC32M_TRIM_EN_POS) & 1)) { | 
|  | LOG_ERR("RC32M trim disabled!"); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | trim_parity = (trim >> EFUSE_RC32M_TRIM_PARITY_POS) & 1; | 
|  | trim = (trim & EFUSE_RC32M_TRIM_MSK) >> EFUSE_RC32M_TRIM_POS; | 
|  |  | 
|  | if (trim_parity != (POPCOUNT(trim) & 1)) { | 
|  | LOG_ERR("Bad trim parity"); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | tmp = sys_read32(PDS_BASE + PDS_RC32M_CTRL0_OFFSET); | 
|  | tmp = (tmp & PDS_RC32M_EXT_CODE_EN_UMSK) | 1 << PDS_RC32M_EXT_CODE_EN_POS; | 
|  | tmp = (tmp & PDS_RC32M_CODE_FR_EXT_UMSK) | trim << PDS_RC32M_CODE_FR_EXT_POS; | 
|  | sys_write32(tmp, PDS_BASE + PDS_RC32M_CTRL0_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* source for most clocks, either XTAL or RC32M */ | 
|  | static uint32_t clock_control_bl60x_get_xclk(const struct device *dev) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | 
|  | tmp &= HBN_ROOT_CLK_SEL_MSK; | 
|  | tmp = tmp >> HBN_ROOT_CLK_SEL_POS; | 
|  | tmp &= 1; | 
|  | if (tmp == 0) { | 
|  | return BFLB_RC32M_FREQUENCY; | 
|  | } else if (tmp == 1) { | 
|  | return DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency); | 
|  | } else { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static uint32_t clock_control_bl60x_get_clk(const struct device *dev) | 
|  | { | 
|  | uint32_t tmp; | 
|  | uint32_t hclk_div; | 
|  |  | 
|  | hclk_div = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | hclk_div = (hclk_div & GLB_REG_HCLK_DIV_MSK) >> GLB_REG_HCLK_DIV_POS; | 
|  |  | 
|  | tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | 
|  | tmp &= HBN_ROOT_CLK_SEL_MSK; | 
|  | tmp = (tmp >> HBN_ROOT_CLK_SEL_POS) >> 1; | 
|  | tmp &= 1; | 
|  |  | 
|  | if (tmp == 0) { | 
|  | return clock_control_bl60x_get_xclk(dev) / (hclk_div + 1); | 
|  | } | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_PLL_SEL_MSK) >> GLB_REG_PLL_SEL_POS; | 
|  | if (tmp == 3) { | 
|  | return MHZ(192) / (hclk_div + 1); | 
|  | } else if (tmp == 2) { | 
|  | return MHZ(160) / (hclk_div + 1); | 
|  | } else if (tmp == 1) { | 
|  | return MHZ(120) / (hclk_div + 1); | 
|  | } else if (tmp == 0) { | 
|  | return MHZ(48) / (hclk_div + 1); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* most peripherals clock */ | 
|  | static uint32_t clock_control_bl60x_get_bclk(const struct device *dev) | 
|  | { | 
|  | uint32_t tmp; | 
|  | uint32_t clock_id; | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_BCLK_DIV_MSK) >> GLB_REG_BCLK_DIV_POS; | 
|  | clock_id = clock_control_bl60x_get_clk(dev); | 
|  | return clock_id / (tmp + 1); | 
|  | } | 
|  |  | 
|  | static uint32_t clock_control_bl60x_mtimer_get_clk_src_div(const struct device *dev) | 
|  | { | 
|  | return clock_control_bl60x_get_bclk(dev) / 1000 / 1000 - 1; | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_cache_2T(bool yes) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(L1C_BASE + L1C_CONFIG_OFFSET); | 
|  |  | 
|  | if (yes) { | 
|  | tmp |= L1C_IROM_2T_ACCESS_MSK; | 
|  | } else { | 
|  | tmp &= ~L1C_IROM_2T_ACCESS_MSK; | 
|  | } | 
|  |  | 
|  | sys_write32(tmp, L1C_BASE + L1C_CONFIG_OFFSET); | 
|  | } | 
|  |  | 
|  | /* HCLK: 0 | 
|  | * PLL120M: 1 | 
|  | */ | 
|  | static void clock_control_bl60x_set_PKA_clock(uint32_t pka_clock) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_SWRST_CFG2_OFFSET); | 
|  | tmp = (tmp & GLB_PKA_CLK_SEL_UMSK) | (pka_clock << GLB_PKA_CLK_SEL_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_SWRST_CFG2_OFFSET); | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_init_root_as_pll(const struct device *dev) | 
|  | { | 
|  | struct clock_control_bl60x_data *data = dev->data; | 
|  | const struct clock_control_bl60x_config *config = dev->config; | 
|  | uint32_t tmp; | 
|  |  | 
|  | clock_control_bl60x_init_pll(data->pll.source, config->crystal_id); | 
|  |  | 
|  | /* enable all 'PDS' clocks */ | 
|  | tmp = sys_read32(PDS_BASE + PDS_CLKPLL_OUTPUT_EN_OFFSET); | 
|  | tmp |= 0x1FF; | 
|  | sys_write32(tmp, PDS_BASE + PDS_CLKPLL_OUTPUT_EN_OFFSET); | 
|  |  | 
|  | /* glb enable pll actual? */ | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_PLL_EN_UMSK) | (1U << GLB_REG_PLL_EN_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_select_PLL(data->root.pll_select); | 
|  |  | 
|  | if (data->pll.source == bl60x_clkid_clk_crystal) { | 
|  | clock_control_bl60x_set_root_clock(3); | 
|  | } else { | 
|  | clock_control_bl60x_set_root_clock(2); | 
|  | } | 
|  |  | 
|  | if (clock_control_bl60x_get_clk(dev) > MHZ(120)) { | 
|  | clock_control_bl60x_cache_2T(true); | 
|  | } | 
|  |  | 
|  | sys_write32(clock_control_bl60x_get_clk(dev), CORECLOCKREGISTER); | 
|  | clock_control_bl60x_set_PKA_clock(1); | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_init_root_as_crystal(const struct device *dev) | 
|  | { | 
|  | clock_control_bl60x_set_root_clock(1); | 
|  | sys_write32(clock_control_bl60x_get_clk(dev), CORECLOCKREGISTER); | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_update_root(const struct device *dev) | 
|  | { | 
|  | struct clock_control_bl60x_data *data = dev->data; | 
|  | uint32_t tmp; | 
|  | int ret; | 
|  |  | 
|  | /* make sure all clocks are enabled */ | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  | tmp = (tmp & GLB_REG_BCLK_EN_UMSK) | (1U << GLB_REG_BCLK_EN_POS); | 
|  | tmp = (tmp & GLB_REG_HCLK_EN_UMSK) | (1U << GLB_REG_HCLK_EN_POS); | 
|  | tmp = (tmp & GLB_REG_FCLK_EN_UMSK) | (1U << GLB_REG_FCLK_EN_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); | 
|  |  | 
|  | /* set root clock to internal 32MHz Oscillator as failsafe */ | 
|  | clock_control_bl60x_set_root_clock(0); | 
|  | if (clock_control_bl60x_set_root_clock_dividers(0, 0) != 0) { | 
|  | return -EIO; | 
|  | } | 
|  | sys_write32(BFLB_RC32M_FREQUENCY, CORECLOCKREGISTER); | 
|  |  | 
|  | clock_control_bl60x_set_PKA_clock(0); | 
|  |  | 
|  | if (data->crystal_enabled) { | 
|  | if (clock_control_bl60x_init_crystal() < 0) { | 
|  | return -EIO; | 
|  | } | 
|  | } else { | 
|  | clock_control_bl60x_deinit_crystal(); | 
|  | } | 
|  |  | 
|  | ret = clock_control_bl60x_set_root_clock_dividers(data->root.divider - 1, | 
|  | data->bclk.divider - 1); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (data->root.source == bl60x_clkid_clk_pll) { | 
|  | clock_control_bl60x_init_root_as_pll(dev); | 
|  | } else if (data->root.source == bl60x_clkid_clk_crystal) { | 
|  | clock_control_bl60x_init_root_as_crystal(dev); | 
|  | } else { | 
|  | /* Root clock already setup as RC32M */ | 
|  | } | 
|  |  | 
|  | ret = clock_control_bl60x_clock_trim_32M(); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | clock_control_bl60x_set_machine_timer_clock( | 
|  | 1, 0, clock_control_bl60x_mtimer_get_clk_src_div(dev)); | 
|  |  | 
|  | clock_control_bl60x_clock_settle(); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void clock_control_bl60x_uart_set_clock_enable(bool enable) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); | 
|  | if (enable) { | 
|  | tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (1U << GLB_UART_CLK_EN_POS); | 
|  | } else { | 
|  | tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (0U << GLB_UART_CLK_EN_POS); | 
|  | } | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG2_OFFSET); | 
|  | } | 
|  |  | 
|  | /* Clock: | 
|  | * FCLK: 0 | 
|  | * 160 Mhz PLL: 1 | 
|  | * When using PLL root clock, we can use either setting, when using the 32Mhz Oscillator with a | 
|  | * uninitialized PLL, only FCLK will be available. | 
|  | */ | 
|  | static void clock_control_bl60x_uart_set_clock(bool enable, uint32_t clock, uint32_t divider) | 
|  | { | 
|  | uint32_t tmp; | 
|  |  | 
|  | if (divider > 0x7) { | 
|  | divider = 0x7; | 
|  | } | 
|  | if (clock > 1) { | 
|  | clock = 1; | 
|  | } | 
|  | /* disable uart clock */ | 
|  | clock_control_bl60x_uart_set_clock_enable(false); | 
|  |  | 
|  | tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); | 
|  | tmp = (tmp & GLB_UART_CLK_DIV_UMSK) | (divider << GLB_UART_CLK_DIV_POS); | 
|  | sys_write32(tmp, GLB_BASE + GLB_CLK_CFG2_OFFSET); | 
|  |  | 
|  | tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | 
|  | tmp = (tmp & HBN_UART_CLK_SEL_UMSK) | (clock << HBN_UART_CLK_SEL_POS); | 
|  | sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_uart_set_clock_enable(enable); | 
|  | } | 
|  |  | 
|  | /* Simple function to enable all peripherals for now */ | 
|  | static void clock_control_bl60x_peripheral_clock_init(void) | 
|  | { | 
|  | uint32_t regval = sys_read32(GLB_BASE + GLB_CGEN_CFG1_OFFSET); | 
|  |  | 
|  | /* enable ADC clock routing */ | 
|  | regval |= (1 << 2); | 
|  | /* enable UART0 clock routing */ | 
|  | regval |= (1 << 16); | 
|  | /* enable I2C0 clock routing */ | 
|  | regval |= (1 << 19); | 
|  |  | 
|  | sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); | 
|  |  | 
|  | clock_control_bl60x_uart_set_clock(1, 0, 0); | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_on(const struct device *dev, clock_control_subsys_t sys) | 
|  | { | 
|  | struct clock_control_bl60x_data *data = dev->data; | 
|  | int ret = -EINVAL; | 
|  | uint32_t key; | 
|  | enum bl60x_clkid oldroot; | 
|  |  | 
|  | key = irq_lock(); | 
|  |  | 
|  | if ((enum bl60x_clkid)sys == bl60x_clkid_clk_crystal) { | 
|  | if (data->crystal_enabled) { | 
|  | ret = 0; | 
|  | } else { | 
|  | data->crystal_enabled = true; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->crystal_enabled = false; | 
|  | } | 
|  | } | 
|  | } else if ((enum bl60x_clkid)sys == bl60x_clkid_clk_pll) { | 
|  | if (data->pll_enabled) { | 
|  | ret = 0; | 
|  | } else { | 
|  | data->pll_enabled = true; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->pll_enabled = false; | 
|  | } | 
|  | } | 
|  | } else if ((int)sys == BFLB_FORCE_ROOT_RC32M) { | 
|  | if (data->root.source == bl60x_clkid_clk_rc32m) { | 
|  | ret = 0; | 
|  | } else { | 
|  | /* Cannot fail to set root to rc32m */ | 
|  | data->root.source = bl60x_clkid_clk_rc32m; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | } | 
|  | } else if ((int)sys == BFLB_FORCE_ROOT_CRYSTAL) { | 
|  | if (data->root.source == bl60x_clkid_clk_crystal) { | 
|  | ret = 0; | 
|  | } else { | 
|  | oldroot = data->root.source; | 
|  | data->root.source = bl60x_clkid_clk_crystal; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->root.source = oldroot; | 
|  | } | 
|  | } | 
|  | } else if ((int)sys == BFLB_FORCE_ROOT_PLL) { | 
|  | if (data->root.source == bl60x_clkid_clk_pll) { | 
|  | ret = 0; | 
|  | } else { | 
|  | oldroot = data->root.source; | 
|  | data->root.source = bl60x_clkid_clk_pll; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->root.source = oldroot; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | irq_unlock(key); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_off(const struct device *dev, clock_control_subsys_t sys) | 
|  | { | 
|  | struct clock_control_bl60x_data *data = dev->data; | 
|  | int ret = -EINVAL; | 
|  | uint32_t key; | 
|  |  | 
|  | key = irq_lock(); | 
|  |  | 
|  | if ((enum bl60x_clkid)sys == bl60x_clkid_clk_crystal) { | 
|  | if (!data->crystal_enabled) { | 
|  | ret = 0; | 
|  | } else { | 
|  | data->crystal_enabled = false; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->crystal_enabled = true; | 
|  | } | 
|  | } | 
|  | } else if ((enum bl60x_clkid)sys == bl60x_clkid_clk_pll) { | 
|  | if (!data->pll_enabled) { | 
|  | ret = 0; | 
|  | } else { | 
|  | data->pll_enabled = false; | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | data->pll_enabled = true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | irq_unlock(key); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static enum clock_control_status clock_control_bl60x_get_status(const struct device *dev, | 
|  | clock_control_subsys_t sys) | 
|  | { | 
|  | struct clock_control_bl60x_data *data = dev->data; | 
|  |  | 
|  | switch ((enum bl60x_clkid)sys) { | 
|  | case bl60x_clkid_clk_root: | 
|  | case bl60x_clkid_clk_bclk: | 
|  | case bl60x_clkid_clk_rc32m: | 
|  | return CLOCK_CONTROL_STATUS_ON; | 
|  | case bl60x_clkid_clk_crystal: | 
|  | if (data->crystal_enabled) { | 
|  | return CLOCK_CONTROL_STATUS_ON; | 
|  | } | 
|  | return CLOCK_CONTROL_STATUS_OFF; | 
|  | case bl60x_clkid_clk_pll: | 
|  | if (data->pll_enabled) { | 
|  | return CLOCK_CONTROL_STATUS_ON; | 
|  | } | 
|  | return CLOCK_CONTROL_STATUS_OFF; | 
|  | default: | 
|  | return CLOCK_CONTROL_STATUS_UNKNOWN; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_get_rate(const struct device *dev, clock_control_subsys_t sys, | 
|  | uint32_t *rate) | 
|  | { | 
|  | if ((enum bl60x_clkid)sys == bl60x_clkid_clk_root) { | 
|  | *rate = clock_control_bl60x_get_clk(dev); | 
|  | } else if ((enum bl60x_clkid)sys == bl60x_clkid_clk_bclk) { | 
|  | *rate = clock_control_bl60x_get_bclk(dev); | 
|  | } else if ((enum bl60x_clkid)sys == bl60x_clkid_clk_crystal) { | 
|  | *rate = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency); | 
|  | } else if ((enum bl60x_clkid)sys == bl60x_clkid_clk_rc32m) { | 
|  | *rate = BFLB_RC32M_FREQUENCY; | 
|  | } else { | 
|  | return -EINVAL; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int clock_control_bl60x_init(const struct device *dev) | 
|  | { | 
|  | int ret; | 
|  | uint32_t key; | 
|  |  | 
|  | key = irq_lock(); | 
|  |  | 
|  | ret = clock_control_bl60x_update_root(dev); | 
|  | if (ret < 0) { | 
|  | irq_unlock(key); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | clock_control_bl60x_peripheral_clock_init(); | 
|  |  | 
|  | irq_unlock(key); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static DEVICE_API(clock_control, clock_control_bl60x_api) = { | 
|  | .on = clock_control_bl60x_on, | 
|  | .off = clock_control_bl60x_off, | 
|  | .get_rate = clock_control_bl60x_get_rate, | 
|  | .get_status = clock_control_bl60x_get_status, | 
|  | }; | 
|  |  | 
|  | static const struct clock_control_bl60x_config clock_control_bl60x_config = { | 
|  | .crystal_id = CRYSTAL_FREQ_TO_ID(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), | 
|  | clock_frequency)), | 
|  | }; | 
|  |  | 
|  | static struct clock_control_bl60x_data clock_control_bl60x_data = { | 
|  | .crystal_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)), | 
|  | .pll_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_192)), | 
|  |  | 
|  | .root = { | 
|  | #if CLK_SRC_IS(root, pll_192) | 
|  | .source = bl60x_clkid_clk_pll, | 
|  | .pll_select = DT_CLOCKS_CELL(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), select), | 
|  | #elif CLK_SRC_IS(root, crystal) | 
|  | .source = bl60x_clkid_clk_crystal, | 
|  | #else | 
|  | .source = bl60x_clkid_clk_rc32m, | 
|  | #endif | 
|  | .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), divider), | 
|  | }, | 
|  |  | 
|  | .pll = { | 
|  | #if CLK_SRC_IS(pll_192, crystal) | 
|  | .source = bl60x_clkid_clk_crystal, | 
|  | #else | 
|  | .source = bl60x_clkid_clk_rc32m, | 
|  | #endif | 
|  | }, | 
|  |  | 
|  | .bclk = { | 
|  | .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, bclk), divider), | 
|  | }, | 
|  | }; | 
|  |  | 
|  | BUILD_ASSERT(CLK_SRC_IS(pll_192, crystal) || CLK_SRC_IS(root, crystal) | 
|  | ? DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)) | 
|  | : 1, | 
|  | "Crystal must be enabled to use it"); | 
|  |  | 
|  | BUILD_ASSERT(CLK_SRC_IS(root, pll_192) ? | 
|  | DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_192)) : 1, | 
|  | "PLL must be enabled to use it"); | 
|  |  | 
|  | BUILD_ASSERT(DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m)), "RC32M is always on"); | 
|  |  | 
|  | BUILD_ASSERT(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m), clock_frequency) | 
|  | == BFLB_RC32M_FREQUENCY, "RC32M must be 32M"); | 
|  |  | 
|  | DEVICE_DT_INST_DEFINE(0, clock_control_bl60x_init, NULL, &clock_control_bl60x_data, | 
|  | &clock_control_bl60x_config, PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, | 
|  | &clock_control_bl60x_api); |