1 /*
2 * Copyright (C) 2025 Savoir-faire Linux, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <soc.h>
8 #include <stm32_ll_bus.h>
9 #include <stm32_ll_rcc.h>
10 #include <zephyr/arch/cpu.h>
11 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
12 #include <zephyr/sys/util.h>
13
stm32_clock_control_on(const struct device * dev,clock_control_subsys_t sub_system)14 static int stm32_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system)
15 {
16 struct stm32_pclken *pclken = (struct stm32_pclken *) sub_system;
17
18 ARG_UNUSED(dev);
19
20 if (!IN_RANGE(pclken->bus, STM32_CLOCK_PERIPH_MIN, STM32_CLOCK_PERIPH_MAX)) {
21 /* Attempt to change a wrong periph clock bit */
22 return -ENOTSUP;
23 }
24
25 sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, pclken->enr);
26
27 return 0;
28 }
29
stm32_clock_control_off(const struct device * dev,clock_control_subsys_t sub_system)30 static int stm32_clock_control_off(const struct device *dev, clock_control_subsys_t sub_system)
31 {
32 struct stm32_pclken *pclken = (struct stm32_pclken *) sub_system;
33
34 ARG_UNUSED(dev);
35
36 if (!IN_RANGE(pclken->bus, STM32_CLOCK_PERIPH_MIN, STM32_CLOCK_PERIPH_MAX)) {
37 /* Attempt to toggle a wrong periph clock bit */
38 return -ENOTSUP;
39 }
40
41 sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, pclken->enr);
42
43 return 0;
44 }
45
stm32_clock_control_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)46 static int stm32_clock_control_get_subsys_rate(const struct device *dev,
47 clock_control_subsys_t sub_system, uint32_t *rate)
48 {
49 struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system);
50
51 ARG_UNUSED(dev);
52
53 switch (pclken->bus) {
54 case STM32_CLOCK_PERIPH_USART1:
55 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_USART1_CLKSOURCE);
56 break;
57 case STM32_CLOCK_PERIPH_USART2:
58 case STM32_CLOCK_PERIPH_UART4:
59 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_UART24_CLKSOURCE);
60 break;
61 case STM32_CLOCK_PERIPH_USART3:
62 case STM32_CLOCK_PERIPH_UART5:
63 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_USART35_CLKSOURCE);
64 break;
65 case STM32_CLOCK_PERIPH_USART6:
66 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_USART6_CLKSOURCE);
67 break;
68 case STM32_CLOCK_PERIPH_UART7:
69 case STM32_CLOCK_PERIPH_UART8:
70 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_UART78_CLKSOURCE);
71 break;
72 case STM32_CLOCK_PERIPH_UART9:
73 *rate = LL_RCC_GetUARTClockFreq(LL_RCC_UART9_CLKSOURCE);
74 break;
75 case STM32_CLOCK_PERIPH_I2C1:
76 case STM32_CLOCK_PERIPH_I2C2:
77 *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C12_I3C12_CLKSOURCE);
78 break;
79 case STM32_CLOCK_PERIPH_I2C4:
80 case STM32_CLOCK_PERIPH_I2C6:
81 *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C46_CLKSOURCE);
82 break;
83 case STM32_CLOCK_PERIPH_I2C3:
84 case STM32_CLOCK_PERIPH_I2C5:
85 *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C35_I3C3_CLKSOURCE);
86 break;
87 case STM32_CLOCK_PERIPH_I2C7:
88 *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C7_CLKSOURCE);
89 break;
90 case STM32_CLOCK_PERIPH_I2C8:
91 *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C8_CLKSOURCE);
92 break;
93 default:
94 return -ENOTSUP;
95 }
96
97 return 0;
98 }
99
100 static DEVICE_API(clock_control, stm32_clock_control_api) = {
101 .on = stm32_clock_control_on,
102 .off = stm32_clock_control_off,
103 .get_rate = stm32_clock_control_get_subsys_rate,
104 };
105
stm32_clock_control_init(const struct device * dev)106 static int stm32_clock_control_init(const struct device *dev)
107 {
108 ARG_UNUSED(dev);
109 return 0;
110 }
111
112 /**
113 * @brief RCC device, note that priority is intentionally set to 1 so
114 * that the device init runs just after SOC init
115 */
116 DEVICE_DT_DEFINE(DT_NODELABEL(rcc), stm32_clock_control_init, NULL, NULL, NULL, PRE_KERNEL_1,
117 CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &stm32_clock_control_api);
118