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