From 424f937c2b0f3a3dc9c68e2409ff459455423564 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 2 Mar 2022 16:53:31 +0100 Subject: [PATCH] drivers/clock_control: stm32u5: Add support for optional clocks config This change updates stm32u5 driver to support configuration of optional clocks on peripherals. Signed-off-by: Erwan Gouriou --- drivers/clock_control/clock_stm32_ll_u5.c | 135 ++++++++++++++++++ .../zephyr/dt-bindings/clock/stm32u5_clock.h | 5 +- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_stm32_ll_u5.c b/drivers/clock_control/clock_stm32_ll_u5.c index 267f636841b..f4d443b2f3c 100644 --- a/drivers/clock_control/clock_stm32_ll_u5.c +++ b/drivers/clock_control/clock_stm32_ll_u5.c @@ -71,6 +71,57 @@ static uint32_t get_startup_frequency(void) } } +__unused +static uint32_t get_pllout_frequency(uint32_t pllsrc_freq, + int pllm_div, + int plln_mul, + int pllout_div) +{ + __ASSERT_NO_MSG(pllm_div && pllout_div); + + return (pllsrc_freq * plln_mul) / + (pllm_div * pllout_div); +} + +static uint32_t get_sysclk_frequency(void) +{ +#if defined(STM32_SYSCLK_SRC_PLL) + return get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_R_DIVISOR); +#elif defined(STM32_SYSCLK_SRC_MSIS) + return get_msis_frequency(); +#elif defined(STM32_SYSCLK_SRC_HSE + return STM32_HSE_FREQ; +#elif defined(STM32_SYSCLK_SRC_HSI)) { + return STM32_HSI_FREQ; +#else + __ASSERT(0, "No SYSCLK Source configured"); + return 0; +#endif + +} + +/** @brief Verifies clock is part of active clock configuration */ +static int enabled_clock(uint32_t src_clk) +{ + if ((src_clk == STM32_SRC_SYSCLK) || + ((src_clk == STM32_SRC_HSE) && IS_ENABLED(STM32_HSE_ENABLED)) || + ((src_clk == STM32_SRC_HSI16) && IS_ENABLED(STM32_HSI_ENABLED)) || + ((src_clk == STM32_SRC_LSE) && IS_ENABLED(STM32_LSE_ENABLED)) || + ((src_clk == STM32_SRC_LSI) && IS_ENABLED(STM32_LSI_ENABLED)) || + ((src_clk == STM32_SRC_MSIS) && IS_ENABLED(STM32_MSIS_ENABLED)) || + ((src_clk == STM32_SRC_MSIK) && IS_ENABLED(STM32_MSIK_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_P) && IS_ENABLED(STM32_PLL_P_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_Q) && IS_ENABLED(STM32_PLL_Q_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_R) && IS_ENABLED(STM32_PLL_R_ENABLED))) { + return 0; + } + + return -ENOTSUP; +} + static inline int stm32_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) { @@ -115,6 +166,35 @@ static inline int stm32_clock_control_off(const struct device *dev, return 0; } +static inline int stm32_clock_control_configure(const struct device *dev, + clock_control_subsys_t sub_system, + void *data) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); + volatile uint32_t *reg; + uint32_t reg_val, dt_val; + int err; + + ARG_UNUSED(dev); + ARG_UNUSED(data); + + err = enabled_clock(pclken->bus); + if (err < 0) { + /* Attempt to configure a src clock not available or not valid */ + return err; + } + + dt_val = STM32U5_CLOCK_VAL_GET(pclken->enr) << + STM32U5_CLOCK_SHIFT_GET(pclken->enr); + reg = (uint32_t *)(DT_REG_ADDR(DT_NODELABEL(rcc)) + + STM32U5_CLOCK_REG_GET(pclken->enr)); + reg_val = *reg; + reg_val |= dt_val; + *reg = reg_val; + + return 0; +} + static int stm32_clock_control_get_subsys_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *rate) @@ -156,6 +236,60 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev, case STM32_CLOCK_BUS_APB3: *rate = apb3_clock; break; + case STM32_SRC_SYSCLK: + *rate = get_sysclk_frequency(); + break; +#if defined(STM32_HSI_ENABLED) + case STM32_SRC_HSI16: + *rate = STM32_HSI_FREQ; + break; +#endif /* STM32_HSI_ENABLED */ +#if defined(STM32_MSIS_ENABLED) + case STM32_SRC_MSIS: + *rate = get_msis_frequency(); + break; +#endif /* STM32_MSIS_ENABLED */ +#if defined(STM32_MSIK_ENABLED) + case STM32_SRC_MSIK: + *rate = __LL_RCC_CALC_MSIK_FREQ(LL_RCC_MSIRANGESEL_RUN, + STM32_MSIK_RANGE << RCC_ICSCR1_MSIKRANGE_Pos); + break; +#endif /* STM32_MSIK_ENABLED */ +#if defined(STM32_HSE_ENABLED) + case STM32_SRC_HSE: + *rate = STM32_HSE_FREQ; + break; +#endif /* STM32_HSE_ENABLED */ +#if defined(STM32_LSE_ENABLED) + case STM32_SRC_LSE: + *rate = STM32_LSE_FREQ; + break; +#endif /* STM32_LSE_ENABLED */ +#if defined(STM32_LSI_ENABLED) + case STM32_SRC_LSI: + *rate = STM32_LSI_FREQ; + break; +#endif /* STM32_LSI_ENABLED */ +#if defined(STM32_PLL_ENABLED) + case STM32_SRC_PLL1_P: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_P_DIVISOR); + break; + case STM32_SRC_PLL1_Q: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_Q_DIVISOR); + break; + case STM32_SRC_PLL1_R: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_R_DIVISOR); + break; +#endif /* STM32_PLL_ENABLED */ default: return -ENOTSUP; } @@ -167,6 +301,7 @@ static struct clock_control_driver_api stm32_clock_control_api = { .on = stm32_clock_control_on, .off = stm32_clock_control_off, .get_rate = stm32_clock_control_get_subsys_rate, + .configure = stm32_clock_control_configure, }; __unused diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index d020d7e802a..99a89e1114b 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -33,6 +33,10 @@ #define STM32_SRC_SYSCLK 0x011 /** Clock muxes */ /* #define STM32_SRC_ICLK 0x012 */ + +#define STM32_SRC_CLOCK_MIN STM32_SRC_PLL1_P +#define STM32_SRC_CLOCK_MAX STM32_SRC_SYSCLK + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x088 #define STM32_CLOCK_BUS_AHB2 0x08C @@ -46,7 +50,6 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB3 - /** * @brief STM32U5 clock configuration bit field. *