| /* |
| * Copyright (c) 2019 STMicroelectronics |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <soc.h> |
| #include <stm32_ll_bus.h> |
| #include <stm32_ll_rcc.h> |
| #include <zephyr/drivers/clock_control.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/drivers/clock_control/stm32_clock_control.h> |
| |
| /** |
| * @brief fill in AHB/APB buses configuration structure |
| */ |
| static inline int stm32_clock_control_on(const struct device *dev, |
| clock_control_subsys_t sub_system) |
| { |
| struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); |
| |
| ARG_UNUSED(dev); |
| |
| switch (pclken->bus) { |
| case STM32_CLOCK_BUS_APB1: |
| LL_APB1_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB2: |
| LL_APB2_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB3: |
| LL_APB3_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB4: |
| LL_APB4_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB5: |
| LL_APB5_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB2: |
| LL_AHB2_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB3: |
| LL_AHB3_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB4: |
| LL_AHB4_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB5: |
| LL_AHB5_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB6: |
| LL_AHB6_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AXI: |
| LL_AXI_GRP1_EnableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_MLAHB: |
| LL_MLAHB_GRP1_EnableClock(pclken->enr); |
| break; |
| default: |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static inline int stm32_clock_control_off(const struct device *dev, |
| clock_control_subsys_t sub_system) |
| { |
| struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); |
| |
| ARG_UNUSED(dev); |
| |
| switch (pclken->bus) { |
| case STM32_CLOCK_BUS_APB1: |
| LL_APB1_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB2: |
| LL_APB2_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB3: |
| LL_APB3_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB4: |
| LL_APB4_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_APB5: |
| LL_APB5_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB2: |
| LL_AHB2_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB3: |
| LL_AHB3_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB4: |
| LL_AHB4_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB5: |
| LL_AHB5_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AHB6: |
| LL_AHB6_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_AXI: |
| LL_AXI_GRP1_DisableClock(pclken->enr); |
| break; |
| case STM32_CLOCK_BUS_MLAHB: |
| LL_MLAHB_GRP1_DisableClock(pclken->enr); |
| break; |
| default: |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static int stm32_clock_control_get_subsys_rate(const struct device *clock, |
| clock_control_subsys_t sub_system, |
| uint32_t *rate) |
| { |
| struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); |
| |
| ARG_UNUSED(clock); |
| |
| switch (pclken->bus) { |
| case STM32_CLOCK_BUS_APB1: |
| switch (pclken->enr) { |
| case LL_APB1_GRP1_PERIPH_TIM2: |
| case LL_APB1_GRP1_PERIPH_TIM3: |
| case LL_APB1_GRP1_PERIPH_TIM4: |
| case LL_APB1_GRP1_PERIPH_TIM5: |
| case LL_APB1_GRP1_PERIPH_TIM6: |
| case LL_APB1_GRP1_PERIPH_TIM7: |
| case LL_APB1_GRP1_PERIPH_TIM12: |
| case LL_APB1_GRP1_PERIPH_TIM13: |
| case LL_APB1_GRP1_PERIPH_TIM14: |
| *rate = LL_RCC_GetTIMGClockFreq(LL_RCC_TIMG1PRES); |
| break; |
| case LL_APB1_GRP1_PERIPH_LPTIM1: |
| *rate = LL_RCC_GetLPTIMClockFreq( |
| LL_RCC_LPTIM1_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_SPI2: |
| case LL_APB1_GRP1_PERIPH_SPI3: |
| *rate = LL_RCC_GetSPIClockFreq(LL_RCC_SPI23_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_USART2: |
| case LL_APB1_GRP1_PERIPH_UART4: |
| *rate = LL_RCC_GetUARTClockFreq( |
| LL_RCC_UART24_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_USART3: |
| case LL_APB1_GRP1_PERIPH_UART5: |
| *rate = LL_RCC_GetUARTClockFreq( |
| LL_RCC_UART35_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_UART7: |
| case LL_APB1_GRP1_PERIPH_UART8: |
| *rate = LL_RCC_GetUARTClockFreq( |
| LL_RCC_UART78_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_I2C1: |
| case LL_APB1_GRP1_PERIPH_I2C2: |
| *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C12_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_I2C3: |
| case LL_APB1_GRP1_PERIPH_I2C5: |
| *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C35_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_SPDIF: |
| *rate = LL_RCC_GetSPDIFRXClockFreq( |
| LL_RCC_SPDIFRX_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_CEC: |
| *rate = LL_RCC_GetCECClockFreq(LL_RCC_CEC_CLKSOURCE); |
| break; |
| case LL_APB1_GRP1_PERIPH_WWDG1: |
| case LL_APB1_GRP1_PERIPH_DAC12: |
| case LL_APB1_GRP1_PERIPH_MDIOS: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_APB2: |
| switch (pclken->enr) { |
| case LL_APB2_GRP1_PERIPH_TIM1: |
| case LL_APB2_GRP1_PERIPH_TIM8: |
| case LL_APB2_GRP1_PERIPH_TIM15: |
| case LL_APB2_GRP1_PERIPH_TIM16: |
| case LL_APB2_GRP1_PERIPH_TIM17: |
| *rate = LL_RCC_GetTIMGClockFreq(LL_RCC_TIMG2PRES); |
| break; |
| case LL_APB2_GRP1_PERIPH_SPI1: |
| *rate = LL_RCC_GetSPIClockFreq(LL_RCC_SPI1_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_SPI4: |
| case LL_APB2_GRP1_PERIPH_SPI5: |
| *rate = LL_RCC_GetSPIClockFreq(LL_RCC_SPI45_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_USART6: |
| *rate = LL_RCC_GetUARTClockFreq( |
| LL_RCC_USART6_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_SAI1: |
| *rate = LL_RCC_GetSAIClockFreq(LL_RCC_SAI1_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_SAI2: |
| *rate = LL_RCC_GetSAIClockFreq(LL_RCC_SAI2_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_SAI3: |
| *rate = LL_RCC_GetSAIClockFreq(LL_RCC_SAI3_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_DFSDM1: |
| *rate = LL_RCC_GetDFSDMClockFreq( |
| LL_RCC_DFSDM_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_FDCAN: |
| *rate = LL_RCC_GetFDCANClockFreq( |
| LL_RCC_FDCAN_CLKSOURCE); |
| break; |
| case LL_APB2_GRP1_PERIPH_ADFSDM1: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_APB3: |
| switch (pclken->enr) { |
| case LL_APB3_GRP1_PERIPH_LPTIM2: |
| case LL_APB3_GRP1_PERIPH_LPTIM3: |
| *rate = LL_RCC_GetLPTIMClockFreq( |
| LL_RCC_LPTIM23_CLKSOURCE); |
| break; |
| case LL_APB3_GRP1_PERIPH_LPTIM4: |
| case LL_APB3_GRP1_PERIPH_LPTIM5: |
| *rate = LL_RCC_GetLPTIMClockFreq( |
| LL_RCC_LPTIM45_CLKSOURCE); |
| break; |
| case LL_APB3_GRP1_PERIPH_SAI4: |
| *rate = LL_RCC_GetSAIClockFreq(LL_RCC_SAI4_CLKSOURCE); |
| break; |
| case LL_APB3_GRP1_PERIPH_SYSCFG: |
| case LL_APB3_GRP1_PERIPH_VREF: |
| case LL_APB3_GRP1_PERIPH_TMPSENS: |
| case LL_APB3_GRP1_PERIPH_HDP: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_APB4: |
| switch (pclken->enr) { |
| case LL_APB4_GRP1_PERIPH_LTDC: |
| *rate = LL_RCC_GetLTDCClockFreq(); |
| break; |
| case LL_APB4_GRP1_PERIPH_DSI: |
| *rate = LL_RCC_GetDSIClockFreq(LL_RCC_DSI_CLKSOURCE); |
| break; |
| case LL_APB4_GRP1_PERIPH_USBPHY: |
| *rate = LL_RCC_GetUSBPHYClockFreq( |
| LL_RCC_USBPHY_CLKSOURCE); |
| break; |
| case LL_APB4_GRP1_PERIPH_DDRPERFM: |
| case LL_APB4_GRP1_PERIPH_STGENRO: |
| case LL_APB4_GRP1_PERIPH_STGENROSTP: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_APB5: |
| switch (pclken->enr) { |
| case LL_APB5_GRP1_PERIPH_SPI6: |
| *rate = LL_RCC_GetSPIClockFreq(LL_RCC_SPI6_CLKSOURCE); |
| break; |
| case LL_APB5_GRP1_PERIPH_I2C4: |
| case LL_APB5_GRP1_PERIPH_I2C6: |
| *rate = LL_RCC_GetI2CClockFreq(LL_RCC_I2C46_CLKSOURCE); |
| break; |
| case LL_APB5_GRP1_PERIPH_USART1: |
| *rate = LL_RCC_GetUARTClockFreq( |
| LL_RCC_USART1_CLKSOURCE); |
| break; |
| case LL_APB5_GRP1_PERIPH_STGEN: |
| case LL_APB5_GRP1_PERIPH_STGENSTP: |
| *rate = LL_RCC_GetSTGENClockFreq( |
| LL_RCC_STGEN_CLKSOURCE); |
| break; |
| case LL_APB5_GRP1_PERIPH_RTCAPB: |
| *rate = LL_RCC_GetRTCClockFreq(); |
| break; |
| case LL_APB5_GRP1_PERIPH_TZC1: |
| case LL_APB5_GRP1_PERIPH_TZC2: |
| case LL_APB5_GRP1_PERIPH_TZPC: |
| case LL_APB5_GRP1_PERIPH_BSEC: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_AHB2: |
| switch (pclken->enr) { |
| case LL_AHB2_GRP1_PERIPH_ADC12: |
| *rate = LL_RCC_GetADCClockFreq(LL_RCC_ADC_CLKSOURCE); |
| break; |
| case LL_AHB2_GRP1_PERIPH_USBO: |
| *rate = LL_RCC_GetUSBOClockFreq(LL_RCC_USBO_CLKSOURCE); |
| break; |
| case LL_AHB2_GRP1_PERIPH_SDMMC3: |
| *rate = LL_RCC_GetSDMMCClockFreq( |
| LL_RCC_SDMMC3_CLKSOURCE); |
| break; |
| case LL_AHB2_GRP1_PERIPH_DMA1: |
| case LL_AHB2_GRP1_PERIPH_DMA2: |
| case LL_AHB2_GRP1_PERIPH_DMAMUX: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_AHB3: |
| switch (pclken->enr) { |
| case LL_AHB3_GRP1_PERIPH_RNG2: |
| *rate = LL_RCC_GetRNGClockFreq(LL_RCC_RNG2_CLKSOURCE); |
| break; |
| case LL_AHB3_GRP1_PERIPH_DCMI: |
| case LL_AHB3_GRP1_PERIPH_CRYP2: |
| case LL_AHB3_GRP1_PERIPH_HASH2: |
| case LL_AHB3_GRP1_PERIPH_CRC2: |
| case LL_AHB3_GRP1_PERIPH_HSEM: |
| case LL_AHB3_GRP1_PERIPH_IPCC: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_AHB4: |
| return -ENOTSUP; |
| case STM32_CLOCK_BUS_AHB5: |
| switch (pclken->enr) { |
| case LL_AHB5_GRP1_PERIPH_RNG1: |
| *rate = LL_RCC_GetRNGClockFreq(LL_RCC_RNG1_CLKSOURCE); |
| break; |
| case LL_AHB5_GRP1_PERIPH_GPIOZ: |
| case LL_AHB5_GRP1_PERIPH_CRYP1: |
| case LL_AHB5_GRP1_PERIPH_HASH1: |
| case LL_AHB5_GRP1_PERIPH_BKPSRAM: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_AHB6: |
| switch (pclken->enr) { |
| case LL_AHB6_GRP1_PERIPH_ETH1CK: |
| case LL_AHB6_GRP1_PERIPH_ETH1TX: |
| case LL_AHB6_GRP1_PERIPH_ETH1RX: |
| case LL_AHB6_GRP1_PERIPH_ETH1MAC: |
| case LL_AHB6_GRP1_PERIPH_ETH1STP: |
| *rate = LL_RCC_GetETHClockFreq(LL_RCC_ETH_CLKSOURCE); |
| break; |
| case LL_AHB6_GRP1_PERIPH_FMC: |
| *rate = LL_RCC_GetFMCClockFreq(LL_RCC_FMC_CLKSOURCE); |
| break; |
| case LL_AHB6_GRP1_PERIPH_QSPI: |
| *rate = LL_RCC_GetQSPIClockFreq(LL_RCC_QSPI_CLKSOURCE); |
| break; |
| case LL_AHB6_GRP1_PERIPH_SDMMC1: |
| case LL_AHB6_GRP1_PERIPH_SDMMC2: |
| *rate = LL_RCC_GetSDMMCClockFreq( |
| LL_RCC_SDMMC12_CLKSOURCE); |
| break; |
| case LL_AHB6_GRP1_PERIPH_MDMA: |
| case LL_AHB6_GRP1_PERIPH_GPU: |
| case LL_AHB6_GRP1_PERIPH_CRC1: |
| case LL_AHB6_GRP1_PERIPH_USBH: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_AXI: |
| switch (pclken->enr) { |
| case LL_AXI_GRP1_PERIPH_SYSRAMEN: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| case STM32_CLOCK_BUS_MLAHB: |
| switch (pclken->enr) { |
| case LL_MLAHB_GRP1_PERIPH_RETRAMEN: |
| default: |
| return -ENOTSUP; |
| } |
| break; |
| default: |
| return -ENOTSUP; |
| } |
| return 0; |
| } |
| |
| static struct clock_control_driver_api stm32_clock_control_api = { |
| .on = stm32_clock_control_on, |
| .off = stm32_clock_control_off, |
| .get_rate = stm32_clock_control_get_subsys_rate, |
| }; |
| |
| static int stm32_clock_control_init(const struct device *dev) |
| { |
| ARG_UNUSED(dev); |
| return 0; |
| } |
| |
| /** |
| * @brief RCC device, note that priority is intentionally set to 1 so |
| * that the device init runs just after SOC init |
| */ |
| DEVICE_DT_DEFINE(DT_NODELABEL(rcc), |
| &stm32_clock_control_init, |
| NULL, |
| NULL, NULL, |
| PRE_KERNEL_1, |
| CONFIG_CLOCK_CONTROL_INIT_PRIORITY, |
| &stm32_clock_control_api); |