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 default:
89 *rate = 0U;
90 /* Invalid parameters */
91 return -EINVAL;
92 }
93
94 return 0;
95 }
96
97 static const struct clock_control_driver_api max32_clkctrl_api = {
98 .on = api_on,
99 .off = api_off,
100 .get_rate = api_get_rate,
101 };
102
setup_fixed_clocks(void)103 static void setup_fixed_clocks(void)
104 {
105 #if DT_NODE_HAS_COMPAT(DT_NODELABEL(clk_extclk), fixed_clock)
106 MXC_SYS_ClockSourceDisable(ADI_MAX32_CLK_EXTCLK);
107 #endif
108
109 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ipo), okay)
110 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IPO);
111 #endif
112
113 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_erfo), okay)
114 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERFO);
115 #endif
116
117 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ibro), okay)
118 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IBRO);
119 #endif
120
121 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_iso), okay)
122 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ISO);
123 #endif
124
125 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_inro), okay)
126 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_INRO);
127 #endif
128
129 #if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ertco), okay)
130 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERTCO);
131 #endif
132
133 /* Some device does not support external clock */
134 #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_extclk), fixed_clock, okay)
135 MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_EXTCLK);
136 #endif
137 }
138
max32_clkctrl_init(const struct device * dev)139 static int max32_clkctrl_init(const struct device *dev)
140 {
141 ARG_UNUSED(dev);
142
143 /* Setup fixed clocks if enabled */
144 setup_fixed_clocks();
145
146 /* Setup device clock source */
147 MXC_SYS_Clock_Select(ADI_MAX32_SYSCLK_SRC);
148
149 #if DT_NODE_HAS_PROP(DT_NODELABEL(gcr), sysclk_prescaler)
150 /* Setup divider */
151 Wrap_MXC_SYS_SetClockDiv(sysclk_prescaler(ADI_MAX32_SYSCLK_PRESCALER));
152 #endif
153
154 return 0;
155 }
156
157 DEVICE_DT_INST_DEFINE(0, max32_clkctrl_init, NULL, NULL, NULL, PRE_KERNEL_1,
158 CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &max32_clkctrl_api);
159