mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-03 15:56:00 +00:00
although udiv is represented in clock tree of L series, this is not really present or controllable from SYSCTL registers. Enable udiv only if present in dts. Signed-off-by: Parthiban Nallathambi <parthiban@linumiz.com>
251 lines
7.1 KiB
C
251 lines
7.1 KiB
C
/*
|
|
* Copyright (c) 2025 Texas Instruments
|
|
* Copyright (c) 2025 Linumiz
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/drivers/clock_control.h>
|
|
#include <zephyr/drivers/clock_control/mspm0_clock_control.h>
|
|
|
|
#include <ti/driverlib/driverlib.h>
|
|
#include <string.h>
|
|
|
|
#define MSPM0_ULPCLK_DIV COND_CODE_1( \
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(ulpclk), clk_div), \
|
|
(CONCAT(DL_SYSCTL_ULPCLK_DIV_, \
|
|
DT_PROP(DT_NODELABEL(ulpclk), clk_div))), \
|
|
(0))
|
|
|
|
#define MSPM0_MCLK_DIV COND_CODE_1( \
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(mclk), clk_div), \
|
|
(CONCAT(DL_SYSCTL_MCLK_DIVIDER_, \
|
|
DT_PROP(DT_NODELABEL(mclk), clk_div))), \
|
|
(0))
|
|
|
|
#define MSPM0_MFPCLK_DIV COND_CODE_1( \
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(mfpclk), clk_div), \
|
|
(CONCAT(DL_SYSCTL_HFCLK_MFPCLK_DIVIDER_, \
|
|
DT_PROP(DT_NODELABEL(mfpclk), clk_div))), \
|
|
(0))
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(mfpclk), okay)
|
|
#define MSPM0_MFPCLK_ENABLED 1
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(pll), okay)
|
|
#define MSPM0_PLL_ENABLED 1
|
|
#endif
|
|
|
|
#define DT_MCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(mclk))
|
|
#define DT_LFCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(lfclk))
|
|
#define DT_HSCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(hsclk))
|
|
#define DT_HFCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(hfclk))
|
|
#define DT_MFPCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(mfpclk))
|
|
#define DT_PLL_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(pll))
|
|
|
|
struct mspm0_clk_cfg {
|
|
uint32_t clk_div;
|
|
uint32_t clk_freq;
|
|
};
|
|
|
|
static struct mspm0_clk_cfg mspm0_lfclk_cfg = {
|
|
.clk_freq = DT_PROP(DT_NODELABEL(lfclk), clock_frequency),
|
|
};
|
|
|
|
static struct mspm0_clk_cfg mspm0_ulpclk_cfg = {
|
|
.clk_freq = DT_PROP(DT_NODELABEL(ulpclk), clock_frequency),
|
|
.clk_div = MSPM0_ULPCLK_DIV,
|
|
};
|
|
|
|
static struct mspm0_clk_cfg mspm0_mclk_cfg = {
|
|
.clk_freq = DT_PROP(DT_NODELABEL(mclk), clock_frequency),
|
|
.clk_div = MSPM0_MCLK_DIV,
|
|
};
|
|
|
|
#if MSPM0_MFPCLK_ENABLED
|
|
static struct mspm0_clk_cfg mspm0_mfpclk_cfg = {
|
|
.clk_freq = DT_PROP(DT_NODELABEL(mfpclk), clock_frequency),
|
|
.clk_div = MSPM0_MFPCLK_DIV,
|
|
};
|
|
#endif
|
|
|
|
#if MSPM0_PLL_ENABLED
|
|
/* basic checks of the devicetree to follow */
|
|
#if (DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div) && \
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div))
|
|
#error "Only CLK2X or CLK0 can be enabled at a time on the PLL"
|
|
#endif
|
|
|
|
static DL_SYSCTL_SYSPLLConfig clock_mspm0_cfg_syspll = {
|
|
.inputFreq = DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ,
|
|
.sysPLLMCLK = DL_SYSCTL_SYSPLL_MCLK_CLK2X,
|
|
.sysPLLRef = DL_SYSCTL_SYSPLL_REF_SYSOSC,
|
|
.rDivClk2x = (DT_PROP_OR(DT_NODELABEL(pll), clk2x_div, 1) - 1),
|
|
.rDivClk1 = (DT_PROP_OR(DT_NODELABEL(pll), clk1_div, 1) - 1),
|
|
.rDivClk0 = (DT_PROP_OR(DT_NODELABEL(pll), clk0_div, 1) - 1),
|
|
.qDiv = (DT_PROP(DT_NODELABEL(pll), q_div) - 1),
|
|
.pDiv = CONCAT(DL_SYSCTL_SYSPLL_PDIV_,
|
|
DT_PROP(DT_NODELABEL(pll), p_div)),
|
|
.enableCLK2x = COND_CODE_1(
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div),
|
|
(DL_SYSCTL_SYSPLL_CLK2X_ENABLE),
|
|
(DL_SYSCTL_SYSPLL_CLK2X_DISABLE)),
|
|
.enableCLK1 = COND_CODE_1(
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk1_div),
|
|
(DL_SYSCTL_SYSPLL_CLK1_ENABLE),
|
|
(DL_SYSCTL_SYSPLL_CLK1_DISABLE)),
|
|
.enableCLK0 = COND_CODE_1(
|
|
DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div),
|
|
(DL_SYSCTL_SYSPLL_CLK0_ENABLE),
|
|
(DL_SYSCTL_SYSPLL_CLK0_DISABLE)),
|
|
};
|
|
#endif
|
|
|
|
static int clock_mspm0_on(const struct device *dev, clock_control_subsys_t sys)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int clock_mspm0_off(const struct device *dev, clock_control_subsys_t sys)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int clock_mspm0_get_rate(const struct device *dev,
|
|
clock_control_subsys_t sys,
|
|
uint32_t *rate)
|
|
{
|
|
struct mspm0_sys_clock *sys_clock = (struct mspm0_sys_clock *)sys;
|
|
|
|
switch (sys_clock->clk) {
|
|
case MSPM0_CLOCK_LFCLK:
|
|
*rate = mspm0_lfclk_cfg.clk_freq;
|
|
break;
|
|
|
|
case MSPM0_CLOCK_ULPCLK:
|
|
*rate = mspm0_ulpclk_cfg.clk_freq;
|
|
break;
|
|
|
|
case MSPM0_CLOCK_MCLK:
|
|
*rate = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
|
|
break;
|
|
|
|
#if MSPM0_MFPCLK_ENABLED
|
|
case MSPM0_CLOCK_MFPCLK:
|
|
*rate = mspm0_mfpclk_cfg.clk_freq;
|
|
break;
|
|
#endif
|
|
|
|
case MSPM0_CLOCK_MFCLK:
|
|
case MSPM0_CLOCK_CANCLK:
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int clock_mspm0_init(const struct device *dev)
|
|
{
|
|
/* setup clocks based on specific rates */
|
|
DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);
|
|
|
|
DL_SYSCTL_setMCLKDivider(mspm0_mclk_cfg.clk_div);
|
|
#if DT_NODE_HAS_PROP(DT_NODELABEL(ulpclk), clk_div)
|
|
DL_SYSCTL_setULPCLKDivider(mspm0_ulpclk_cfg.clk_div);
|
|
#endif
|
|
|
|
#if MSPM0_PLL_ENABLED
|
|
#if DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll0))
|
|
clock_mspm0_cfg_syspll.sysPLLMCLK = DL_SYSCTL_SYSPLL_MCLK_CLK0;
|
|
#endif
|
|
#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(hfclk))
|
|
clock_mspm0_cfg_syspll.sysPLLRef = DL_SYSCTL_SYSPLL_REF_HFCLK;
|
|
#endif
|
|
DL_SYSCTL_configSYSPLL(
|
|
(DL_SYSCTL_SYSPLLConfig *)&clock_mspm0_cfg_syspll);
|
|
#endif
|
|
|
|
#if DT_SAME_NODE(DT_HFCLK_CLOCKS_CTRL, DT_NODELABEL(hfxt))
|
|
uint32_t hf_range;
|
|
uint32_t hfxt_freq = DT_PROP(DT_NODELABEL(hfxt),
|
|
clock_frequency) / MHZ(1);
|
|
uint32_t xtal_startup_delay = DT_PROP_OR(DT_NODELABEL(hfxt),
|
|
ti_xtal_startup_delay_us, 0);
|
|
|
|
if (hfxt_freq >= 4 &&
|
|
hfxt_freq <= 8) {
|
|
hf_range = DL_SYSCTL_HFXT_RANGE_4_8_MHZ;
|
|
} else if (hfxt_freq > 8 &&
|
|
hfxt_freq <= 16) {
|
|
hf_range = DL_SYSCTL_HFXT_RANGE_8_16_MHZ;
|
|
} else if (hfxt_freq > 16 &&
|
|
hfxt_freq <= 32) {
|
|
hf_range = DL_SYSCTL_HFXT_RANGE_16_32_MHZ;
|
|
} else if (hfxt_freq > 32 &&
|
|
hfxt_freq <= 48) {
|
|
hf_range = DL_SYSCTL_HFXT_RANGE_32_48_MHZ;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* startup time in 64us resolution */
|
|
DL_SYSCTL_setHFCLKSourceHFXTParams(hf_range,
|
|
mspm0_hfclk_cfg.xtal_startup_delay / 64,
|
|
true);
|
|
#else
|
|
DL_SYSCTL_setHFCLKSourceHFCLKIN();
|
|
#endif
|
|
|
|
#if MSPM0_LFCLK_ENABLED
|
|
#if DT_SAME_NODE(DT_LFCLK_CLOCKS_CTRL, DT_NODELABEL(lfxt))
|
|
DL_SYSCTL_LFCLKConfig config = {0};
|
|
|
|
DL_SYSCTL_setLFCLKSourceLFXT(&config);
|
|
#elif DT_SAME_NODE(DT_LFCLK_CLOCKS_CTRL, DT_NODELABEL(lfdig_in))
|
|
DL_SYSCTL_setLFCLKSourceEXLF();
|
|
#endif
|
|
#endif /* MSPM0_LFCLK_ENABLED */
|
|
|
|
#if DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(hsclk))
|
|
#if DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(hfclk))
|
|
DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK,
|
|
DL_SYSCTL_HSCLK_SOURCE_HFCLK);
|
|
#endif
|
|
|
|
#if MSPM0_PLL_ENABLED
|
|
#if (DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll0)) || \
|
|
DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll2x)))
|
|
DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK,
|
|
DL_SYSCTL_HSCLK_SOURCE_SYSPLL);
|
|
#endif
|
|
#endif /* MSPM0_PLL_ENABLED */
|
|
|
|
#elif DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(lfclk))
|
|
DL_SYSCTL_setMCLKSource(SYSOSC, LFCLK, false);
|
|
#endif /* DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(hsclk)) */
|
|
|
|
#if MSPM0_MFPCLK_ENABLED
|
|
#if DT_SAME_NODE(DT_MFPCLK_CLOCKS_CTRL, DT_NODELABEL(hfclk))
|
|
DL_SYSCTL_setHFCLKDividerForMFPCLK(mspm0_mfpclk_cfg.clk_div);
|
|
DL_SYSCTL_setMFPCLKSource(DL_SYSCTL_MFPCLK_SOURCE_HFCLK);
|
|
#else
|
|
DL_SYSCTL_setMFPCLKSource(DL_SYSCTL_MFPCLK_SOURCE_SYSOSC);
|
|
#endif
|
|
DL_SYSCTL_enableMFPCLK();
|
|
#endif /* MSPM0_MFPCLK_ENABLED */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DEVICE_API(clock_control, clock_mspm0_driver_api) = {
|
|
.on = clock_mspm0_on,
|
|
.off = clock_mspm0_off,
|
|
.get_rate = clock_mspm0_get_rate,
|
|
};
|
|
|
|
DEVICE_DT_DEFINE(DT_NODELABEL(ckm), &clock_mspm0_init, NULL, NULL, NULL,
|
|
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
|
|
&clock_mspm0_driver_api);
|