clock control:stm32: provide STM32Cube LL based driver
This new clock control driver aims at providing a lightweight generic driver to the whole stm32 family. Driver is based on LL Cube API and hence is for now available only for STM32 supporting this API: stm32f3xx and stm32l4xx. Other families should be supported soon. Once globally supported, this unique driver will also help reducing the impact of stm32 clock control heterogeneity in other drivers. Change-Id: Id15a8d0d44f03809b2907ef10d6877700459e674 Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
This commit is contained in:
parent
b4b395845a
commit
58c8d15147
@ -44,6 +44,8 @@ source "drivers/clock_control/Kconfig.nrf5"
|
||||
|
||||
source "drivers/clock_control/Kconfig.quark_se"
|
||||
|
||||
source "drivers/clock_control/Kconfig.stm32"
|
||||
|
||||
source "drivers/clock_control/Kconfig.stm32f10x"
|
||||
|
||||
source "drivers/clock_control/Kconfig.stm32f107xx"
|
||||
|
||||
186
drivers/clock_control/Kconfig.stm32
Normal file
186
drivers/clock_control/Kconfig.stm32
Normal file
@ -0,0 +1,186 @@
|
||||
# Kconfig - STM32 MCU clock control driver config
|
||||
#
|
||||
# Copyright (c) 2017 Linaro
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
if SOC_FAMILY_STM32
|
||||
|
||||
menuconfig CLOCK_CONTROL_STM32_CUBE
|
||||
bool
|
||||
prompt "STM32 Reset & Clock Control"
|
||||
depends on CLOCK_CONTROL
|
||||
default n if SOC_SERIES_STM32
|
||||
help
|
||||
Enable driver for Reset & Clock Control subsystem found
|
||||
in STM32 family of MCUs
|
||||
|
||||
config CLOCK_CONTROL_STM32_DEVICE_INIT_PRIORITY
|
||||
int "Clock Control Device Priority"
|
||||
default 1
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
help
|
||||
This option controls the priority of clock control
|
||||
device initialization. Higher priority ensures that the device
|
||||
is initialized earlier in the startup cycle. If unsure, leave
|
||||
at default value 1
|
||||
|
||||
choice
|
||||
prompt "STM32 System Clock Source"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
default CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
|
||||
config CLOCK_STM32_SYSCLK_SRC_HSE
|
||||
bool "HSE"
|
||||
help
|
||||
Use HSE as source of SYSCLK
|
||||
|
||||
config CLOCK_STM32_SYSCLK_SRC_HSI
|
||||
bool "HSI"
|
||||
help
|
||||
Use HSI as source of SYSCLK
|
||||
|
||||
config CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
bool "PLL"
|
||||
help
|
||||
Use PLL as source of SYSCLK
|
||||
|
||||
endchoice
|
||||
|
||||
config CLOCK_STM32_HSE_BYPASS
|
||||
bool "HSE bypass"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && (CLOCK_STM32_SYSCLK_SRC_HSE || CLOCK_STM32_PLL_SRC_HSE)
|
||||
help
|
||||
Enable this option to bypass external high-speed clock (HSE).
|
||||
|
||||
config CLOCK_STM32_HSE_CLOCK
|
||||
int "HSE clock value"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && (CLOCK_STM32_SYSCLK_SRC_HSE || CLOCK_STM32_PLL_SRC_HSE)
|
||||
help
|
||||
Value of external high-speed clock (HSE).
|
||||
|
||||
choice
|
||||
prompt "STM32 PLL Clock Source"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default CLOCK_STM32_PLL_SRC_HSI
|
||||
|
||||
config CLOCK_STM32_PLL_SRC_MSI
|
||||
bool "MSI"
|
||||
help
|
||||
Use MSI as source of PLL
|
||||
|
||||
config CLOCK_STM32_PLL_SRC_HSI
|
||||
bool "HSI"
|
||||
help
|
||||
Use HSI as source of PLL
|
||||
|
||||
config CLOCK_STM32_PLL_SRC_HSE
|
||||
bool "HSE"
|
||||
help
|
||||
Use HSE as source of PLL
|
||||
endchoice
|
||||
|
||||
if SOC_SERIES_STM32F3X
|
||||
|
||||
config CLOCK_STM32_PLL_PREDIV
|
||||
int "PREDIV Prescaler"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
default 1
|
||||
range 1 16
|
||||
help
|
||||
PREDIV is PLLSCR clock signal prescaler, allowed values: 1 - 16.
|
||||
|
||||
config CLOCK_STM32_PLL_PREDIV1
|
||||
int "PREDIV1 Prescaler"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_PLL_SRC_HSE && (SOC_STM32F302XE || SOC_STM32F303XE || SOC_STM32F398XX)
|
||||
default 1
|
||||
range 1 16
|
||||
help
|
||||
PREDIV is PLLSCR clock signal prescaler, present on STM32F302xE, STM32F303xE and STM32F39xx SoCs.
|
||||
Allowed values: 1 - 16.
|
||||
|
||||
config CLOCK_STM32_PLL_MULTIPLIER
|
||||
int "PLL multiplier"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 9
|
||||
range 2 16
|
||||
help
|
||||
PLL multiplier, allowed values: 2-16. PLL output must not exceed 72MHz.
|
||||
|
||||
endif # SOC_SERIES_STM32F3X
|
||||
|
||||
if SOC_SERIES_STM32L4X
|
||||
|
||||
config CLOCK_STM32_PLL_M_DIVISOR
|
||||
int "PLL divisor"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 1
|
||||
range 1 8
|
||||
help
|
||||
PLL divisor, allowed values: 1-8. With this ensure that the PLL
|
||||
VCO input frequency ranges from 4 to 16MHz.
|
||||
|
||||
config CLOCK_STM32_PLL_N_MULTIPLIER
|
||||
int "PLL multiplier"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 20
|
||||
range 8 86
|
||||
help
|
||||
PLL multiplier, allowed values: 2-16. PLL output must not
|
||||
exceed 344MHz.
|
||||
|
||||
config CLOCK_STM32_PLL_P_DIVISOR
|
||||
int "PLL P Divisor"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 7
|
||||
range 0 17
|
||||
help
|
||||
PLL P Output divisor, allowed values: 0, 7, 17.
|
||||
|
||||
config CLOCK_STM32_PLL_Q_DIVISOR
|
||||
int "PLL Q Divisor"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 2
|
||||
range 0 8
|
||||
help
|
||||
PLL Q Output divisor, allowed values: 0, 2, 4, 6, 8.
|
||||
|
||||
config CLOCK_STM32_PLL_R_DIVISOR
|
||||
int "PLL R Divisor"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE && CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
default 4
|
||||
range 0 8
|
||||
help
|
||||
PLL R Output divisor, allowed values: 0, 2, 4, 6, 8.
|
||||
|
||||
endif # SOC_SERIES_STM32L4X
|
||||
|
||||
config CLOCK_STM32_AHB_PRESCALER
|
||||
int "AHB prescaler"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
default 0
|
||||
range 0 512
|
||||
help
|
||||
AHB prescaler, allowed values: 1, 2, 4, 8, 16, 64, 128,
|
||||
256, 512.
|
||||
|
||||
config CLOCK_STM32_APB1_PRESCALER
|
||||
int "APB1 prescaler"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
default 1
|
||||
range 1 16
|
||||
help
|
||||
APB1 Low speed clock (PCLK1) prescaler, allowed values:
|
||||
1, 2, 4, 8, 16
|
||||
|
||||
config CLOCK_STM32_APB2_PRESCALER
|
||||
int "APB2 prescaler"
|
||||
depends on CLOCK_CONTROL_STM32_CUBE
|
||||
default 1
|
||||
range 1 16
|
||||
help
|
||||
APB2 High speed clock (PCLK2) prescaler, allowed values:
|
||||
1, 2, 4, 8, 16
|
||||
|
||||
endif # SOC_FAMILY_STM32
|
||||
@ -1,8 +1,14 @@
|
||||
obj-$(CONFIG_CLOCK_CONTROL_NRF5) += nrf5_power_clock.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_QUARK_SE) += quark_se_clock_control.o
|
||||
ifeq ($(CONFIG_CLOCK_CONTROL_STM32_CUBE),y)
|
||||
obj-y += stm32_ll_clock.o
|
||||
obj-$(CONFIG_SOC_SERIES_STM32L4X) += stm32l4x_ll_clock.o
|
||||
obj-$(CONFIG_SOC_SERIES_STM32F3X) += stm32f3x_ll_clock.o
|
||||
else
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32F10X) += stm32f10x_clock.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32F10X_CONN_LINE) += stm32f107xx_clock.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32F3X) += stm32f3x_clock.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32F4X) += stm32f4x_clock.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32L4X) += stm32l4x_clock.o
|
||||
endif
|
||||
obj-$(CONFIG_CLOCK_CONTROL_BEETLE) += beetle_clock_control.o
|
||||
|
||||
351
drivers/clock_control/stm32_ll_clock.c
Normal file
351
drivers/clock_control/stm32_ll_clock.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2017 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <soc.h>
|
||||
#include <soc_registers.h>
|
||||
#include <clock_control.h>
|
||||
#include <misc/util.h>
|
||||
#include <clock_control/stm32_clock_control.h>
|
||||
#include "stm32_ll_clock.h"
|
||||
|
||||
/**
|
||||
* @brief helper for mapping a setting to register value
|
||||
*/
|
||||
uint32_t map_reg_val(const struct regval_map *map, size_t cnt, int val)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (map[i].val == val) {
|
||||
return map[i].reg;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief map AHB prescaler setting to register value
|
||||
*/
|
||||
static uint32_t ahb_prescaler(int prescaler)
|
||||
{
|
||||
const struct regval_map ahb_map[] = {
|
||||
{1, LL_RCC_SYSCLK_DIV_1},
|
||||
{2, LL_RCC_SYSCLK_DIV_2},
|
||||
{4, LL_RCC_SYSCLK_DIV_4},
|
||||
{8, LL_RCC_SYSCLK_DIV_8},
|
||||
{16, LL_RCC_SYSCLK_DIV_16},
|
||||
{64, LL_RCC_SYSCLK_DIV_64},
|
||||
{128, LL_RCC_SYSCLK_DIV_128},
|
||||
{256, LL_RCC_SYSCLK_DIV_256},
|
||||
{512, LL_RCC_SYSCLK_DIV_512},
|
||||
};
|
||||
|
||||
return map_reg_val(ahb_map, ARRAY_SIZE(ahb_map), prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief map APB1 prescaler setting to register value
|
||||
*/
|
||||
static uint32_t apb1_prescaler(int prescaler)
|
||||
{
|
||||
const struct regval_map apb1_map[] = {
|
||||
{1, LL_RCC_APB1_DIV_1},
|
||||
{2, LL_RCC_APB1_DIV_2},
|
||||
{4, LL_RCC_APB1_DIV_4},
|
||||
{8, LL_RCC_APB1_DIV_8},
|
||||
{16, LL_RCC_APB1_DIV_16},
|
||||
};
|
||||
|
||||
return map_reg_val(apb1_map, ARRAY_SIZE(apb1_map), prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief map APB2 prescaler setting to register value
|
||||
*/
|
||||
static uint32_t apb2_prescaler(int prescaler)
|
||||
{
|
||||
const struct regval_map apb2_map[] = {
|
||||
{1, LL_RCC_APB2_DIV_1},
|
||||
{2, LL_RCC_APB2_DIV_2},
|
||||
{4, LL_RCC_APB2_DIV_4},
|
||||
{8, LL_RCC_APB2_DIV_8},
|
||||
{16, LL_RCC_APB2_DIV_16},
|
||||
};
|
||||
|
||||
return map_reg_val(apb2_map, ARRAY_SIZE(apb2_map), prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fill in AHB/APB buses configuration structure
|
||||
*/
|
||||
static void config_bus_clk_init(LL_UTILS_ClkInitTypeDef *clk_init)
|
||||
{
|
||||
clk_init->AHBCLKDivider = ahb_prescaler(
|
||||
CONFIG_CLOCK_STM32_AHB_PRESCALER);
|
||||
clk_init->APB1CLKDivider = apb1_prescaler(
|
||||
CONFIG_CLOCK_STM32_APB1_PRESCALER);
|
||||
clk_init->APB2CLKDivider = apb2_prescaler(
|
||||
CONFIG_CLOCK_STM32_APB2_PRESCALER);
|
||||
}
|
||||
|
||||
static uint32_t get_bus_clock(uint32_t clock, uint32_t prescaler)
|
||||
{
|
||||
return clock / prescaler;
|
||||
}
|
||||
|
||||
static inline int stm32_clock_control_on(struct device *dev,
|
||||
clock_control_subsys_t sub_system)
|
||||
{
|
||||
struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system);
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
switch (pclken->bus) {
|
||||
case STM32_CLOCK_BUS_AHB1:
|
||||
LL_AHB1_GRP1_EnableClock(pclken->enr);
|
||||
break;
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
case STM32_CLOCK_BUS_AHB2:
|
||||
LL_AHB2_GRP1_EnableClock(pclken->enr);
|
||||
break;
|
||||
#endif /* CONFIG_SOC_SERIES_STM32L4X */
|
||||
case STM32_CLOCK_BUS_APB1:
|
||||
LL_APB1_GRP1_EnableClock(pclken->enr);
|
||||
break;
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
case STM32_CLOCK_BUS_APB1_2:
|
||||
LL_APB1_GRP2_EnableClock(pclken->enr);
|
||||
break;
|
||||
#endif /* CONFIG_SOC_SERIES_STM32L4X */
|
||||
case STM32_CLOCK_BUS_APB2:
|
||||
LL_APB2_GRP1_EnableClock(pclken->enr);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int stm32_clock_control_off(struct device *dev,
|
||||
clock_control_subsys_t sub_system)
|
||||
{
|
||||
struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system);
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
switch (pclken->bus) {
|
||||
case STM32_CLOCK_BUS_AHB1:
|
||||
LL_AHB1_GRP1_DisableClock(pclken->enr);
|
||||
break;
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
case STM32_CLOCK_BUS_AHB2:
|
||||
LL_AHB2_GRP1_DisableClock(pclken->enr);
|
||||
break;
|
||||
#endif /* CONFIG_SOC_SERIES_STM32L4X */
|
||||
case STM32_CLOCK_BUS_APB1:
|
||||
LL_APB1_GRP1_DisableClock(pclken->enr);
|
||||
break;
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
case STM32_CLOCK_BUS_APB1_2:
|
||||
LL_APB1_GRP2_DisableClock(pclken->enr);
|
||||
break;
|
||||
#endif
|
||||
case STM32_CLOCK_BUS_APB2:
|
||||
LL_APB2_GRP1_DisableClock(pclken->enr);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int stm32_clock_control_get_subsys_rate(struct device *clock,
|
||||
clock_control_subsys_t sub_system,
|
||||
uint32_t *rate)
|
||||
{
|
||||
struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system);
|
||||
/*
|
||||
* Get AHB Clock (= SystemCoreClock = SYSCLK/prescaler)
|
||||
* SystemCoreClock is preferred to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
* since it will be updated after clock configuration and hence
|
||||
* more likely to contain actual clock speed
|
||||
*/
|
||||
uint32_t ahb_clock = SystemCoreClock;
|
||||
uint32_t apb1_clock = get_bus_clock(ahb_clock,
|
||||
CONFIG_CLOCK_STM32_APB1_PRESCALER);
|
||||
uint32_t apb2_clock = get_bus_clock(ahb_clock,
|
||||
CONFIG_CLOCK_STM32_APB2_PRESCALER);
|
||||
|
||||
ARG_UNUSED(clock);
|
||||
|
||||
switch (pclken->bus) {
|
||||
case STM32_CLOCK_BUS_AHB1:
|
||||
case STM32_CLOCK_BUS_AHB2:
|
||||
*rate = ahb_clock;
|
||||
break;
|
||||
case STM32_CLOCK_BUS_APB1:
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
case STM32_CLOCK_BUS_APB1_2:
|
||||
#endif
|
||||
*rate = apb1_clock;
|
||||
break;
|
||||
case STM32_CLOCK_BUS_APB2:
|
||||
*rate = apb2_clock;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static int stm32_clock_control_init(struct device *dev)
|
||||
{
|
||||
LL_UTILS_ClkInitTypeDef s_ClkInitStruct;
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
/* configure clock for AHB/APB buses */
|
||||
config_bus_clk_init((LL_UTILS_ClkInitTypeDef *)&s_ClkInitStruct);
|
||||
|
||||
#ifdef CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
LL_UTILS_PLLInitTypeDef s_PLLInitStruct;
|
||||
|
||||
/* configure PLL input settings */
|
||||
config_pll_init(&s_PLLInitStruct);
|
||||
|
||||
/* Disable PLL before configuration */
|
||||
LL_RCC_PLL_Disable();
|
||||
|
||||
#ifdef CONFIG_CLOCK_STM32_PLL_SRC_MSI
|
||||
/* Switch to PLL with MSI as clock source */
|
||||
LL_PLL_ConfigSystemClock_MSI(&s_PLLInitStruct, &s_ClkInitStruct);
|
||||
|
||||
/* Disable other clocks */
|
||||
LL_RCC_HSI_Disable();
|
||||
LL_RCC_HSE_Disable();
|
||||
|
||||
#elif CONFIG_CLOCK_STM32_PLL_SRC_HSI
|
||||
/* Switch to PLL with HSI as clock source */
|
||||
LL_PLL_ConfigSystemClock_HSI(&s_PLLInitStruct, &s_ClkInitStruct);
|
||||
|
||||
/* Disable other clocks */
|
||||
LL_RCC_HSE_Disable();
|
||||
LL_RCC_MSI_Disable();
|
||||
|
||||
#elif CONFIG_CLOCK_STM32_PLL_SRC_HSE
|
||||
int hse_bypass = LL_UTILS_HSEBYPASS_OFF;
|
||||
|
||||
#ifdef CONFIG_CLOCK_STM32_HSE_BYPASS
|
||||
hse_bypass = LL_UTILS_HSEBYPASS_ON;
|
||||
#endif /* CONFIG_CLOCK_STM32_HSE_BYPASS */
|
||||
|
||||
/* Switch to PLL with HSE as clock source */
|
||||
LL_PLL_ConfigSystemClock_HSE(CONFIG_CLOCK_STM32_HSE_CLOCK, hse_bypass,
|
||||
&s_PLLInitStruct,
|
||||
&s_ClkInitStruct);
|
||||
|
||||
/* Disable other clocks */
|
||||
LL_RCC_HSI_Disable();
|
||||
LL_RCC_MSI_Disable();
|
||||
|
||||
#endif /* CONFIG_CLOCK_STM32_PLL_SRC_... */
|
||||
|
||||
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE
|
||||
|
||||
/* Enable HSE if not enabled */
|
||||
if (LL_RCC_HSE_IsReady() != 1) {
|
||||
/* Check if need to enable HSE bypass feature or not */
|
||||
#ifdef CONFIG_CLOCK_STM32_HSE_BYPASS
|
||||
LL_RCC_HSE_EnableBypass();
|
||||
#else
|
||||
LL_RCC_HSE_DisableBypass();
|
||||
#endif /* CONFIG_CLOCK_STM32_HSE_BYPASS */
|
||||
|
||||
/* Enable HSE */
|
||||
LL_RCC_HSE_Enable();
|
||||
while (LL_RCC_HSE_IsReady() != 1) {
|
||||
/* Wait for HSE ready */
|
||||
}
|
||||
}
|
||||
|
||||
/* Set HSE as SYSCLCK source */
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
|
||||
LL_RCC_SetAHBPrescaler(s_ClkInitStruct.AHBCLKDivider);
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) {
|
||||
}
|
||||
|
||||
/* Update SystemCoreClock variable */
|
||||
LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(
|
||||
CONFIG_CLOCK_STM32_HSE_CLOCK,
|
||||
s_ClkInitStruct.AHBCLKDivider));
|
||||
|
||||
/* Set APB1 & APB2 prescaler*/
|
||||
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
|
||||
LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider);
|
||||
|
||||
/* Set flash latency */
|
||||
/* HSI used as SYSCLK, set latency to 0 */
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
|
||||
/* Disable other clocks */
|
||||
LL_RCC_HSI_Disable();
|
||||
LL_RCC_MSI_Disable();
|
||||
LL_RCC_PLL_Disable();
|
||||
|
||||
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSI
|
||||
|
||||
/* Enable HSI if not enabled */
|
||||
if (LL_RCC_HSI_IsReady() != 1) {
|
||||
/* Enable HSI */
|
||||
LL_RCC_HSI_Enable();
|
||||
while (LL_RCC_HSI_IsReady() != 1) {
|
||||
/* Wait for HSI ready */
|
||||
}
|
||||
}
|
||||
|
||||
/* Set HSI as SYSCLCK source */
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
|
||||
LL_RCC_SetAHBPrescaler(s_ClkInitStruct.AHBCLKDivider);
|
||||
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
|
||||
}
|
||||
|
||||
/* Update SystemCoreClock variable */
|
||||
LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(HSI_VALUE,
|
||||
s_ClkInitStruct.AHBCLKDivider));
|
||||
|
||||
/* Set APB1 & APB2 prescaler*/
|
||||
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
|
||||
LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider);
|
||||
|
||||
/* Set flash latency */
|
||||
/* HSI used as SYSCLK, set latency to 0 */
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
|
||||
/* Disable other clocks */
|
||||
LL_RCC_HSE_Disable();
|
||||
LL_RCC_MSI_Disable();
|
||||
LL_RCC_PLL_Disable();
|
||||
|
||||
#endif /* CONFIG_CLOCK_STM32_SYSCLK_SRC_... */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RCC device, note that priority is intentionally set to 1 so
|
||||
* that the device init runs just after SOC init
|
||||
*/
|
||||
DEVICE_AND_API_INIT(rcc_stm32, STM32_CLOCK_CONTROL_NAME,
|
||||
&stm32_clock_control_init,
|
||||
NULL, NULL,
|
||||
PRE_KERNEL_1,
|
||||
CONFIG_CLOCK_CONTROL_STM32_DEVICE_INIT_PRIORITY,
|
||||
&stm32_clock_control_api);
|
||||
23
drivers/clock_control/stm32_ll_clock.h
Normal file
23
drivers/clock_control/stm32_ll_clock.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2017 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _STM32_LL_CLOCK_H_
|
||||
#define _STM32_LL_CLOCK_H_
|
||||
|
||||
void config_pll_init(LL_UTILS_PLLInitTypeDef *pllinit);
|
||||
|
||||
struct regval_map {
|
||||
int val;
|
||||
uint32_t reg;
|
||||
};
|
||||
|
||||
uint32_t map_reg_val(const struct regval_map *map, size_t cnt, int val);
|
||||
|
||||
/* */
|
||||
void LL_AHB2_GRP1_EnableClock(uint32_t Periphs);
|
||||
void LL_RCC_MSI_Disable(void);
|
||||
#endif /* _STM32_LL_CLOCK_H_ */
|
||||
73
drivers/clock_control/stm32f3x_ll_clock.c
Normal file
73
drivers/clock_control/stm32f3x_ll_clock.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2017 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <soc.h>
|
||||
#include <soc_registers.h>
|
||||
#include <clock_control.h>
|
||||
#include <misc/util.h>
|
||||
#include <clock_control/stm32_clock_control.h>
|
||||
#include "stm32_ll_clock.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
|
||||
/**
|
||||
* @brief fill in pll configuration structure
|
||||
*/
|
||||
void config_pll_init(LL_UTILS_PLLInitTypeDef *pllinit)
|
||||
{
|
||||
/*
|
||||
* PLL MUL
|
||||
* 2 -> LL_RCC_PLL_MUL_2 -> 0x00000000
|
||||
* 3 -> LL_RCC_PLL_MUL_3 -> 0x00040000
|
||||
* 4 -> LL_RCC_PLL_MUL_4 -> 0x00080000
|
||||
* ...
|
||||
* 16 -> LL_RCC_PLL_MUL_16 -> 0x00380000
|
||||
*/
|
||||
pllinit->PLLMul = ((CONFIG_CLOCK_STM32_PLL_MULTIPLIER - 2)
|
||||
<< RCC_CFGR_PLLMUL_Pos);
|
||||
#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
|
||||
/* PREDIV support is a specific RCC configuration present on */
|
||||
/* following SoCs: STM32F302XE, STM32F303xE and STM32F398xx */
|
||||
/* cf Reference manual for more details */
|
||||
#if defined(CONFIG_CLOCK_STM32_PLL_SRC_HSI)
|
||||
pllinit->PLLDiv = LL_RCC_PLLSOURCE_HSI_DIV_2;
|
||||
#else
|
||||
/*
|
||||
* PLL DIV
|
||||
* 1 -> LL_RCC_PLLSOURCE_HSE_DIV_1 -> 0x00010000
|
||||
* 2 -> LL_RCC_PLLSOURCE_HSE_DIV_2 -> 0x00010001
|
||||
* 3 -> LL_RCC_PLLSOURCE_HSE_DIV_3 -> 0x00010002
|
||||
* ...
|
||||
* 16 -> LL_RCC_PLLSOURCE_HSE_DIV_16 -> 0x0001000F
|
||||
*/
|
||||
pllinit->PLLDiv = (RCC_CFGR_PLLSRC_HSE_PREDIV |
|
||||
(CONFIG_CLOCK_STM32_PLL_PREDIV1 - 1));
|
||||
#endif /* CONFIG_CLOCK_STM32_PLL_SRC_HSI */
|
||||
#else
|
||||
/*
|
||||
* PLL Prediv
|
||||
* 1 -> LL_RCC_PREDIV_DIV_1 -> 0x00000000
|
||||
* 2 -> LL_RCC_PREDIV_DIV_2 -> 0x00000001
|
||||
* 3 -> LL_RCC_PREDIV_DIV_3 -> 0x00000002
|
||||
* ...
|
||||
* 16 -> LL_RCC_PREDIV_DIV_16 -> 0x0000000F
|
||||
*/
|
||||
pllinit->Prediv = CONFIG_CLOCK_STM32_PLL_PREDIV - 1;
|
||||
#endif /* RCC_PLLSRC_PREDIV1_SUPPORT */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL */
|
||||
|
||||
/**
|
||||
* @brief Function kept for driver genericity
|
||||
*/
|
||||
void LL_RCC_MSI_Disable(void)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
62
drivers/clock_control/stm32l4x_ll_clock.c
Normal file
62
drivers/clock_control/stm32l4x_ll_clock.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2017 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <soc.h>
|
||||
#include <soc_registers.h>
|
||||
#include <clock_control.h>
|
||||
#include <misc/util.h>
|
||||
#include <clock_control/stm32_clock_control.h>
|
||||
#include "stm32_ll_clock.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL
|
||||
|
||||
/**
|
||||
* @brief map PLLM setting to register value
|
||||
*/
|
||||
static uint32_t pllm(int prescaler)
|
||||
{
|
||||
const struct regval_map map[] = {
|
||||
{1, LL_RCC_PLLM_DIV_1},
|
||||
{2, LL_RCC_PLLM_DIV_2},
|
||||
{3, LL_RCC_PLLM_DIV_3},
|
||||
{4, LL_RCC_PLLM_DIV_4},
|
||||
{5, LL_RCC_PLLM_DIV_5},
|
||||
{6, LL_RCC_PLLM_DIV_6},
|
||||
{7, LL_RCC_PLLM_DIV_7},
|
||||
{8, LL_RCC_PLLM_DIV_8},
|
||||
};
|
||||
|
||||
return map_reg_val(map, ARRAY_SIZE(map), prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief map PLLR setting to register value
|
||||
*/
|
||||
static uint32_t pllr(int prescaler)
|
||||
{
|
||||
const struct regval_map map[] = {
|
||||
{2, LL_RCC_PLLR_DIV_2},
|
||||
{4, LL_RCC_PLLR_DIV_4},
|
||||
{6, LL_RCC_PLLR_DIV_6},
|
||||
{8, LL_RCC_PLLR_DIV_8},
|
||||
};
|
||||
|
||||
return map_reg_val(map, ARRAY_SIZE(map), prescaler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fill in pll configuration structure
|
||||
*/
|
||||
void config_pll_init(LL_UTILS_PLLInitTypeDef *pllinit)
|
||||
{
|
||||
pllinit->PLLM = pllm(CONFIG_CLOCK_STM32_PLL_M_DIVISOR);
|
||||
pllinit->PLLN = CONFIG_CLOCK_STM32_PLL_N_MULTIPLIER;
|
||||
pllinit->PLLR = pllr(CONFIG_CLOCK_STM32_PLL_R_DIVISOR);
|
||||
}
|
||||
#endif /* CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL */
|
||||
@ -11,6 +11,7 @@ endif
|
||||
ifdef CONFIG_SOC_SERIES_STM32F3X
|
||||
obj-y += stm32f3xx/drivers/src/stm32f3xx_hal.o
|
||||
obj-y += stm32f3xx/drivers/src/stm32f3xx_hal_rcc.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32_CUBE) += stm32f3xx/drivers/src/stm32f3xx_ll_utils.o
|
||||
obj-$(CONFIG_SERIAL_HAS_DRIVER) += stm32f3xx/drivers/src/stm32f3xx_hal_uart.o
|
||||
obj-y += stm32f3xx/soc/system_stm32f3xx.o
|
||||
endif
|
||||
@ -31,6 +32,7 @@ endif
|
||||
ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
obj-y += stm32l4xx/drivers/src/stm32l4xx_hal.o
|
||||
obj-y += stm32l4xx/drivers/src/stm32l4xx_hal_rcc.o
|
||||
obj-$(CONFIG_CLOCK_CONTROL_STM32_CUBE) += stm32l4xx/drivers/src/stm32l4xx_ll_utils.o
|
||||
obj-$(CONFIG_PWM) += stm32l4xx/drivers/src/stm32l4xx_hal_tim.o
|
||||
obj-$(CONFIG_SERIAL_HAS_DRIVER) += stm32l4xx/drivers/src/stm32l4xx_hal_uart.o
|
||||
obj-y += stm32l4xx/soc/system_stm32l4xx.o
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2016 Open-RnD Sp. z o.o.
|
||||
* Copyright (c) 2016 BayLibre, SAS
|
||||
* Copyright (c) 2016 RnDity Sp. z o.o.
|
||||
* Copyright (c) 2017 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -23,4 +24,20 @@
|
||||
#include "stm32l4x_clock_control.h"
|
||||
#endif
|
||||
|
||||
/* Bus */
|
||||
enum {
|
||||
STM32_CLOCK_BUS_AHB1,
|
||||
STM32_CLOCK_BUS_AHB2,
|
||||
STM32_CLOCK_BUS_APB1,
|
||||
#ifdef CONFIG_SOC_SERIES_STM32L4X
|
||||
STM32_CLOCK_BUS_APB1_2,
|
||||
#endif
|
||||
STM32_CLOCK_BUS_APB2,
|
||||
};
|
||||
|
||||
struct stm32_pclken {
|
||||
uint32_t bus;
|
||||
uint32_t enr;
|
||||
};
|
||||
|
||||
#endif /* _STM32_CLOCK_CONTROL_H_ */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user