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