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:
parent
db43d2c4c1
commit
fafaa58240
11 changed files with 72 additions and 12 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue