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