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; return -ENOTSUP;
} }
if (pclken->div) {
*rate /= (pclken->div + 1);
}
return 0; return 0;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -67,6 +67,17 @@ description: |
should be the one matching SoC reset state. Confere reference manual to check 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. 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" compatible: "st,stm32-rcc"
include: [clock-controller.yaml, base.yaml] include: [clock-controller.yaml, base.yaml]

View file

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

View file

@ -23,4 +23,9 @@
#define STM32_CLOCK_BUS_AXI 13 #define STM32_CLOCK_BUS_AXI 13
#define STM32_CLOCK_BUS_MLAHB 14 #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_ */ #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_CLOCK_H_ */

View file

@ -15,6 +15,11 @@
/** Dummy: Add a specifier when no selection is possible */ /** Dummy: Add a specifier when no selection is possible */
#define NO_SEL 0xFF #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 */ /** STM32 MCO configuration values */
#define STM32_MCO_CFGR_REG_MASK 0xFFFFU #define STM32_MCO_CFGR_REG_MASK 0xFFFFU
#define STM32_MCO_CFGR_REG_SHIFT 0U #define STM32_MCO_CFGR_REG_SHIFT 0U