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