1 /*
2 * Copyright (c) 2023-2024 Analog Devices, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/clock_control.h>
8 #include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
9
10 #include <wrap_max32_sys.h>
11
12 #define DT_DRV_COMPAT adi_max32_gcr
13
api_on(const struct device * dev,clock_control_subsys_t clkcfg)14 static inline int api_on(const struct device *dev, clock_control_subsys_t clkcfg)
15 {
16 ARG_UNUSED(dev);
17 struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg);
18
19 switch (perclk->bus) {
20 case ADI_MAX32_CLOCK_BUS0:
21 MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)perclk->bit);
22 break;
23 case ADI_MAX32_CLOCK_BUS1:
24 MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)(perclk->bit + 32));
25 break;
26 case ADI_MAX32_CLOCK_BUS2:
27 MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)(perclk->bit + 64));
28 break;
29 default:
30 return -EINVAL;
31 }
32
33 return 0;
34 }
35
api_off(const struct device * dev,clock_control_subsys_t clkcfg)36 static inline int api_off(const struct device *dev, clock_control_subsys_t clkcfg)
37 {
38 ARG_UNUSED(dev);
39 struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg);
40
41 switch (perclk->bus) {
42 case ADI_MAX32_CLOCK_BUS0:
43 MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)perclk->bit);
44 break;
45 case ADI_MAX32_CLOCK_BUS1:
46 MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)(perclk->bit + 32));
47 break;
48 case ADI_MAX32_CLOCK_BUS2:
49 MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)(perclk->bit + 64));
50 break;
51 default:
52 return -EINVAL;
53 }
54
55 return 0;
56 }
57
api_get_rate(const struct device * dev,clock_control_subsys_t clkcfg,uint32_t * rate)58 static int api_get_rate(const struct device *dev, clock_control_subsys_t clkcfg, uint32_t *rate)
59 {
60 ARG_UNUSED(dev);
61 struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg);
62
63 switch (perclk->clk_src) {
64 case ADI_MAX32_PRPH_CLK_SRC_PCLK:
65 *rate = ADI_MAX32_PCLK_FREQ;
66 break;
67 case ADI_MAX32_PRPH_CLK_SRC_EXTCLK:
68 *rate = ADI_MAX32_CLK_EXTCLK_FREQ;
69 break;
70 case ADI_MAX32_PRPH_CLK_SRC_IBRO:
71 *rate = ADI_MAX32_CLK_IBRO_FREQ;
72 break;
73 case ADI_MAX32_PRPH_CLK_SRC_ERFO:
74 *rate = ADI_MAX32_CLK_ERFO_FREQ;
75 break;
76 case ADI_MAX32_PRPH_CLK_SRC_ERTCO:
77 *rate = ADI_MAX32_CLK_ERTCO_FREQ;
78 break;
79 case ADI_MAX32_PRPH_CLK_SRC_INRO:
80 *rate = ADI_MAX32_CLK_INRO_FREQ;
81 break;
82 case ADI_MAX32_PRPH_CLK_SRC_ISO:
83 *rate = ADI_MAX32_CLK_ISO_FREQ;
84 break;
85 case ADI_MAX32_PRPH_CLK_SRC_IBRO_DIV8:
86 *rate = ADI_MAX32_CLK_IBRO_FREQ / 8;
87 break;
88 case ADI_MAX32_PRPH_CLK_SRC_IPLL:
89 *rate = ADI_MAX32_CLK_IPLL_FREQ;
90 break;
91 default:
92 *rate = 0U;
93 /* Invalid parameters */
94 return -EINVAL;
95 }
96
97 return 0;
98 }
99
100 static DEVICE_API(clock_control, max32_clkctrl_api) = {
101 .on = api_on,
102 .off = api_off,
103 .get_rate = api_get_rate,
104 };
105
setup_fixed_clocks(void)106 static void setup_fixed_clocks(void)
107 {
108 #if DT_NODE_HAS_COMPAT(DT_NODELABEL(clk_extclk), fixed_clock)
109 MXC_SYS_ClockSourceDisable(ADI_MAX32_CLK_EXTCLK);
110 #endif
111
112 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_ipo))
113 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IPO);
114 #endif
115
116 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_erfo))
117 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERFO);
118 #endif
119
120 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_ibro))
121 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IBRO);
122 #endif
123
124 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_iso))
125 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ISO);
126 #endif
127
128 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_inro))
129 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_INRO);
130 #endif
131
132 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_ertco))
133 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERTCO);
134 #endif
135
136 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk_ipll))
137 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IPLL);
138 #endif
139
140 /* Some device does not support external clock */
141 #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_extclk), fixed_clock, okay)
142 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_EXTCLK);
143 #endif
144 }
145
max32_clkctrl_init(const struct device * dev)146 static int max32_clkctrl_init(const struct device *dev)
147 {
148 ARG_UNUSED(dev);
149
150 /* Setup fixed clocks if enabled */
151 setup_fixed_clocks();
152
153 /* Setup device clock source */
154 MXC_SYS_Clock_Select(ADI_MAX32_SYSCLK_SRC);
155
156 #if DT_NODE_HAS_PROP(DT_NODELABEL(gcr), sysclk_prescaler)
157 /* Setup divider */
158 Wrap_MXC_SYS_SetClockDiv(sysclk_prescaler(ADI_MAX32_SYSCLK_PRESCALER));
159 #endif
160
161 return 0;
162 }
163
164 DEVICE_DT_INST_DEFINE(0, max32_clkctrl_init, NULL, NULL, NULL, PRE_KERNEL_1,
165 CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &max32_clkctrl_api);
166