1 /*
2  * Copyright (c) 2019-2021 Vestas Wind Systems A/S
3  * Copyright 2024 NXP
4  *
5  * Based on clock_control_mcux_sim.c, which is:
6  * Copyright (c) 2017, 2024 NXP
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #define DT_DRV_COMPAT nxp_kinetis_scg
12 
13 #include <zephyr/drivers/clock_control.h>
14 #include <zephyr/dt-bindings/clock/kinetis_scg.h>
15 #include <soc.h>
16 #include <fsl_clock.h>
17 
18 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(clock_control_scg);
21 
22 #define MCUX_SCG_CLOCK_NODE(name) DT_INST_CHILD(0, name)
23 
mcux_scg_on(const struct device * dev,clock_control_subsys_t sub_system)24 static int mcux_scg_on(const struct device *dev,
25 		       clock_control_subsys_t sub_system)
26 {
27 	return 0;
28 }
29 
mcux_scg_off(const struct device * dev,clock_control_subsys_t sub_system)30 static int mcux_scg_off(const struct device *dev,
31 			clock_control_subsys_t sub_system)
32 {
33 	return 0;
34 }
35 
mcux_scg_get_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)36 static int mcux_scg_get_rate(const struct device *dev,
37 			     clock_control_subsys_t sub_system,
38 			     uint32_t *rate)
39 {
40 	clock_name_t clock_name;
41 
42 	switch ((uint32_t) sub_system) {
43 	case KINETIS_SCG_CORESYS_CLK:
44 		clock_name = kCLOCK_CoreSysClk;
45 		break;
46 	case KINETIS_SCG_BUS_CLK:
47 		clock_name = kCLOCK_BusClk;
48 		break;
49 #if !(defined(CONFIG_SOC_MKE17Z7) || defined(CONFIG_SOC_MKE17Z9))
50 	case KINETIS_SCG_FLEXBUS_CLK:
51 		clock_name = kCLOCK_FlexBusClk;
52 		break;
53 #endif
54 	case KINETIS_SCG_FLASH_CLK:
55 		clock_name = kCLOCK_FlashClk;
56 		break;
57 	case KINETIS_SCG_SOSC_CLK:
58 		clock_name = kCLOCK_ScgSysOscClk;
59 		break;
60 	case KINETIS_SCG_SIRC_CLK:
61 		clock_name = kCLOCK_ScgSircClk;
62 		break;
63 	case KINETIS_SCG_FIRC_CLK:
64 		clock_name = kCLOCK_ScgFircClk;
65 		break;
66 #if (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL)
67 	case KINETIS_SCG_SPLL_CLK:
68 		clock_name = kCLOCK_ScgSysPllClk;
69 		break;
70 #endif /* (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) */
71 #if (defined(FSL_FEATURE_SCG_HAS_LPFLL) && FSL_FEATURE_SCG_HAS_LPFLL)
72 	case KINETIS_SCG_SPLL_CLK:
73 		clock_name = kCLOCK_ScgLpFllClk;
74 		break;
75 #endif /* (defined(FSL_FEATURE_SCG_HAS_LPFLL) && FSL_FEATURE_SCG_HAS_LPFLL) */
76 #if (defined(FSL_FEATURE_SCG_HAS_SOSCDIV1) && FSL_FEATURE_SCG_HAS_SOSCDIV1)
77 	case KINETIS_SCG_SOSC_ASYNC_DIV1_CLK:
78 		clock_name = kCLOCK_ScgSysOscAsyncDiv1Clk;
79 		break;
80 #endif /* (defined(FSL_FEATURE_SCG_HAS_SOSCDIV1) && FSL_FEATURE_SCG_HAS_SOSCDIV1) */
81 	case KINETIS_SCG_SOSC_ASYNC_DIV2_CLK:
82 		clock_name = kCLOCK_ScgSysOscAsyncDiv2Clk;
83 		break;
84 #if (defined(FSL_FEATURE_SCG_HAS_SIRCDIV1) && FSL_FEATURE_SCG_HAS_SIRCDIV1)
85 	case KINETIS_SCG_SIRC_ASYNC_DIV1_CLK:
86 		clock_name = kCLOCK_ScgSircAsyncDiv1Clk;
87 		break;
88 #endif /* (defined(FSL_FEATURE_SCG_HAS_SIRCDIV1) && FSL_FEATURE_SCG_HAS_SIRCDIV1) */
89 	case KINETIS_SCG_SIRC_ASYNC_DIV2_CLK:
90 		clock_name = kCLOCK_ScgSircAsyncDiv2Clk;
91 		break;
92 #if (defined(FSL_FEATURE_FSL_FEATURE_SCG_HAS_FIRCDIV1) && FSL_FEATURE_SCG_HAS_FIRCDIV1)
93 	case KINETIS_SCG_FIRC_ASYNC_DIV1_CLK:
94 		clock_name = kCLOCK_ScgFircAsyncDiv1Clk;
95 		break;
96 #endif /* (defined(FSL_FEATURE_FSL_FEATURE_SCG_HAS_FIRCDIV1) && FSL_FEATURE_SCG_HAS_FIRCDIV1) */
97 	case KINETIS_SCG_FIRC_ASYNC_DIV2_CLK:
98 		clock_name = kCLOCK_ScgFircAsyncDiv2Clk;
99 		break;
100 #if (defined(FSL_FEATURE_SCG_HAS_SPLLDIV1) && FSL_FEATURE_SCG_HAS_SPLLDIV1)
101 	case KINETIS_SCG_SPLL_ASYNC_DIV1_CLK:
102 		clock_name = kCLOCK_ScgSysPllAsyncDiv1Clk;
103 		break;
104 #endif /* (defined(FSL_FEATURE_SCG_HAS_SPLLDIV1) && FSL_FEATURE_SCG_HAS_SPLLDIV1) */
105 #if (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL)
106 	case KINETIS_SCG_SPLL_ASYNC_DIV2_CLK:
107 		clock_name = kCLOCK_ScgSysPllAsyncDiv2Clk;
108 		break;
109 #endif /* (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) */
110 #if (defined(FSL_FEATURE_SCG_HAS_FLLDIV1) && FSL_FEATURE_SCG_HAS_FLLDIV1)
111 	case KINETIS_SCG_LPFLL_ASYNC_DIV2_CLK:
112 		clock_name = kCLOCK_ScgSysLPFllAsyncDiv2Clk;
113 		break;
114 #endif /* (defined(FSL_FEATURE_SCG_HAS_FLLDIV1) && FSL_FEATURE_SCG_HAS_FLLDIV1) */
115 
116 
117 	default:
118 		LOG_ERR("Unsupported clock name");
119 		return -EINVAL;
120 	}
121 
122 	*rate = CLOCK_GetFreq(clock_name);
123 	return 0;
124 }
125 
mcux_scg_init(const struct device * dev)126 static int mcux_scg_init(const struct device *dev)
127 {
128 #if DT_NODE_HAS_STATUS_OKAY(MCUX_SCG_CLOCK_NODE(clkout_clk))
129 #if DT_SAME_NODE(DT_CLOCKS_CTLR(MCUX_SCG_CLOCK_NODE(clkout_clk)), MCUX_SCG_CLOCK_NODE(slow_clk))
130 	CLOCK_SetClkOutSel(kClockClkoutSelScgSlow);
131 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(MCUX_SCG_CLOCK_NODE(clkout_clk)), MCUX_SCG_CLOCK_NODE(sosc_clk))
132 	CLOCK_SetClkOutSel(kClockClkoutSelSysOsc);
133 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(MCUX_SCG_CLOCK_NODE(clkout_clk)), MCUX_SCG_CLOCK_NODE(sirc_clk))
134 	CLOCK_SetClkOutSel(kClockClkoutSelSirc);
135 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(MCUX_SCG_CLOCK_NODE(clkout_clk)), MCUX_SCG_CLOCK_NODE(firc_clk))
136 	CLOCK_SetClkOutSel(kClockClkoutSelFirc);
137 #elif DT_SAME_NODE(DT_CLOCKS_CTLR(MCUX_SCG_CLOCK_NODE(clkout_clk)), MCUX_SCG_CLOCK_NODE(spll_clk))
138 	CLOCK_SetClkOutSel(kClockClkoutSelSysPll);
139 #else
140 #error Unsupported SCG clkout clock source
141 #endif
142 #endif /* DT_NODE_HAS_STATUS_OKAY(MCUX_SCG_CLOCK_NODE(clkout_clk)) */
143 
144 	return 0;
145 }
146 
147 static DEVICE_API(clock_control, mcux_scg_driver_api) = {
148 	.on = mcux_scg_on,
149 	.off = mcux_scg_off,
150 	.get_rate = mcux_scg_get_rate,
151 };
152 
153 DEVICE_DT_INST_DEFINE(0,
154 		    mcux_scg_init,
155 		    NULL,
156 		    NULL, NULL,
157 		    PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
158 		    &mcux_scg_driver_api);
159