diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 209fb9fdab..d75498f536 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -22,6 +22,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION nrf_clo zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_control_rv32m1_pcc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_INFINEON_CAT1 clock_control_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_control_sam_pmc.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 114b9f60f5..c21af00cdb 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -70,4 +70,6 @@ source "drivers/clock_control/Kconfig.gd32" source "drivers/clock_control/Kconfig.sam" +source "drivers/clock_control/Kconfig.smartbond" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.smartbond b/drivers/clock_control/Kconfig.smartbond new file mode 100644 index 0000000000..a8e2d2f86f --- /dev/null +++ b/drivers/clock_control/Kconfig.smartbond @@ -0,0 +1,10 @@ +# Smartbond clock control driver config + +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_SMARTBOND + bool "Smartbond Clock Control" + depends on SOC_FAMILY_SMARTBOND + help + Enable driver for Clock Control subsystem found in SmartBond diff --git a/drivers/clock_control/clock_control_smartbond.c b/drivers/clock_control/clock_control_smartbond.c new file mode 100644 index 0000000000..99c5fa5600 --- /dev/null +++ b/drivers/clock_control/clock_control_smartbond.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2022 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define DT_DRV_COMPAT smartbond_clock + +static inline int smartbond_clock_control_on(const struct device *dev, + clock_control_subsys_t sub_system) +{ + const uint32_t *clk = (const uint32_t *)(sub_system); + + ARG_UNUSED(dev); + + switch (*clk) { + case DT_DEP_ORD(DT_NODELABEL(rc32k)): + CRG_TOP->CLK_RC32K_REG |= CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; + break; + case DT_DEP_ORD(DT_NODELABEL(rcx)): + da1469x_clock_lp_rcx_enable(); + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32k)): + da1469x_clock_lp_xtal32k_enable(); + break; + case DT_DEP_ORD(DT_NODELABEL(rc32m)): + CRG_TOP->CLK_RC32M_REG |= CRG_TOP_CLK_RC32M_REG_RC32M_ENABLE_Msk; + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32m)): + da1469x_clock_sys_xtal32m_init(); + da1469x_clock_sys_xtal32m_enable(); + break; + case DT_DEP_ORD(DT_NODELABEL(pll)): + if ((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_PLL96M_Msk) == 0) { + if ((CRG_TOP->CLK_CTRL_REG & + CRG_TOP_CLK_CTRL_REG_RUNNING_AT_XTAL32M_Msk) == 0) { + da1469x_clock_sys_xtal32m_init(); + da1469x_clock_sys_xtal32m_enable(); + da1469x_clock_sys_xtal32m_wait_to_settle(); + } + da1469x_clock_sys_pll_enable(); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline int smartbond_clock_control_off(const struct device *dev, + clock_control_subsys_t sub_system) +{ + const uint32_t *clk = (const uint32_t *)(sub_system); + + ARG_UNUSED(dev); + + switch (*clk) { + case DT_DEP_ORD(DT_NODELABEL(rc32k)): + if (((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) >> + CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos) != 0) { + CRG_TOP->CLK_RC32K_REG &= ~CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; + } + break; + case DT_DEP_ORD(DT_NODELABEL(rcx)): + if (((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) >> + CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos) != 1) { + CRG_TOP->CLK_RCX_REG &= ~CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk; + } + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32k)): + if (((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) >> + CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos) > 1) { + CRG_TOP->CLK_XTAL32K_REG &= ~CRG_TOP_CLK_XTAL32K_REG_XTAL32K_ENABLE_Msk; + } + break; + case DT_DEP_ORD(DT_NODELABEL(rc32m)): + /* Disable rc32m only if not used as system clock */ + if ((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_RC32M_Msk) == 0) { + da1469x_clock_sys_rc32m_disable(); + } + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32m)): + da1469x_clock_sys_xtal32m_init(); + da1469x_clock_sys_xtal32m_enable(); + break; + case DT_DEP_ORD(DT_NODELABEL(pll)): + da1469x_clock_sys_pll_disable(); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int smartbond_clock_control_get_rate(const struct device *dev, + clock_control_subsys_t sub_system, + uint32_t *rate) +{ + const uint32_t *clk = (const uint32_t *)(sub_system); + + switch (*clk) { + case DT_DEP_ORD(DT_NODELABEL(rc32k)): + *rate = da1469x_clock_lp_rc32m_freq_get(); + break; + case DT_DEP_ORD(DT_NODELABEL(rcx)): + *rate = da1469x_clock_lp_rcx_freq_get(); + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32k)): + *rate = DT_PROP(DT_NODELABEL(xtal32k), clock_frequency); + break; + case DT_DEP_ORD(DT_NODELABEL(rc32m)): + *rate = DT_PROP(DT_NODELABEL(rc32m), clock_frequency); + break; + case DT_DEP_ORD(DT_NODELABEL(xtal32m)): + *rate = DT_PROP(DT_NODELABEL(xtal32m), clock_frequency); + break; + case DT_DEP_ORD(DT_NODELABEL(pll)): + *rate = DT_PROP(DT_NODELABEL(pll), clock_frequency); + break; + default: + return -ENOTSUP; + } + return 0; +} + +static void smartbond_clock_control_on_by_ord(const struct device *dev, + uint32_t clock_id) +{ + smartbond_clock_control_on(dev, &clock_id); +} + +static void smartbond_clock_control_off_by_ord(const struct device *dev, + uint32_t clock_id) +{ + smartbond_clock_control_off(dev, &clock_id); +} + +/** + * @brief Initialize clocks for the Smartbond + * + * This routine is called to enable and configure the clocks and PLL + * of the soc on the board. + * + * @param dev clocks device struct + * + * @return 0 + */ +int smartbond_clocks_init(const struct device *dev) +{ + ARG_UNUSED(dev); + uint32_t clk_ctrl; + uint32_t sys_clk_id; + +#define ENABLE_OSC(clock) smartbond_clock_control_on_by_ord(dev, DT_DEP_ORD(clock)) +#define DISABLE_OSC(clock) if (DT_NODE_HAS_STATUS(clock, disabled)) { \ + smartbond_clock_control_off_by_ord(dev, DT_DEP_ORD(clock)); \ + } + + /* Enable all oscillators with status "okay" */ + DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(crg, osc), ENABLE_OSC, (;)); + + clk_ctrl = CRG_TOP->CLK_CTRL_REG & + ~(CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk | CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk); + + /* Make sure that selected sysclock is enabled */ + BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_PROP(DT_NODELABEL(sys_clk), clock_src), okay), + "Clock selected as system clock no enabled in DT"); + BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_PROP(DT_NODELABEL(lp_clk), clock_src), okay), + "Clock selected as LP clock no enabled in DT"); + BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(pll), disabled) || + DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay), + "PLL enabled in DT but XTAL32M is disabled"); + + sys_clk_id = DT_DEP_ORD(DT_NODELABEL(sys_clk)); + smartbond_clock_control_on(dev, &sys_clk_id); + if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(lp_clk), clock_src), + DT_NODELABEL(rc32k))) { + } else if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(lp_clk), clock_src), + DT_NODELABEL(rcx))) { + clk_ctrl |= 1 << CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos; + } else if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(lp_clk), clock_src), + DT_NODELABEL(xtal32k))) { + clk_ctrl |= 2 << CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos; + } + + if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(sys_clk), clock_src), + DT_NODELABEL(rc32m))) { + clk_ctrl |= 1 << CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos; + SystemCoreClock = DT_PROP(DT_NODELABEL(rc32m), clock_frequency); + } else if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(sys_clk), clock_src), + DT_NODELABEL(pll))) { + da1469x_clock_pll_wait_to_lock(); + SystemCoreClock = DT_PROP(DT_NODELABEL(pll), clock_frequency); + clk_ctrl |= 3 << CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos; + } else if (DT_SAME_NODE(DT_PROP(DT_NODELABEL(sys_clk), clock_src), + DT_NODELABEL(xtal32m))) { + da1469x_clock_sys_xtal32m_switch_safe(); + } + CRG_TOP->CLK_CTRL_REG = clk_ctrl; + + /* Disable unwanted oscillators */ + DT_FOREACH_CHILD_SEP(DT_PATH(crg, osc), DISABLE_OSC, (;)); + + return 0; +} + +static struct clock_control_driver_api smartbond_clock_control_api = { + .on = smartbond_clock_control_on, + .off = smartbond_clock_control_off, + .get_rate = smartbond_clock_control_get_rate, +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(osc), + &smartbond_clocks_init, + NULL, + NULL, NULL, + PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &smartbond_clock_control_api); diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index 8e76419264..9ad866fb0b 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -5,6 +5,7 @@ #include #include +#include #include / { @@ -23,6 +24,63 @@ }; }; + crg { + osc: osc { + rc32k: rc32k { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "okay"; + }; + xtal32k: xtal32k { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + status = "disabled"; + }; + rcx: rcx { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "disabled"; + }; + rc32m: rc32m { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "okay"; + }; + xtal32m: xtal32m { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "disabled"; + }; + pll: pll { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "disabled"; + }; + }; + divn_clk: divn_clk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + status = "okay"; + }; + sys_clk: sys_clk { + compatible = "renesas,smartbond-sys-clk"; + status = "okay"; + clock-src = <&rc32m>; + status = "okay"; + }; + lp_clk: lp_clk { + compatible = "renesas,smartbond-lp-clk"; + clock-src = <&rc32k>; + status = "okay"; + }; + }; soc { sram0: memory@20000000 { diff --git a/dts/bindings/clock/renesas,smartbond-lp-clock.yaml b/dts/bindings/clock/renesas,smartbond-lp-clock.yaml new file mode 100644 index 0000000000..6b4f5614de --- /dev/null +++ b/dts/bindings/clock/renesas,smartbond-lp-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Smartbond low power clock + +compatible: "renesas,smartbond-lp-clk" + +include: + - name: base.yaml + property-allowlist: + - status + - compatible + +properties: + clock-src: + type: phandle + description: | + Low power clock source. diff --git a/dts/bindings/clock/renesas,smartbond-sys-clock.yaml b/dts/bindings/clock/renesas,smartbond-sys-clock.yaml new file mode 100644 index 0000000000..4b19970010 --- /dev/null +++ b/dts/bindings/clock/renesas,smartbond-sys-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Smartbond system clock + +compatible: "renesas,smartbond-sys-clk" + +include: + - name: base.yaml + property-allowlist: + - status + - compatible + +properties: + clock-src: + type: phandle + description: | + System clock source. diff --git a/soc/arm/renesas_smartbond/da1469x/Kconfig.series b/soc/arm/renesas_smartbond/da1469x/Kconfig.series index 247259b5dc..775ad6fdc0 100644 --- a/soc/arm/renesas_smartbond/da1469x/Kconfig.series +++ b/soc/arm/renesas_smartbond/da1469x/Kconfig.series @@ -10,5 +10,7 @@ config SOC_SERIES_DA1469X select CPU_CORTEX_M_HAS_SYSTICK select SOC_FAMILY_SMARTBOND select HAS_SEGGER_RTT + select CLOCK_CONTROL + select CLOCK_CONTROL_SMARTBOND help Enable support for Renesas SmartBond(tm) DA1469x MCU series