blob: 99c5fa560045a1cd0dbd054d2009e349aeac83e7 [file] [log] [blame]
/*
* Copyright (c) 2022 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <soc.h>
#include <zephyr/sys/onoff.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>
#include <da1469x_clock.h>
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);