drivers: clock: stm32: support STM32_CLOCK_DIV()

Support specifying divided clock buses by introduction of
STM32_CLOCK_DIV(div) macro. This macro can be used in devicetree to define
clock source of peripherals.

HSE is selected in devicetree using:

   <&rcc STM32_SRC_HSE ...>;

HSE/2 can now be selected with:

   <&rcc (STM32_SRC_HSE | STM32_CLOCK_DIV(2)) ...>;

This allows to use clock_control_get_rate() API in peripherals in order to
get desired clock rate.

Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
This commit is contained in:
Marcin Niestroj 2024-12-05 19:55:48 +01:00 committed by Benjamin Cabé
commit fafaa58240
11 changed files with 72 additions and 12 deletions

View file

@ -469,6 +469,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *clock,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -342,6 +342,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -646,6 +646,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *clock,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -390,6 +390,11 @@ static int stm32_clock_control_get_subsys_rate(const struct device *clock,
default:
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -357,6 +357,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -271,10 +271,10 @@ static inline int stm32_clock_control_configure(const struct device *dev,
return 0;
}
static inline int get_apb0_periph_clkrate(uint32_t enr, uint32_t *rate,
uint32_t slow_clock, uint32_t sysclk, uint32_t clk_sys)
static inline int get_apb0_periph_clkrate(struct stm32_pclken *pclken,
uint32_t *rate, uint32_t slow_clock, uint32_t sysclk, uint32_t clk_sys)
{
switch (enr) {
switch (pclken->enr) {
/* Slow clock peripherals: RTC & IWDG */
case LL_APB0_GRP1_PERIPH_RTC:
case LL_APB0_GRP1_PERIPH_WDG:
@ -305,13 +305,17 @@ static inline int get_apb0_periph_clkrate(uint32_t enr, uint32_t *rate,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}
static inline int get_apb1_periph_clkrate(uint32_t enr, uint32_t *rate,
uint32_t clk_sys)
static inline int get_apb1_periph_clkrate(struct stm32_pclken *pclken,
uint32_t *rate, uint32_t clk_sys)
{
switch (enr) {
switch (pclken->enr) {
#if defined(SPI1)
case LL_APB1_GRP1_PERIPH_SPI1:
*rate = clk_sys;
@ -387,6 +391,10 @@ static inline int get_apb1_periph_clkrate(uint32_t enr, uint32_t *rate,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}
@ -457,11 +465,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
*rate = clk_sys;
break;
case STM32_CLOCK_BUS_APB0:
return get_apb0_periph_clkrate(pclken->enr, rate,
slow_clock, sysclk, clk_sys);
return get_apb0_periph_clkrate(pclken, rate, slow_clock,
sysclk, clk_sys);
case STM32_CLOCK_BUS_APB1:
return get_apb1_periph_clkrate(pclken->enr, rate,
clk_sys);
return get_apb1_periph_clkrate(pclken, rate, clk_sys);
case STM32_SRC_SYSCLK:
*rate = sysclk;
break;
@ -494,6 +501,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -271,6 +271,10 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
return -ENOTSUP;
}
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0;
}

View file

@ -67,6 +67,17 @@ description: |
should be the one matching SoC reset state. Confere reference manual to check
what is the reset value of the clock source for each peripheral.
Specifying a divided domain clock source:
Some peripherals are sourced through fixed clock dividers. For such cases there is
STM32_CLOCK_DIV() macro, which allows to specify such divider value. Selecting HSE/2 (HSE
frequency divided by 2) is done with following clock property:
... {
...
clocks = <&rcc (STM32_SRC_HSE | STM32_CLOCK_DIV(2)) ...>;
...
}
compatible: "st,stm32-rcc"
include: [clock-controller.yaml, base.yaml]

View file

@ -431,7 +431,8 @@
/** Driver structure definition */
struct stm32_pclken {
uint32_t bus;
uint32_t bus : STM32_CLOCK_DIV_SHIFT;
uint32_t div : (32 - STM32_CLOCK_DIV_SHIFT);
uint32_t enr;
};
@ -440,7 +441,9 @@ struct stm32_pclken {
#define STM32_CLOCK_INFO(clk_index, node_id) \
{ \
.enr = DT_CLOCKS_CELL_BY_IDX(node_id, clk_index, bits), \
.bus = DT_CLOCKS_CELL_BY_IDX(node_id, clk_index, bus) \
.bus = DT_CLOCKS_CELL_BY_IDX(node_id, clk_index, bus) & 0xff, \
.div = DT_CLOCKS_CELL_BY_IDX(node_id, clk_index, bus) >> \
STM32_CLOCK_DIV_SHIFT, \
}
#define STM32_DT_CLOCKS(node_id) \
{ \

View file

@ -23,4 +23,9 @@
#define STM32_CLOCK_BUS_AXI 13
#define STM32_CLOCK_BUS_MLAHB 14
#define STM32_CLOCK_DIV_SHIFT 12
/** Clock divider */
#define STM32_CLOCK_DIV(div) (((div) - 1) << STM32_CLOCK_DIV_SHIFT)
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_CLOCK_H_ */

View file

@ -15,6 +15,11 @@
/** Dummy: Add a specifier when no selection is possible */
#define NO_SEL 0xFF
#define STM32_CLOCK_DIV_SHIFT 12
/** Clock divider */
#define STM32_CLOCK_DIV(div) (((div) - 1) << STM32_CLOCK_DIV_SHIFT)
/** STM32 MCO configuration values */
#define STM32_MCO_CFGR_REG_MASK 0xFFFFU
#define STM32_MCO_CFGR_REG_SHIFT 0U