xref: /rk3399_ARM-atf/drivers/nxp/clk/s32cc/s32cc_clk_drv.c (revision 84e82085a1d59624ab7dc14256a152d6d7dd15f2)
13a580e9eSGhennadi Procopciuc /*
23a580e9eSGhennadi Procopciuc  * Copyright 2024 NXP
33a580e9eSGhennadi Procopciuc  *
43a580e9eSGhennadi Procopciuc  * SPDX-License-Identifier: BSD-3-Clause
53a580e9eSGhennadi Procopciuc  */
63a580e9eSGhennadi Procopciuc #include <errno.h>
73a580e9eSGhennadi Procopciuc 
88ab34357SGhennadi Procopciuc #include <s32cc-clk-regs.h>
98ab34357SGhennadi Procopciuc 
10d9373519SGhennadi Procopciuc #include <common/debug.h>
113a580e9eSGhennadi Procopciuc #include <drivers/clk.h>
128ab34357SGhennadi Procopciuc #include <lib/mmio.h>
13b5101c45SGhennadi Procopciuc #include <s32cc-clk-ids.h>
14d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h>
15d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h>
16d9373519SGhennadi Procopciuc 
17d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH		(15U)
18d9373519SGhennadi Procopciuc 
19b5101c45SGhennadi Procopciuc /* This is used for floating-point precision calculations. */
20b5101c45SGhennadi Procopciuc #define FP_PRECISION		(100000000UL)
21b5101c45SGhennadi Procopciuc 
228ab34357SGhennadi Procopciuc struct s32cc_clk_drv {
238ab34357SGhennadi Procopciuc 	uintptr_t fxosc_base;
24b5101c45SGhennadi Procopciuc 	uintptr_t armpll_base;
258ab34357SGhennadi Procopciuc };
268ab34357SGhennadi Procopciuc 
27d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth)
28d9373519SGhennadi Procopciuc {
29d9373519SGhennadi Procopciuc 	if (*depth == 0U) {
30d9373519SGhennadi Procopciuc 		return -ENOMEM;
31d9373519SGhennadi Procopciuc 	}
32d9373519SGhennadi Procopciuc 
33d9373519SGhennadi Procopciuc 	(*depth)--;
34d9373519SGhennadi Procopciuc 	return 0;
35d9373519SGhennadi Procopciuc }
363a580e9eSGhennadi Procopciuc 
378ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void)
388ab34357SGhennadi Procopciuc {
398ab34357SGhennadi Procopciuc 	static struct s32cc_clk_drv driver = {
408ab34357SGhennadi Procopciuc 		.fxosc_base = FXOSC_BASE_ADDR,
41b5101c45SGhennadi Procopciuc 		.armpll_base = ARMPLL_BASE_ADDR,
428ab34357SGhennadi Procopciuc 	};
438ab34357SGhennadi Procopciuc 
448ab34357SGhennadi Procopciuc 	return &driver;
458ab34357SGhennadi Procopciuc }
468ab34357SGhennadi Procopciuc 
478ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth);
488ab34357SGhennadi Procopciuc 
498ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module,
508ab34357SGhennadi Procopciuc 			     const struct s32cc_clk_drv *drv,
518ab34357SGhennadi Procopciuc 			     unsigned int *depth)
528ab34357SGhennadi Procopciuc {
538ab34357SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
548ab34357SGhennadi Procopciuc 	int ret;
558ab34357SGhennadi Procopciuc 
568ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
578ab34357SGhennadi Procopciuc 	if (ret != 0) {
588ab34357SGhennadi Procopciuc 		return ret;
598ab34357SGhennadi Procopciuc 	}
608ab34357SGhennadi Procopciuc 
618ab34357SGhennadi Procopciuc 	if (clk == NULL) {
628ab34357SGhennadi Procopciuc 		return -EINVAL;
638ab34357SGhennadi Procopciuc 	}
648ab34357SGhennadi Procopciuc 
658ab34357SGhennadi Procopciuc 	if (clk->module != NULL) {
668ab34357SGhennadi Procopciuc 		return enable_module(clk->module, depth);
678ab34357SGhennadi Procopciuc 	}
688ab34357SGhennadi Procopciuc 
698ab34357SGhennadi Procopciuc 	if (clk->pclock != NULL) {
708ab34357SGhennadi Procopciuc 		return enable_clk_module(&clk->pclock->desc, drv, depth);
718ab34357SGhennadi Procopciuc 	}
728ab34357SGhennadi Procopciuc 
738ab34357SGhennadi Procopciuc 	return -EINVAL;
748ab34357SGhennadi Procopciuc }
758ab34357SGhennadi Procopciuc 
76b5101c45SGhennadi Procopciuc static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv,
77b5101c45SGhennadi Procopciuc 			 uintptr_t *base)
78b5101c45SGhennadi Procopciuc {
79b5101c45SGhennadi Procopciuc 	int ret = 0;
80b5101c45SGhennadi Procopciuc 
81b5101c45SGhennadi Procopciuc 	switch (id) {
82b5101c45SGhennadi Procopciuc 	case S32CC_FXOSC:
83b5101c45SGhennadi Procopciuc 		*base = drv->fxosc_base;
84b5101c45SGhennadi Procopciuc 		break;
85b5101c45SGhennadi Procopciuc 	case S32CC_ARM_PLL:
86b5101c45SGhennadi Procopciuc 		*base = drv->armpll_base;
87b5101c45SGhennadi Procopciuc 		break;
88b5101c45SGhennadi Procopciuc 	case S32CC_CGM1:
89b5101c45SGhennadi Procopciuc 		ret = -ENOTSUP;
90b5101c45SGhennadi Procopciuc 		break;
91b5101c45SGhennadi Procopciuc 	case S32CC_FIRC:
92b5101c45SGhennadi Procopciuc 		break;
93b5101c45SGhennadi Procopciuc 	case S32CC_SIRC:
94b5101c45SGhennadi Procopciuc 		break;
95b5101c45SGhennadi Procopciuc 	default:
96b5101c45SGhennadi Procopciuc 		ret = -EINVAL;
97b5101c45SGhennadi Procopciuc 		break;
98b5101c45SGhennadi Procopciuc 	}
99b5101c45SGhennadi Procopciuc 
100b5101c45SGhennadi Procopciuc 	if (ret != 0) {
101b5101c45SGhennadi Procopciuc 		ERROR("Unknown clock source id: %u\n", id);
102b5101c45SGhennadi Procopciuc 	}
103b5101c45SGhennadi Procopciuc 
104b5101c45SGhennadi Procopciuc 	return ret;
105b5101c45SGhennadi Procopciuc }
106b5101c45SGhennadi Procopciuc 
1078ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv)
1088ab34357SGhennadi Procopciuc {
1098ab34357SGhennadi Procopciuc 	uintptr_t fxosc_base = drv->fxosc_base;
1108ab34357SGhennadi Procopciuc 	uint32_t ctrl;
1118ab34357SGhennadi Procopciuc 
1128ab34357SGhennadi Procopciuc 	ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base));
1138ab34357SGhennadi Procopciuc 	if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) {
1148ab34357SGhennadi Procopciuc 		return;
1158ab34357SGhennadi Procopciuc 	}
1168ab34357SGhennadi Procopciuc 
1178ab34357SGhennadi Procopciuc 	ctrl = FXOSC_CTRL_COMP_EN;
1188ab34357SGhennadi Procopciuc 	ctrl &= ~FXOSC_CTRL_OSC_BYP;
1198ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_EOCV(0x1);
1208ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_GM_SEL(0x7);
1218ab34357SGhennadi Procopciuc 	mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl);
1228ab34357SGhennadi Procopciuc 
1238ab34357SGhennadi Procopciuc 	/* Switch ON the crystal oscillator. */
1248ab34357SGhennadi Procopciuc 	mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON);
1258ab34357SGhennadi Procopciuc 
1268ab34357SGhennadi Procopciuc 	/* Wait until the clock is stable. */
1278ab34357SGhennadi Procopciuc 	while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) {
1288ab34357SGhennadi Procopciuc 	}
1298ab34357SGhennadi Procopciuc }
1308ab34357SGhennadi Procopciuc 
1318ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module,
1328ab34357SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
1338ab34357SGhennadi Procopciuc 		      unsigned int *depth)
1348ab34357SGhennadi Procopciuc {
1358ab34357SGhennadi Procopciuc 	const struct s32cc_osc *osc = s32cc_obj2osc(module);
1368ab34357SGhennadi Procopciuc 	int ret = 0;
1378ab34357SGhennadi Procopciuc 
1388ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1398ab34357SGhennadi Procopciuc 	if (ret != 0) {
1408ab34357SGhennadi Procopciuc 		return ret;
1418ab34357SGhennadi Procopciuc 	}
1428ab34357SGhennadi Procopciuc 
1438ab34357SGhennadi Procopciuc 	switch (osc->source) {
1448ab34357SGhennadi Procopciuc 	case S32CC_FXOSC:
1458ab34357SGhennadi Procopciuc 		enable_fxosc(drv);
1468ab34357SGhennadi Procopciuc 		break;
1478ab34357SGhennadi Procopciuc 	/* FIRC and SIRC oscillators are enabled by default */
1488ab34357SGhennadi Procopciuc 	case S32CC_FIRC:
1498ab34357SGhennadi Procopciuc 		break;
1508ab34357SGhennadi Procopciuc 	case S32CC_SIRC:
1518ab34357SGhennadi Procopciuc 		break;
1528ab34357SGhennadi Procopciuc 	default:
1538ab34357SGhennadi Procopciuc 		ERROR("Invalid oscillator %d\n", osc->source);
1548ab34357SGhennadi Procopciuc 		ret = -EINVAL;
1558ab34357SGhennadi Procopciuc 		break;
1568ab34357SGhennadi Procopciuc 	};
1578ab34357SGhennadi Procopciuc 
1588ab34357SGhennadi Procopciuc 	return ret;
1598ab34357SGhennadi Procopciuc }
1608ab34357SGhennadi Procopciuc 
161b5101c45SGhennadi Procopciuc static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq,
162b5101c45SGhennadi Procopciuc 			   uint32_t *mfi, uint32_t *mfn)
163b5101c45SGhennadi Procopciuc 
164b5101c45SGhennadi Procopciuc {
165b5101c45SGhennadi Procopciuc 	unsigned long vco;
166b5101c45SGhennadi Procopciuc 	unsigned long mfn64;
167b5101c45SGhennadi Procopciuc 
168b5101c45SGhennadi Procopciuc 	/* FRAC-N mode */
169b5101c45SGhennadi Procopciuc 	*mfi = (uint32_t)(pll_vco / ref_freq);
170b5101c45SGhennadi Procopciuc 
171b5101c45SGhennadi Procopciuc 	/* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */
172b5101c45SGhennadi Procopciuc 	mfn64 = pll_vco % ref_freq;
173b5101c45SGhennadi Procopciuc 	mfn64 *= FP_PRECISION;
174b5101c45SGhennadi Procopciuc 	mfn64 /= ref_freq;
175b5101c45SGhennadi Procopciuc 	mfn64 *= 18432UL;
176b5101c45SGhennadi Procopciuc 	mfn64 /= FP_PRECISION;
177b5101c45SGhennadi Procopciuc 
178b5101c45SGhennadi Procopciuc 	if (mfn64 > UINT32_MAX) {
179b5101c45SGhennadi Procopciuc 		return -EINVAL;
180b5101c45SGhennadi Procopciuc 	}
181b5101c45SGhennadi Procopciuc 
182b5101c45SGhennadi Procopciuc 	*mfn = (uint32_t)mfn64;
183b5101c45SGhennadi Procopciuc 
184b5101c45SGhennadi Procopciuc 	vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL;
185b5101c45SGhennadi Procopciuc 	vco += (unsigned long)*mfi * FP_PRECISION;
186b5101c45SGhennadi Procopciuc 	vco *= ref_freq;
187b5101c45SGhennadi Procopciuc 	vco /= FP_PRECISION;
188b5101c45SGhennadi Procopciuc 
189b5101c45SGhennadi Procopciuc 	if (vco != pll_vco) {
190b5101c45SGhennadi Procopciuc 		ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n",
191b5101c45SGhennadi Procopciuc 		      pll_vco, vco);
192b5101c45SGhennadi Procopciuc 		return -EINVAL;
193b5101c45SGhennadi Procopciuc 	}
194b5101c45SGhennadi Procopciuc 
195b5101c45SGhennadi Procopciuc 	return 0;
196b5101c45SGhennadi Procopciuc }
197b5101c45SGhennadi Procopciuc 
198b5101c45SGhennadi Procopciuc static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll)
199b5101c45SGhennadi Procopciuc {
200b5101c45SGhennadi Procopciuc 	const struct s32cc_clk_obj *source = pll->source;
201b5101c45SGhennadi Procopciuc 	const struct s32cc_clk *clk;
202b5101c45SGhennadi Procopciuc 
203b5101c45SGhennadi Procopciuc 	if (source == NULL) {
204b5101c45SGhennadi Procopciuc 		ERROR("Failed to identify PLL's parent\n");
205b5101c45SGhennadi Procopciuc 		return NULL;
206b5101c45SGhennadi Procopciuc 	}
207b5101c45SGhennadi Procopciuc 
208b5101c45SGhennadi Procopciuc 	if (source->type != s32cc_clk_t) {
209b5101c45SGhennadi Procopciuc 		ERROR("The parent of the PLL isn't a clock\n");
210b5101c45SGhennadi Procopciuc 		return NULL;
211b5101c45SGhennadi Procopciuc 	}
212b5101c45SGhennadi Procopciuc 
213b5101c45SGhennadi Procopciuc 	clk = s32cc_obj2clk(source);
214b5101c45SGhennadi Procopciuc 
215b5101c45SGhennadi Procopciuc 	if (clk->module == NULL) {
216b5101c45SGhennadi Procopciuc 		ERROR("The clock isn't connected to a module\n");
217b5101c45SGhennadi Procopciuc 		return NULL;
218b5101c45SGhennadi Procopciuc 	}
219b5101c45SGhennadi Procopciuc 
220b5101c45SGhennadi Procopciuc 	source = clk->module;
221b5101c45SGhennadi Procopciuc 
222b5101c45SGhennadi Procopciuc 	if ((source->type != s32cc_clkmux_t) &&
223b5101c45SGhennadi Procopciuc 	    (source->type != s32cc_shared_clkmux_t)) {
224b5101c45SGhennadi Procopciuc 		ERROR("The parent of the PLL isn't a MUX\n");
225b5101c45SGhennadi Procopciuc 		return NULL;
226b5101c45SGhennadi Procopciuc 	}
227b5101c45SGhennadi Procopciuc 
228b5101c45SGhennadi Procopciuc 	return s32cc_obj2clkmux(source);
229b5101c45SGhennadi Procopciuc }
230b5101c45SGhennadi Procopciuc 
231b5101c45SGhennadi Procopciuc static void disable_odiv(uintptr_t pll_addr, uint32_t div_index)
232b5101c45SGhennadi Procopciuc {
233b5101c45SGhennadi Procopciuc 	mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
234b5101c45SGhennadi Procopciuc }
235b5101c45SGhennadi Procopciuc 
236*84e82085SGhennadi Procopciuc static void enable_odiv(uintptr_t pll_addr, uint32_t div_index)
237*84e82085SGhennadi Procopciuc {
238*84e82085SGhennadi Procopciuc 	mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
239*84e82085SGhennadi Procopciuc }
240*84e82085SGhennadi Procopciuc 
241b5101c45SGhennadi Procopciuc static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs)
242b5101c45SGhennadi Procopciuc {
243b5101c45SGhennadi Procopciuc 	uint32_t i;
244b5101c45SGhennadi Procopciuc 
245b5101c45SGhennadi Procopciuc 	for (i = 0; i < ndivs; i++) {
246b5101c45SGhennadi Procopciuc 		disable_odiv(pll_addr, i);
247b5101c45SGhennadi Procopciuc 	}
248b5101c45SGhennadi Procopciuc }
249b5101c45SGhennadi Procopciuc 
250b5101c45SGhennadi Procopciuc static void enable_pll_hw(uintptr_t pll_addr)
251b5101c45SGhennadi Procopciuc {
252b5101c45SGhennadi Procopciuc 	/* Enable the PLL. */
253b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0);
254b5101c45SGhennadi Procopciuc 
255b5101c45SGhennadi Procopciuc 	/* Poll until PLL acquires lock. */
256b5101c45SGhennadi Procopciuc 	while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) {
257b5101c45SGhennadi Procopciuc 	}
258b5101c45SGhennadi Procopciuc }
259b5101c45SGhennadi Procopciuc 
260b5101c45SGhennadi Procopciuc static void disable_pll_hw(uintptr_t pll_addr)
261b5101c45SGhennadi Procopciuc {
262b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD);
263b5101c45SGhennadi Procopciuc }
264b5101c45SGhennadi Procopciuc 
265b5101c45SGhennadi Procopciuc static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr,
266b5101c45SGhennadi Procopciuc 		       const struct s32cc_clk_drv *drv, uint32_t sclk_id,
267b5101c45SGhennadi Procopciuc 		       unsigned long sclk_freq)
268b5101c45SGhennadi Procopciuc {
269b5101c45SGhennadi Procopciuc 	uint32_t rdiv = 1, mfi, mfn;
270b5101c45SGhennadi Procopciuc 	int ret;
271b5101c45SGhennadi Procopciuc 
272b5101c45SGhennadi Procopciuc 	ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn);
273b5101c45SGhennadi Procopciuc 	if (ret != 0) {
274b5101c45SGhennadi Procopciuc 		return -EINVAL;
275b5101c45SGhennadi Procopciuc 	}
276b5101c45SGhennadi Procopciuc 
277b5101c45SGhennadi Procopciuc 	/* Disable ODIVs*/
278b5101c45SGhennadi Procopciuc 	disable_odivs(pll_addr, pll->ndividers);
279b5101c45SGhennadi Procopciuc 
280b5101c45SGhennadi Procopciuc 	/* Disable PLL */
281b5101c45SGhennadi Procopciuc 	disable_pll_hw(pll_addr);
282b5101c45SGhennadi Procopciuc 
283b5101c45SGhennadi Procopciuc 	/* Program PLLCLKMUX */
284b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id);
285b5101c45SGhennadi Procopciuc 
286b5101c45SGhennadi Procopciuc 	/* Program VCO */
287b5101c45SGhennadi Procopciuc 	mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr),
288b5101c45SGhennadi Procopciuc 			   PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK,
289b5101c45SGhennadi Procopciuc 			   PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi));
290b5101c45SGhennadi Procopciuc 
291b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLFD(pll_addr),
292b5101c45SGhennadi Procopciuc 		      PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN);
293b5101c45SGhennadi Procopciuc 
294b5101c45SGhennadi Procopciuc 	enable_pll_hw(pll_addr);
295b5101c45SGhennadi Procopciuc 
296b5101c45SGhennadi Procopciuc 	return ret;
297b5101c45SGhennadi Procopciuc }
298b5101c45SGhennadi Procopciuc 
299b5101c45SGhennadi Procopciuc static int enable_pll(const struct s32cc_clk_obj *module,
300b5101c45SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
301b5101c45SGhennadi Procopciuc 		      unsigned int *depth)
302b5101c45SGhennadi Procopciuc {
303b5101c45SGhennadi Procopciuc 	const struct s32cc_pll *pll = s32cc_obj2pll(module);
304b5101c45SGhennadi Procopciuc 	const struct s32cc_clkmux *mux;
305b5101c45SGhennadi Procopciuc 	uintptr_t pll_addr = UL(0x0);
306b5101c45SGhennadi Procopciuc 	unsigned long sclk_freq;
307b5101c45SGhennadi Procopciuc 	uint32_t sclk_id;
308b5101c45SGhennadi Procopciuc 	int ret;
309b5101c45SGhennadi Procopciuc 
310b5101c45SGhennadi Procopciuc 	ret = update_stack_depth(depth);
311b5101c45SGhennadi Procopciuc 	if (ret != 0) {
312b5101c45SGhennadi Procopciuc 		return ret;
313b5101c45SGhennadi Procopciuc 	}
314b5101c45SGhennadi Procopciuc 
315b5101c45SGhennadi Procopciuc 	mux = get_pll_mux(pll);
316b5101c45SGhennadi Procopciuc 	if (mux == NULL) {
317b5101c45SGhennadi Procopciuc 		return -EINVAL;
318b5101c45SGhennadi Procopciuc 	}
319b5101c45SGhennadi Procopciuc 
320b5101c45SGhennadi Procopciuc 	if (pll->instance != mux->module) {
321b5101c45SGhennadi Procopciuc 		ERROR("MUX type is not in sync with PLL ID\n");
322b5101c45SGhennadi Procopciuc 		return -EINVAL;
323b5101c45SGhennadi Procopciuc 	}
324b5101c45SGhennadi Procopciuc 
325b5101c45SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
326b5101c45SGhennadi Procopciuc 	if (ret != 0) {
327b5101c45SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
328b5101c45SGhennadi Procopciuc 		return ret;
329b5101c45SGhennadi Procopciuc 	}
330b5101c45SGhennadi Procopciuc 
331b5101c45SGhennadi Procopciuc 	switch (mux->source_id) {
332b5101c45SGhennadi Procopciuc 	case S32CC_CLK_FIRC:
333b5101c45SGhennadi Procopciuc 		sclk_freq = 48U * MHZ;
334b5101c45SGhennadi Procopciuc 		sclk_id = 0;
335b5101c45SGhennadi Procopciuc 		break;
336b5101c45SGhennadi Procopciuc 	case S32CC_CLK_FXOSC:
337b5101c45SGhennadi Procopciuc 		sclk_freq = 40U * MHZ;
338b5101c45SGhennadi Procopciuc 		sclk_id = 1;
339b5101c45SGhennadi Procopciuc 		break;
340b5101c45SGhennadi Procopciuc 	default:
341b5101c45SGhennadi Procopciuc 		ERROR("Invalid source selection for PLL 0x%lx\n",
342b5101c45SGhennadi Procopciuc 		      pll_addr);
343b5101c45SGhennadi Procopciuc 		return -EINVAL;
344b5101c45SGhennadi Procopciuc 	};
345b5101c45SGhennadi Procopciuc 
346b5101c45SGhennadi Procopciuc 	return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq);
347b5101c45SGhennadi Procopciuc }
348b5101c45SGhennadi Procopciuc 
349*84e82085SGhennadi Procopciuc static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv)
350*84e82085SGhennadi Procopciuc {
351*84e82085SGhennadi Procopciuc 	const struct s32cc_clk_obj *parent;
352*84e82085SGhennadi Procopciuc 
353*84e82085SGhennadi Procopciuc 	parent = pdiv->parent;
354*84e82085SGhennadi Procopciuc 	if (parent == NULL) {
355*84e82085SGhennadi Procopciuc 		ERROR("Failed to identify PLL divider's parent\n");
356*84e82085SGhennadi Procopciuc 		return NULL;
357*84e82085SGhennadi Procopciuc 	}
358*84e82085SGhennadi Procopciuc 
359*84e82085SGhennadi Procopciuc 	if (parent->type != s32cc_pll_t) {
360*84e82085SGhennadi Procopciuc 		ERROR("The parent of the divider is not a PLL instance\n");
361*84e82085SGhennadi Procopciuc 		return NULL;
362*84e82085SGhennadi Procopciuc 	}
363*84e82085SGhennadi Procopciuc 
364*84e82085SGhennadi Procopciuc 	return s32cc_obj2pll(parent);
365*84e82085SGhennadi Procopciuc }
366*84e82085SGhennadi Procopciuc 
367*84e82085SGhennadi Procopciuc static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc)
368*84e82085SGhennadi Procopciuc {
369*84e82085SGhennadi Procopciuc 	uint32_t pllodiv;
370*84e82085SGhennadi Procopciuc 	uint32_t pdiv;
371*84e82085SGhennadi Procopciuc 
372*84e82085SGhennadi Procopciuc 	pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index));
373*84e82085SGhennadi Procopciuc 	pdiv = PLLDIG_PLLODIV_DIV(pllodiv);
374*84e82085SGhennadi Procopciuc 
375*84e82085SGhennadi Procopciuc 	if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) {
376*84e82085SGhennadi Procopciuc 		return;
377*84e82085SGhennadi Procopciuc 	}
378*84e82085SGhennadi Procopciuc 
379*84e82085SGhennadi Procopciuc 	if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) {
380*84e82085SGhennadi Procopciuc 		disable_odiv(pll_addr, div_index);
381*84e82085SGhennadi Procopciuc 	}
382*84e82085SGhennadi Procopciuc 
383*84e82085SGhennadi Procopciuc 	pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U);
384*84e82085SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv);
385*84e82085SGhennadi Procopciuc 
386*84e82085SGhennadi Procopciuc 	enable_odiv(pll_addr, div_index);
387*84e82085SGhennadi Procopciuc }
388*84e82085SGhennadi Procopciuc 
389*84e82085SGhennadi Procopciuc static int enable_pll_div(const struct s32cc_clk_obj *module,
390*84e82085SGhennadi Procopciuc 			  const struct s32cc_clk_drv *drv,
391*84e82085SGhennadi Procopciuc 			  unsigned int *depth)
392*84e82085SGhennadi Procopciuc {
393*84e82085SGhennadi Procopciuc 	const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
394*84e82085SGhennadi Procopciuc 	uintptr_t pll_addr = 0x0ULL;
395*84e82085SGhennadi Procopciuc 	const struct s32cc_pll *pll;
396*84e82085SGhennadi Procopciuc 	uint32_t dc;
397*84e82085SGhennadi Procopciuc 	int ret;
398*84e82085SGhennadi Procopciuc 
399*84e82085SGhennadi Procopciuc 	ret = update_stack_depth(depth);
400*84e82085SGhennadi Procopciuc 	if (ret != 0) {
401*84e82085SGhennadi Procopciuc 		return ret;
402*84e82085SGhennadi Procopciuc 	}
403*84e82085SGhennadi Procopciuc 
404*84e82085SGhennadi Procopciuc 	pll = get_div_pll(pdiv);
405*84e82085SGhennadi Procopciuc 	if (pll == NULL) {
406*84e82085SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
407*84e82085SGhennadi Procopciuc 		return 0;
408*84e82085SGhennadi Procopciuc 	}
409*84e82085SGhennadi Procopciuc 
410*84e82085SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
411*84e82085SGhennadi Procopciuc 	if (ret != 0) {
412*84e82085SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
413*84e82085SGhennadi Procopciuc 		return -EINVAL;
414*84e82085SGhennadi Procopciuc 	}
415*84e82085SGhennadi Procopciuc 
416*84e82085SGhennadi Procopciuc 	dc = (uint32_t)(pll->vco_freq / pdiv->freq);
417*84e82085SGhennadi Procopciuc 
418*84e82085SGhennadi Procopciuc 	config_pll_out_div(pll_addr, pdiv->index, dc);
419*84e82085SGhennadi Procopciuc 
420*84e82085SGhennadi Procopciuc 	return 0;
421*84e82085SGhennadi Procopciuc }
422*84e82085SGhennadi Procopciuc 
4238ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
4248ab34357SGhennadi Procopciuc {
4258ab34357SGhennadi Procopciuc 	const struct s32cc_clk_drv *drv = get_drv();
4268ab34357SGhennadi Procopciuc 	int ret = 0;
4278ab34357SGhennadi Procopciuc 
4288ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
4298ab34357SGhennadi Procopciuc 	if (ret != 0) {
4308ab34357SGhennadi Procopciuc 		return ret;
4318ab34357SGhennadi Procopciuc 	}
4328ab34357SGhennadi Procopciuc 
4338ab34357SGhennadi Procopciuc 	if (drv == NULL) {
4348ab34357SGhennadi Procopciuc 		return -EINVAL;
4358ab34357SGhennadi Procopciuc 	}
4368ab34357SGhennadi Procopciuc 
4378ab34357SGhennadi Procopciuc 	switch (module->type) {
4388ab34357SGhennadi Procopciuc 	case s32cc_osc_t:
4398ab34357SGhennadi Procopciuc 		ret = enable_osc(module, drv, depth);
4408ab34357SGhennadi Procopciuc 		break;
4418ab34357SGhennadi Procopciuc 	case s32cc_clk_t:
4428ab34357SGhennadi Procopciuc 		ret = enable_clk_module(module, drv, depth);
4438ab34357SGhennadi Procopciuc 		break;
444b5101c45SGhennadi Procopciuc 	case s32cc_pll_t:
445b5101c45SGhennadi Procopciuc 		ret = enable_pll(module, drv, depth);
446b5101c45SGhennadi Procopciuc 		break;
447*84e82085SGhennadi Procopciuc 	case s32cc_pll_out_div_t:
448*84e82085SGhennadi Procopciuc 		ret = enable_pll_div(module, drv, depth);
449*84e82085SGhennadi Procopciuc 		break;
450a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
451a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
452a8be748aSGhennadi Procopciuc 		break;
4533fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
4543fa91a94SGhennadi Procopciuc 		ret = -ENOTSUP;
4553fa91a94SGhennadi Procopciuc 		break;
45644e2130aSGhennadi Procopciuc 	case s32cc_fixed_div_t:
457a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
458a8be748aSGhennadi Procopciuc 		break;
4598ab34357SGhennadi Procopciuc 	default:
4608ab34357SGhennadi Procopciuc 		ret = -EINVAL;
4618ab34357SGhennadi Procopciuc 		break;
4628ab34357SGhennadi Procopciuc 	}
4638ab34357SGhennadi Procopciuc 
4648ab34357SGhennadi Procopciuc 	return ret;
4658ab34357SGhennadi Procopciuc }
4668ab34357SGhennadi Procopciuc 
4673a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id)
4683a580e9eSGhennadi Procopciuc {
4698ab34357SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
4708ab34357SGhennadi Procopciuc 	const struct s32cc_clk *clk;
4718ab34357SGhennadi Procopciuc 
4728ab34357SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
4738ab34357SGhennadi Procopciuc 	if (clk == NULL) {
4748ab34357SGhennadi Procopciuc 		return -EINVAL;
4758ab34357SGhennadi Procopciuc 	}
4768ab34357SGhennadi Procopciuc 
4778ab34357SGhennadi Procopciuc 	return enable_module(&clk->desc, &depth);
4783a580e9eSGhennadi Procopciuc }
4793a580e9eSGhennadi Procopciuc 
4803a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id)
4813a580e9eSGhennadi Procopciuc {
4823a580e9eSGhennadi Procopciuc }
4833a580e9eSGhennadi Procopciuc 
4843a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id)
4853a580e9eSGhennadi Procopciuc {
4863a580e9eSGhennadi Procopciuc 	return false;
4873a580e9eSGhennadi Procopciuc }
4883a580e9eSGhennadi Procopciuc 
4893a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id)
4903a580e9eSGhennadi Procopciuc {
4913a580e9eSGhennadi Procopciuc 	return 0;
4923a580e9eSGhennadi Procopciuc }
4933a580e9eSGhennadi Procopciuc 
494d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
495d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
496d9373519SGhennadi Procopciuc 			   unsigned int *depth);
497d9373519SGhennadi Procopciuc 
498d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
499d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
500d9373519SGhennadi Procopciuc {
501d9373519SGhennadi Procopciuc 	struct s32cc_osc *osc = s32cc_obj2osc(module);
502d9373519SGhennadi Procopciuc 	int ret;
503d9373519SGhennadi Procopciuc 
504d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
505d9373519SGhennadi Procopciuc 	if (ret != 0) {
506d9373519SGhennadi Procopciuc 		return ret;
507d9373519SGhennadi Procopciuc 	}
508d9373519SGhennadi Procopciuc 
509d9373519SGhennadi Procopciuc 	if ((osc->freq != 0UL) && (rate != osc->freq)) {
510d9373519SGhennadi Procopciuc 		ERROR("Already initialized oscillator. freq = %lu\n",
511d9373519SGhennadi Procopciuc 		      osc->freq);
512d9373519SGhennadi Procopciuc 		return -EINVAL;
513d9373519SGhennadi Procopciuc 	}
514d9373519SGhennadi Procopciuc 
515d9373519SGhennadi Procopciuc 	osc->freq = rate;
516d9373519SGhennadi Procopciuc 	*orate = osc->freq;
517d9373519SGhennadi Procopciuc 
518d9373519SGhennadi Procopciuc 	return 0;
519d9373519SGhennadi Procopciuc }
520d9373519SGhennadi Procopciuc 
521d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
522d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
523d9373519SGhennadi Procopciuc {
524d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
525d9373519SGhennadi Procopciuc 	int ret;
526d9373519SGhennadi Procopciuc 
527d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
528d9373519SGhennadi Procopciuc 	if (ret != 0) {
529d9373519SGhennadi Procopciuc 		return ret;
530d9373519SGhennadi Procopciuc 	}
531d9373519SGhennadi Procopciuc 
532d9373519SGhennadi Procopciuc 	if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
533d9373519SGhennadi Procopciuc 	    ((rate < clk->min_freq) || (rate > clk->max_freq))) {
534d9373519SGhennadi Procopciuc 		ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
535d9373519SGhennadi Procopciuc 		      rate, clk->min_freq, clk->max_freq);
536d9373519SGhennadi Procopciuc 		return -EINVAL;
537d9373519SGhennadi Procopciuc 	}
538d9373519SGhennadi Procopciuc 
539d9373519SGhennadi Procopciuc 	if (clk->module != NULL) {
540d9373519SGhennadi Procopciuc 		return set_module_rate(clk->module, rate, orate, depth);
541d9373519SGhennadi Procopciuc 	}
542d9373519SGhennadi Procopciuc 
543d9373519SGhennadi Procopciuc 	if (clk->pclock != NULL) {
544d9373519SGhennadi Procopciuc 		return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
545d9373519SGhennadi Procopciuc 	}
546d9373519SGhennadi Procopciuc 
547d9373519SGhennadi Procopciuc 	return -EINVAL;
548d9373519SGhennadi Procopciuc }
549d9373519SGhennadi Procopciuc 
5507ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
5517ad4e231SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
5527ad4e231SGhennadi Procopciuc {
5537ad4e231SGhennadi Procopciuc 	struct s32cc_pll *pll = s32cc_obj2pll(module);
5547ad4e231SGhennadi Procopciuc 	int ret;
5557ad4e231SGhennadi Procopciuc 
5567ad4e231SGhennadi Procopciuc 	ret = update_stack_depth(depth);
5577ad4e231SGhennadi Procopciuc 	if (ret != 0) {
5587ad4e231SGhennadi Procopciuc 		return ret;
5597ad4e231SGhennadi Procopciuc 	}
5607ad4e231SGhennadi Procopciuc 
5617ad4e231SGhennadi Procopciuc 	if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) {
5627ad4e231SGhennadi Procopciuc 		ERROR("PLL frequency was already set\n");
5637ad4e231SGhennadi Procopciuc 		return -EINVAL;
5647ad4e231SGhennadi Procopciuc 	}
5657ad4e231SGhennadi Procopciuc 
5667ad4e231SGhennadi Procopciuc 	pll->vco_freq = rate;
5677ad4e231SGhennadi Procopciuc 	*orate = pll->vco_freq;
5687ad4e231SGhennadi Procopciuc 
5697ad4e231SGhennadi Procopciuc 	return 0;
5707ad4e231SGhennadi Procopciuc }
5717ad4e231SGhennadi Procopciuc 
572de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
573de950ef0SGhennadi Procopciuc 			    unsigned long *orate, unsigned int *depth)
574de950ef0SGhennadi Procopciuc {
575de950ef0SGhennadi Procopciuc 	struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
576de950ef0SGhennadi Procopciuc 	const struct s32cc_pll *pll;
577de950ef0SGhennadi Procopciuc 	unsigned long prate, dc;
578de950ef0SGhennadi Procopciuc 	int ret;
579de950ef0SGhennadi Procopciuc 
580de950ef0SGhennadi Procopciuc 	ret = update_stack_depth(depth);
581de950ef0SGhennadi Procopciuc 	if (ret != 0) {
582de950ef0SGhennadi Procopciuc 		return ret;
583de950ef0SGhennadi Procopciuc 	}
584de950ef0SGhennadi Procopciuc 
585de950ef0SGhennadi Procopciuc 	if (pdiv->parent == NULL) {
586de950ef0SGhennadi Procopciuc 		ERROR("Failed to identify PLL divider's parent\n");
587de950ef0SGhennadi Procopciuc 		return -EINVAL;
588de950ef0SGhennadi Procopciuc 	}
589de950ef0SGhennadi Procopciuc 
590de950ef0SGhennadi Procopciuc 	pll = s32cc_obj2pll(pdiv->parent);
591de950ef0SGhennadi Procopciuc 	if (pll == NULL) {
592de950ef0SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
593de950ef0SGhennadi Procopciuc 		return -EINVAL;
594de950ef0SGhennadi Procopciuc 	}
595de950ef0SGhennadi Procopciuc 
596de950ef0SGhennadi Procopciuc 	prate = pll->vco_freq;
597de950ef0SGhennadi Procopciuc 
598de950ef0SGhennadi Procopciuc 	/**
599de950ef0SGhennadi Procopciuc 	 * The PLL is not initialized yet, so let's take a risk
600de950ef0SGhennadi Procopciuc 	 * and accept the proposed rate.
601de950ef0SGhennadi Procopciuc 	 */
602de950ef0SGhennadi Procopciuc 	if (prate == 0UL) {
603de950ef0SGhennadi Procopciuc 		pdiv->freq = rate;
604de950ef0SGhennadi Procopciuc 		*orate = rate;
605de950ef0SGhennadi Procopciuc 		return 0;
606de950ef0SGhennadi Procopciuc 	}
607de950ef0SGhennadi Procopciuc 
608de950ef0SGhennadi Procopciuc 	/* Decline in case the rate cannot fit PLL's requirements. */
609de950ef0SGhennadi Procopciuc 	dc = prate / rate;
610de950ef0SGhennadi Procopciuc 	if ((prate / dc) != rate) {
611de950ef0SGhennadi Procopciuc 		return -EINVAL;
612de950ef0SGhennadi Procopciuc 	}
613de950ef0SGhennadi Procopciuc 
614de950ef0SGhennadi Procopciuc 	pdiv->freq = rate;
615de950ef0SGhennadi Procopciuc 	*orate = pdiv->freq;
616de950ef0SGhennadi Procopciuc 
617de950ef0SGhennadi Procopciuc 	return 0;
618de950ef0SGhennadi Procopciuc }
619de950ef0SGhennadi Procopciuc 
62065739db2SGhennadi Procopciuc static int set_fixed_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
62165739db2SGhennadi Procopciuc 			      unsigned long *orate, unsigned int *depth)
62265739db2SGhennadi Procopciuc {
62365739db2SGhennadi Procopciuc 	const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module);
62465739db2SGhennadi Procopciuc 	int ret;
62565739db2SGhennadi Procopciuc 
62665739db2SGhennadi Procopciuc 	ret = update_stack_depth(depth);
62765739db2SGhennadi Procopciuc 	if (ret != 0) {
62865739db2SGhennadi Procopciuc 		return ret;
62965739db2SGhennadi Procopciuc 	}
63065739db2SGhennadi Procopciuc 
63165739db2SGhennadi Procopciuc 	if (fdiv->parent == NULL) {
63265739db2SGhennadi Procopciuc 		ERROR("The divider doesn't have a valid parent\b");
63365739db2SGhennadi Procopciuc 		return -EINVAL;
63465739db2SGhennadi Procopciuc 	}
63565739db2SGhennadi Procopciuc 
63665739db2SGhennadi Procopciuc 	ret = set_module_rate(fdiv->parent, rate * fdiv->rate_div, orate, depth);
63765739db2SGhennadi Procopciuc 
63865739db2SGhennadi Procopciuc 	/* Update the output rate based on the parent's rate */
63965739db2SGhennadi Procopciuc 	*orate /= fdiv->rate_div;
64065739db2SGhennadi Procopciuc 
64165739db2SGhennadi Procopciuc 	return ret;
64265739db2SGhennadi Procopciuc }
64365739db2SGhennadi Procopciuc 
64464e0c226SGhennadi Procopciuc static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate,
64564e0c226SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
64664e0c226SGhennadi Procopciuc {
64764e0c226SGhennadi Procopciuc 	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
64864e0c226SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id);
64964e0c226SGhennadi Procopciuc 	int ret;
65064e0c226SGhennadi Procopciuc 
65164e0c226SGhennadi Procopciuc 	ret = update_stack_depth(depth);
65264e0c226SGhennadi Procopciuc 	if (ret != 0) {
65364e0c226SGhennadi Procopciuc 		return ret;
65464e0c226SGhennadi Procopciuc 	}
65564e0c226SGhennadi Procopciuc 
65664e0c226SGhennadi Procopciuc 	if (clk == NULL) {
65764e0c226SGhennadi Procopciuc 		ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n",
65864e0c226SGhennadi Procopciuc 		      mux->index, mux->source_id);
65964e0c226SGhennadi Procopciuc 		return -EINVAL;
66064e0c226SGhennadi Procopciuc 	}
66164e0c226SGhennadi Procopciuc 
66264e0c226SGhennadi Procopciuc 	return set_module_rate(&clk->desc, rate, orate, depth);
66364e0c226SGhennadi Procopciuc }
66464e0c226SGhennadi Procopciuc 
665d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
666d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
667d9373519SGhennadi Procopciuc 			   unsigned int *depth)
668d9373519SGhennadi Procopciuc {
669d9373519SGhennadi Procopciuc 	int ret = 0;
670d9373519SGhennadi Procopciuc 
671d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
672d9373519SGhennadi Procopciuc 	if (ret != 0) {
673d9373519SGhennadi Procopciuc 		return ret;
674d9373519SGhennadi Procopciuc 	}
675d9373519SGhennadi Procopciuc 
676d9373519SGhennadi Procopciuc 	switch (module->type) {
677d9373519SGhennadi Procopciuc 	case s32cc_clk_t:
678d9373519SGhennadi Procopciuc 		ret = set_clk_freq(module, rate, orate, depth);
679d9373519SGhennadi Procopciuc 		break;
680d9373519SGhennadi Procopciuc 	case s32cc_osc_t:
681d9373519SGhennadi Procopciuc 		ret = set_osc_freq(module, rate, orate, depth);
682d9373519SGhennadi Procopciuc 		break;
6837ad4e231SGhennadi Procopciuc 	case s32cc_pll_t:
6847ad4e231SGhennadi Procopciuc 		ret = set_pll_freq(module, rate, orate, depth);
6857ad4e231SGhennadi Procopciuc 		break;
686de950ef0SGhennadi Procopciuc 	case s32cc_pll_out_div_t:
687de950ef0SGhennadi Procopciuc 		ret = set_pll_div_freq(module, rate, orate, depth);
688de950ef0SGhennadi Procopciuc 		break;
68965739db2SGhennadi Procopciuc 	case s32cc_fixed_div_t:
69065739db2SGhennadi Procopciuc 		ret = set_fixed_div_freq(module, rate, orate, depth);
69165739db2SGhennadi Procopciuc 		break;
692a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
69364e0c226SGhennadi Procopciuc 		ret = set_mux_freq(module, rate, orate, depth);
69464e0c226SGhennadi Procopciuc 		break;
6953fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
69664e0c226SGhennadi Procopciuc 		ret = set_mux_freq(module, rate, orate, depth);
697a8be748aSGhennadi Procopciuc 		break;
698d9373519SGhennadi Procopciuc 	default:
699d9373519SGhennadi Procopciuc 		ret = -EINVAL;
700d9373519SGhennadi Procopciuc 		break;
701d9373519SGhennadi Procopciuc 	}
702d9373519SGhennadi Procopciuc 
703d9373519SGhennadi Procopciuc 	return ret;
704d9373519SGhennadi Procopciuc }
705d9373519SGhennadi Procopciuc 
7063a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
7073a580e9eSGhennadi Procopciuc 			      unsigned long *orate)
7083a580e9eSGhennadi Procopciuc {
709d9373519SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
710d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk;
711d9373519SGhennadi Procopciuc 	int ret;
712d9373519SGhennadi Procopciuc 
713d9373519SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
714d9373519SGhennadi Procopciuc 	if (clk == NULL) {
715d9373519SGhennadi Procopciuc 		return -EINVAL;
716d9373519SGhennadi Procopciuc 	}
717d9373519SGhennadi Procopciuc 
718d9373519SGhennadi Procopciuc 	ret = set_module_rate(&clk->desc, rate, orate, &depth);
719d9373519SGhennadi Procopciuc 	if (ret != 0) {
720d9373519SGhennadi Procopciuc 		ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
721d9373519SGhennadi Procopciuc 		      rate, id);
722d9373519SGhennadi Procopciuc 	}
723d9373519SGhennadi Procopciuc 
724d9373519SGhennadi Procopciuc 	return ret;
7253a580e9eSGhennadi Procopciuc }
7263a580e9eSGhennadi Procopciuc 
7273a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id)
7283a580e9eSGhennadi Procopciuc {
7293a580e9eSGhennadi Procopciuc 	return -ENOTSUP;
7303a580e9eSGhennadi Procopciuc }
7313a580e9eSGhennadi Procopciuc 
7323a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
7333a580e9eSGhennadi Procopciuc {
73412e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *parent;
73512e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *clk;
73612e7a2cdSGhennadi Procopciuc 	bool valid_source = false;
73712e7a2cdSGhennadi Procopciuc 	struct s32cc_clkmux *mux;
73812e7a2cdSGhennadi Procopciuc 	uint8_t i;
73912e7a2cdSGhennadi Procopciuc 
74012e7a2cdSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
74112e7a2cdSGhennadi Procopciuc 	if (clk == NULL) {
74212e7a2cdSGhennadi Procopciuc 		return -EINVAL;
74312e7a2cdSGhennadi Procopciuc 	}
74412e7a2cdSGhennadi Procopciuc 
74512e7a2cdSGhennadi Procopciuc 	parent = s32cc_get_arch_clk(parent_id);
74612e7a2cdSGhennadi Procopciuc 	if (parent == NULL) {
74712e7a2cdSGhennadi Procopciuc 		return -EINVAL;
74812e7a2cdSGhennadi Procopciuc 	}
74912e7a2cdSGhennadi Procopciuc 
75012e7a2cdSGhennadi Procopciuc 	if (!is_s32cc_clk_mux(clk)) {
75112e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a mux\n", id);
75212e7a2cdSGhennadi Procopciuc 		return -EINVAL;
75312e7a2cdSGhennadi Procopciuc 	}
75412e7a2cdSGhennadi Procopciuc 
75512e7a2cdSGhennadi Procopciuc 	mux = s32cc_clk2mux(clk);
75612e7a2cdSGhennadi Procopciuc 	if (mux == NULL) {
75712e7a2cdSGhennadi Procopciuc 		ERROR("Failed to cast clock %lu to clock mux\n", id);
75812e7a2cdSGhennadi Procopciuc 		return -EINVAL;
75912e7a2cdSGhennadi Procopciuc 	}
76012e7a2cdSGhennadi Procopciuc 
76112e7a2cdSGhennadi Procopciuc 	for (i = 0; i < mux->nclks; i++) {
76212e7a2cdSGhennadi Procopciuc 		if (mux->clkids[i] == parent_id) {
76312e7a2cdSGhennadi Procopciuc 			valid_source = true;
76412e7a2cdSGhennadi Procopciuc 			break;
76512e7a2cdSGhennadi Procopciuc 		}
76612e7a2cdSGhennadi Procopciuc 	}
76712e7a2cdSGhennadi Procopciuc 
76812e7a2cdSGhennadi Procopciuc 	if (!valid_source) {
76912e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a valid clock for mux %lu\n",
77012e7a2cdSGhennadi Procopciuc 		      parent_id, id);
77112e7a2cdSGhennadi Procopciuc 		return -EINVAL;
77212e7a2cdSGhennadi Procopciuc 	}
77312e7a2cdSGhennadi Procopciuc 
77412e7a2cdSGhennadi Procopciuc 	mux->source_id = parent_id;
77512e7a2cdSGhennadi Procopciuc 
77612e7a2cdSGhennadi Procopciuc 	return 0;
7773a580e9eSGhennadi Procopciuc }
7783a580e9eSGhennadi Procopciuc 
7793a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void)
7803a580e9eSGhennadi Procopciuc {
7813a580e9eSGhennadi Procopciuc 	static const struct clk_ops s32cc_clk_ops = {
7823a580e9eSGhennadi Procopciuc 		.enable		= s32cc_clk_enable,
7833a580e9eSGhennadi Procopciuc 		.disable	= s32cc_clk_disable,
7843a580e9eSGhennadi Procopciuc 		.is_enabled	= s32cc_clk_is_enabled,
7853a580e9eSGhennadi Procopciuc 		.get_rate	= s32cc_clk_get_rate,
7863a580e9eSGhennadi Procopciuc 		.set_rate	= s32cc_clk_set_rate,
7873a580e9eSGhennadi Procopciuc 		.get_parent	= s32cc_clk_get_parent,
7883a580e9eSGhennadi Procopciuc 		.set_parent	= s32cc_clk_set_parent,
7893a580e9eSGhennadi Procopciuc 	};
7903a580e9eSGhennadi Procopciuc 
7913a580e9eSGhennadi Procopciuc 	clk_register(&s32cc_clk_ops);
7923a580e9eSGhennadi Procopciuc }
7933a580e9eSGhennadi Procopciuc 
794