Skip to content

Commit d614aeb

Browse files
committed
drivers: clock: ti: Add initial support TI MSPM0 clock module
Add initial support TI MSPM0 clock module Signed-off-by: Saravanan Sekar <[email protected]> Signed-off-by: Jackson Farley <[email protected]>
1 parent 1e677d2 commit d614aeb

File tree

10 files changed

+418
-0
lines changed

10 files changed

+418
-0
lines changed

drivers/clock_control/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG clock_cont
1919
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG_K4 clock_control_mcux_scg_k4.c)
2020
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SIM clock_control_mcux_sim.c)
2121
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SYSCON clock_control_mcux_syscon.c)
22+
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MSPM0 clock_control_mspm0.c)
2223
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCM clock_control_npcm.c)
2324
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCX clock_control_npcx.c)
2425
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF clock_control_nrf.c)

drivers/clock_control/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ source "drivers/clock_control/Kconfig.mcux_sim"
5050

5151
source "drivers/clock_control/Kconfig.mcux_syscon"
5252

53+
source "drivers/clock_control/Kconfig.mspm0"
54+
5355
source "drivers/clock_control/Kconfig.npcm"
5456

5557
source "drivers/clock_control/Kconfig.npcx"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# TI MSPM0 Family
2+
3+
# Copyright (c) 2025, Texas Instruments Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config CLOCK_CONTROL_MSPM0
7+
bool "TI MSPM0 clock"
8+
default y
9+
depends on SOC_FAMILY_TI_MSPM0
10+
help
11+
This option enables the TI MSPM0 Clock Control Enabler
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
* Copyright (c) 2025 Texas Instruments
3+
* Copyright (c) 2025 Linumiz
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/drivers/clock_control.h>
9+
#include <zephyr/drivers/clock_control/mspm0_clock_control.h>
10+
11+
#include <ti/driverlib/driverlib.h>
12+
#include <string.h>
13+
14+
#define MSPM0_ULPCLK_DIV COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(ulpclk), clk_div), \
15+
(CONCAT(DL_SYSCTL_ULPCLK_DIV_, DT_PROP(DT_NODELABEL(ulpclk), clk_div))), \
16+
(0))
17+
18+
#define MSPM0_MCLK_DIV COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(mclk), clk_div), \
19+
(CONCAT(DL_SYSCTL_MCLK_DIVIDER_, DT_PROP(DT_NODELABEL(mclk), clk_div))), \
20+
(0))
21+
22+
#define MSPM0_MFPCLK_DIV COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(mfpclk), clk_div), \
23+
(CONCAT(DL_SYSCTL_HFCLK_MFPCLK_DIVIDER_, DT_PROP(DT_NODELABEL(mfpclk), clk_div))), \
24+
(0))
25+
26+
#if DT_NODE_HAS_STATUS(DT_NODELABEL(pll), okay)
27+
#define MSPM0_PLL_ENABLED 1
28+
static const DL_SYSCTL_SYSPLLConfig clock_mspm0_cfg_syspll;
29+
#endif
30+
31+
struct mspm0_clk_cfg {
32+
bool is_crystal;
33+
uint32_t xtal_startup_delay;
34+
uint32_t clk_freq;
35+
uint32_t clk_div;
36+
uint32_t clk_source;
37+
};
38+
39+
static struct mspm0_clk_cfg mspm0_lfclk_cfg = {
40+
.clk_freq = DT_PROP(DT_NODELABEL(lfclk), clock_frequency),
41+
.clk_source = DT_PROP(DT_NODELABEL(lfclk), clock_source),
42+
};
43+
44+
static struct mspm0_clk_cfg mspm0_ulpclk_cfg = {
45+
.clk_freq = DT_PROP(DT_NODELABEL(ulpclk), clock_frequency),
46+
.clk_div = MSPM0_ULPCLK_DIV,
47+
.clk_source = DT_PROP(DT_NODELABEL(ulpclk), clock_source),
48+
};
49+
50+
static struct mspm0_clk_cfg mspm0_mclk_cfg = {
51+
.clk_freq = DT_PROP(DT_NODELABEL(mclk), clock_frequency),
52+
.clk_div = MSPM0_MCLK_DIV,
53+
.clk_source = DT_PROP(DT_NODELABEL(mclk), clock_source),
54+
};
55+
56+
static struct mspm0_clk_cfg mspm0_mfpclk_cfg = {
57+
.clk_freq = DT_PROP(DT_NODELABEL(mfpclk), clock_frequency),
58+
.clk_div = MSPM0_MFPCLK_DIV,
59+
.clk_source = DT_PROP(DT_NODELABEL(mfpclk), clock_source),
60+
};
61+
62+
#if DT_NODE_HAS_STATUS(DT_NODELABEL(hfclk), okay)
63+
#define MSPM0_HFCLK_ENABLED 1
64+
static struct mspm0_clk_cfg mspm0_hfclk_cfg = {
65+
.clk_freq = DT_PROP(DT_NODELABEL(hfclk), clock_frequency),
66+
.is_crystal = DT_NODE_HAS_PROP(DT_NODELABEL(hfclk), ti_xtal),
67+
.xtal_startup_delay = DT_PROP_OR(DT_NODELABEL(hfclk),
68+
ti_xtal_startup_delay_us, 0),
69+
};
70+
#endif
71+
72+
#if DT_NODE_HAS_STATUS(DT_NODELABEL(exlfclk), okay)
73+
#define MSPM0_EXLFCLK_ENABLED 1
74+
static const struct mspm0_clk_cfg mspm0_exlfclk_cfg = {
75+
.clk_freq = DT_PROP(DT_NODELABEL(exlfclk), clock_frequency),
76+
.is_crystal = DT_NODE_HAS_PROP(DT_NODELABEL(exlfclk), ti_xtal),
77+
};
78+
#endif
79+
80+
static int clock_mspm0_on(const struct device *dev, clock_control_subsys_t sys)
81+
{
82+
return 0;
83+
}
84+
85+
static int clock_mspm0_off(const struct device *dev, clock_control_subsys_t sys)
86+
{
87+
return 0;
88+
}
89+
90+
static int clock_mspm0_get_rate(const struct device *dev,
91+
clock_control_subsys_t sys,
92+
uint32_t *rate)
93+
{
94+
struct mspm0_sys_clock *sys_clock = (struct mspm0_sys_clock *)sys;
95+
96+
switch (sys_clock->bus) {
97+
case MSPM0_CLOCK_BUS_LFCLK:
98+
*rate = mspm0_lfclk_cfg.clk_freq;
99+
break;
100+
101+
case MSPM0_CLOCK_BUS_ULPCLK:
102+
*rate = mspm0_ulpclk_cfg.clk_freq;
103+
break;
104+
105+
case MSPM0_CLOCK_BUS_MCLK:
106+
*rate = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
107+
break;
108+
109+
case MSPM0_CLOCK_BUS_MFPCLK:
110+
*rate = mspm0_mfpclk_cfg.clk_freq;
111+
break;
112+
113+
case MSPM0_CLOCK_BUS_MFCLK:
114+
case MSPM0_CLOCK_BUS_CANCLK:
115+
default:
116+
return -ENOTSUP;
117+
}
118+
119+
return 0;
120+
}
121+
122+
static int clock_mspm0_init(const struct device *dev)
123+
{
124+
/* setup clocks based on specific rates */
125+
DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);
126+
127+
#if MSPM0_PLL_ENABLED
128+
DL_SYSCTL_configSYSPLL(
129+
(DL_SYSCTL_SYSPLLConfig *)&clock_mspm0_cfg_syspll);
130+
131+
DL_SYSCTL_setMCLKDivider(mspm0_mclk_cfg.clk_div);
132+
DL_SYSCTL_setULPCLKDivider(mspm0_ulpclk_cfg.clk_div);
133+
DL_SYSCTL_setHFCLKDividerForMFPCLK(mspm0_mfpclk_cfg.clk_div);
134+
135+
if (mspm0_mclk_cfg.clk_source == MSPM0_CLOCK_BUS_SYSPLL0 ||
136+
mspm0_mclk_cfg.clk_source == MSPM0_CLOCK_BUS_SYSPLL2X) {
137+
DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK,
138+
DL_SYSCTL_HSCLK_SOURCE_SYSPLL);
139+
}
140+
#endif
141+
142+
#if MSPM0_HFCLK_ENABLED
143+
uint32_t hf_range;
144+
uint32_t hfclk_freq_in_mhz = mspm0_hfclk_cfg.clk_freq / MHZ(1);
145+
if (hfclk_freq_in_mhz >= 4 &&
146+
hfclk_freq_in_mhz <= 8) {
147+
hf_range = DL_SYSCTL_HFXT_RANGE_4_8_MHZ;
148+
} else if (hfclk_freq_in_mhz > 8 &&
149+
hfclk_freq_in_mhz <= 16) {
150+
hf_range = DL_SYSCTL_HFXT_RANGE_8_16_MHZ;
151+
} else if (hfclk_freq_in_mhz > 16 &&
152+
hfclk_freq_in_mhz <= 32) {
153+
hf_range = DL_SYSCTL_HFXT_RANGE_16_32_MHZ;
154+
} else if (hfclk_freq_in_mhz > 32 &&
155+
hfclk_freq_in_mhz <= 48) {
156+
hf_range = DL_SYSCTL_HFXT_RANGE_32_48_MHZ;
157+
} else {
158+
return -EINVAL;
159+
}
160+
161+
if (mspm0_hfclk_cfg.is_crystal == false) {
162+
DL_SYSCTL_setHFCLKSourceHFCLKIN();
163+
} else {
164+
/* startup time in 64us resolution */
165+
DL_SYSCTL_setHFCLKSourceHFXTParams(hf_range,
166+
mspm0_hfclk_cfg.xtal_startup_delay / 64,
167+
true);
168+
}
169+
170+
if (mspm0_mclk_cfg.clk_source == MSPM0_CLOCK_BUS_HFCLK) {
171+
DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK,
172+
DL_SYSCTL_HSCLK_SOURCE_HFCLK);
173+
}
174+
#endif
175+
176+
#if MSPM0_EXLFCLK_ENABLED
177+
if (mspm0_lfclk_cfg.clk_source == MSPM0_CLOCK_BUS_EXLFCLK) {
178+
if (mspm0_exlfclk_cfg.is_crystal == false) {
179+
DL_SYSCTL_setLFCLKSourceEXLF();
180+
} else {
181+
DL_SYSCTL_LFCLKConfig config = {0};
182+
183+
DL_SYSCTL_setLFCLKSourceLFXT(&config);
184+
}
185+
}
186+
#endif
187+
188+
if (mspm0_mclk_cfg.clk_source == MSPM0_CLOCK_BUS_LFCLK) {
189+
DL_SYSCTL_setMCLKSource(SYSOSC, LFCLK, false);
190+
}
191+
192+
return 0;
193+
}
194+
195+
static const struct clock_control_driver_api clock_mspm0_driver_api = {
196+
.on = clock_mspm0_on,
197+
.off = clock_mspm0_off,
198+
.get_rate = clock_mspm0_get_rate,
199+
};
200+
201+
DEVICE_DT_DEFINE(DT_NODELABEL(ckm), &clock_mspm0_init, NULL, NULL, NULL,
202+
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
203+
&clock_mspm0_driver_api);
204+
205+
#if MSPM0_PLL_ENABLED
206+
207+
/* basic checks of the devicetree to follow */
208+
#if (DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div) && \
209+
DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div))
210+
#error "Only CLK2X or CLK0 can be enabled at a time on the PLL"
211+
#endif
212+
213+
#define GENERATE_PLL_STRUCT() \
214+
static const DL_SYSCTL_SYSPLLConfig clock_mspm0_cfg_syspll = { \
215+
.inputFreq = DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ, \
216+
.rDivClk2x = (DT_PROP_OR(DT_NODELABEL(pll), clk2x_div, 1) - 1), \
217+
.rDivClk1 = (DT_PROP_OR(DT_NODELABEL(pll), clk1_div, 1) - 1), \
218+
.rDivClk0 = (DT_PROP_OR(DT_NODELABEL(pll), clk0_div, 1) - 1), \
219+
.qDiv = (DT_PROP(DT_NODELABEL(pll), q_div) - 1), \
220+
.pDiv = CONCAT(DL_SYSCTL_SYSPLL_PDIV_, DT_PROP(DT_NODELABEL(pll), p_div)), \
221+
.sysPLLMCLK = COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div), \
222+
(DL_SYSCTL_SYSPLL_MCLK_CLK2X), (DL_SYSCTL_SYSPLL_MCLK_CLK0)), \
223+
.enableCLK2x = COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div), \
224+
(DL_SYSCTL_SYSPLL_CLK2X_ENABLE), (DL_SYSCTL_SYSPLL_CLK2X_DISABLE)), \
225+
.enableCLK1 = COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk1_div), \
226+
(DL_SYSCTL_SYSPLL_CLK1_ENABLE), (DL_SYSCTL_SYSPLL_CLK1_DISABLE)), \
227+
.enableCLK0 = COND_CODE_1(DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div), \
228+
(DL_SYSCTL_SYSPLL_CLK0_ENABLE), (DL_SYSCTL_SYSPLL_CLK0_DISABLE)), \
229+
.sysPLLRef = COND_CODE_1(DT_CLOCKS_CELL(DT_NODELABEL(pll), clocks), \
230+
(DL_SYSCTL_SYSPLL_REF_HFCLK), (DL_SYSCTL_SYSPLL_REF_SYSOSC)), \
231+
};
232+
233+
GENERATE_PLL_STRUCT()
234+
235+
#endif /* MSPM0_PLL_ENABLED */
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright (c) 2025 Texas Instruments Inc.
2+
# Copyright (c) 2025 Linumiz
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
description: TI MSPM0 Clock Module Bus
6+
7+
compatible: "ti,mspm0-ckm-bus"
8+
9+
include: [clock-controller.yaml, base.yaml]
10+
11+
properties:
12+
"#clock-cells":
13+
const: 0
14+
15+
clock-source:
16+
type: int
17+
description: |
18+
Clock input reference source.
19+
20+
clock-frequency:
21+
type: int
22+
required: true
23+
description: |
24+
Output clock frequency in Hz.
25+
26+
ti,xtal:
27+
type: boolean
28+
description: |
29+
Specify it is external crystal Oscillator.
30+
31+
ti,xtal-startup-delay-us:
32+
type: int
33+
description: |
34+
Crystal Oscillator startup delay in micro seconds.
35+
36+
clk-div:
37+
type: int
38+
description: |
39+
Clock divider selction value. Valid range [2 ... 16].
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) 2025 Texas Instruments Inc.
2+
# Copyright (c) 2025 Linumiz
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
description: TI MSPM0 Clock Module
6+
7+
compatible: "ti,mspm0-ckm"
8+
9+
include: [clock-controller.yaml, base.yaml]
10+
11+
properties:
12+
"#clock-cells":
13+
const: 1
14+
15+
clock-cells:
16+
- bus
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright (c) 2024 Texas Instruments Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: TI MSPM0 Phase Locked Loop
5+
6+
compatible: "ti,mspm0-pll"
7+
8+
include: [clock-controller.yaml, base.yaml]
9+
10+
properties:
11+
clocks:
12+
required: true
13+
description: |
14+
Clock reference source
15+
16+
"#clock-cells":
17+
const: 0
18+
19+
p-div:
20+
type: int
21+
required: true
22+
enum:
23+
- 1
24+
- 2
25+
- 4
26+
- 8
27+
description: |
28+
pdiv is the pre-divider of the output. ref_in / pdiv * qdiv = VCO
29+
30+
q-div:
31+
type: int
32+
required: true
33+
description: |
34+
qdiv functions as a multiplier value for the ref_in / pdiv * qdiv = VCO
35+
Valid Range: 2 - 128
36+
37+
clk0-div:
38+
type: int
39+
description: |
40+
CLK0 PLL output is only enabled if the divider is present. Use CLK0 on
41+
the MSPM0 to output to the MCLK, UCLK, and CPUCLK
42+
Valid Range: 1 - 16
43+
44+
clk1-div:
45+
type: int
46+
description: |
47+
CLK1 PLL output is only enabled if the divider is present. Use CLK1 on
48+
the MSPM0 to output to the CANCLK, FCC, or output via EXCLK
49+
Valid Range: 1 - 16
50+
51+
clk2x-div:
52+
type: int
53+
description: |
54+
CLK2X PLL output is only enabled if the divider is present. Use CLK2X on
55+
the MSPM0 to output to the MCLK, UCLK, and CPUCLK instead of CLK0
56+
Valid Range: 1 - 16
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2025 Texas Instruments Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL
8+
#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL
9+
10+
#include <zephyr/dt-bindings/clock/mspm0_clock.h>
11+
12+
struct mspm0_sys_clock {
13+
uint32_t bus;
14+
};
15+
16+
#define MSPM0_CLOCK_SUBSYS_FN(index) {.bus = DT_INST_CLOCKS_CELL(index, bus)}
17+
18+
#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL */

0 commit comments

Comments
 (0)