diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 596b07676e0353..4ba6a166d3a0b6 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_cont if(CONFIG_CLOCK_CONTROL_STM32_CUBE) zephyr_library_sources_ifdef(CONFIG_CLOCK_STM32_MUX clock_stm32_mux.c) + zephyr_library_sources_ifdef(CONFIG_CLOCK_STM32_MCO clock_stm32_mco.c) if(CONFIG_SOC_SERIES_STM32MP1X) zephyr_library_sources(clock_stm32_ll_mp1.c) elseif(CONFIG_SOC_SERIES_STM32H7X) diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index cccbe5e2e74a9d..5b0f7181eb1c58 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -46,6 +46,13 @@ config CLOCK_STM32_MUX for a specific domain. For instance per_ck clock on STM32H7 or CLK48 clock +config CLOCK_STM32_MCO + bool "STM32 clock MCO driver" + default y + depends on DT_HAS_ST_STM32_MCO_CLOCK_ENABLED + help + Enable driver for STM32 clock MCO clock output. + # Micro-controller Clock output configuration options choice diff --git a/drivers/clock_control/clock_stm32_mco.c b/drivers/clock_control/clock_stm32_mco.c new file mode 100644 index 00000000000000..70a8fde5b374df --- /dev/null +++ b/drivers/clock_control/clock_stm32_mco.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 Benjamin Björnsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_stm32_mco_clock + +#include +#include +#include +#include +#include + +#include + +struct clock_control_stm32_mco_config { + uint32_t base; + const struct stm32_pclken *pclken; + size_t pclk_len; + const struct pinctrl_dev_config *pcfg; +}; + +static int clock_control_stm32_mco_init(const struct device *dev) +{ + const struct clock_control_stm32_mco_config *config = dev->config; + + for (int i = 0; i < config->pclk_len; i++) { + sys_clear_bits(config->base + STM32_CLOCK_REG_GET(config->pclken->enr), + STM32_CLOCK_MASK_GET(config->pclken[i].enr) + << STM32_CLOCK_SHIFT_GET(config->pclken[i].enr)); + sys_set_bits(config->base + STM32_CLOCK_REG_GET(config->pclken->enr), + STM32_CLOCK_VAL_GET(config->pclken[i].enr) + << STM32_CLOCK_SHIFT_GET(config->pclken[i].enr)); + } + + return 0; +} + +#define STM32_MCO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static const struct stm32_pclken pclken_##inst[] = STM32_DT_INST_CLOCKS(inst); \ + \ + static struct clock_control_stm32_mco_config clk_cfg_##inst = { \ + .base = DT_REG_ADDR(DT_INST_CLOCKS_CTLR(inst)), \ + .pclken = pclken_##inst, \ + .pclk_len = DT_INST_NUM_CLOCKS(inst), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &clock_control_stm32_mco_init, \ + NULL, NULL, &clk_cfg_##inst, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(STM32_MCO_INIT) + +#define GET_DEV(node_id) DEVICE_DT_GET(node_id), + +static int stm32_mco_pinctrl_init(void) +{ + const struct device *dev_list[] = {DT_FOREACH_STATUS_OKAY(st_stm32_mco_clock, GET_DEV)}; + int list_len = ARRAY_SIZE(dev_list); + + for (int i = 0; i < list_len; i++) { + const struct clock_control_stm32_mco_config *config = dev_list[i]->config; + int res = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (res < 0) { + return res; + } + } + + return 0; +} + +/* Need to be initialised after GPIO driver */ +SYS_INIT(stm32_mco_pinctrl_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index fd37b14b5f93b0..83ce1b0ca72c42 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -64,6 +64,16 @@ clock-frequency = ; status = "disabled"; }; + + clk_mco: clk-mco { + compatible = "st,stm32-mco-clock"; + status = "disabled"; + }; + + clk_mco2: clk-mco2 { + compatible = "st,stm32-mco-clock"; + status = "disabled"; + }; }; soc { diff --git a/dts/bindings/clock/st,stm32-mco-clock.yaml b/dts/bindings/clock/st,stm32-mco-clock.yaml new file mode 100644 index 00000000000000..fa466d5f81482a --- /dev/null +++ b/dts/bindings/clock/st,stm32-mco-clock.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Benjamin Björnsson +# SPDX-License-Identifier: Apache-2.0 + +description: STM32 MCO Clock + +compatible: "st,stm32-mco-clock" + +include: [pinctrl-device.yaml, base.yaml] + +properties: + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/include/zephyr/dt-bindings/clock/stm32c0_clock.h b/include/zephyr/dt-bindings/clock/stm32c0_clock.h index 224bd1517d5e7e..3414eca6d4d888 100644 --- a/include/zephyr/dt-bindings/clock/stm32c0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32c0_clock.h @@ -57,6 +57,9 @@ (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) +/** @brief RCC_CFGRR register offset */ +#define CFGR_REG 0x08 + /** @brief RCC_CCIPR register offset */ #define CCIPR_REG 0x54 @@ -64,6 +67,11 @@ #define CSR1_REG 0x5C /** @brief Device domain clocks selection helpers */ +/** CFGR devices */ +#define MCO_SEL(val) STM32_CLOCK(val, 3, 24, CFGR_REG) +#define MCO_DIV(val) STM32_CLOCK(val, 3, 28, CFGR_REG) +#define MCO2_SEL(val) STM32_CLOCK(val, 3, 16, CFGR_REG) +#define MCO2_DIV(val) STM32_CLOCK(val, 3, 20, CFGR_REG) /** CCIPR devices */ #define USART1_SEL(val) STM32_CLOCK(val, 3, 0, CCIPR_REG) #define I2C1_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR_REG) diff --git a/west.yml b/west.yml index a8de0372daa419..8725b0ce8ce6f5 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 60c9634f61c697e1c310ec648d33529712806069 + revision: pull/195/head path: modules/hal/stm32 groups: - hal