xref: /rk3399_ARM-atf/drivers/nxp/clk/s32cc/s32cc_clk_drv.c (revision 44e2130ab9948530cd5eb3fbd1d6d8ead6336845)
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>
13d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h>
14d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h>
15d9373519SGhennadi Procopciuc 
16d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH		(15U)
17d9373519SGhennadi Procopciuc 
188ab34357SGhennadi Procopciuc struct s32cc_clk_drv {
198ab34357SGhennadi Procopciuc 	uintptr_t fxosc_base;
208ab34357SGhennadi Procopciuc };
218ab34357SGhennadi Procopciuc 
22d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth)
23d9373519SGhennadi Procopciuc {
24d9373519SGhennadi Procopciuc 	if (*depth == 0U) {
25d9373519SGhennadi Procopciuc 		return -ENOMEM;
26d9373519SGhennadi Procopciuc 	}
27d9373519SGhennadi Procopciuc 
28d9373519SGhennadi Procopciuc 	(*depth)--;
29d9373519SGhennadi Procopciuc 	return 0;
30d9373519SGhennadi Procopciuc }
313a580e9eSGhennadi Procopciuc 
328ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void)
338ab34357SGhennadi Procopciuc {
348ab34357SGhennadi Procopciuc 	static struct s32cc_clk_drv driver = {
358ab34357SGhennadi Procopciuc 		.fxosc_base = FXOSC_BASE_ADDR,
368ab34357SGhennadi Procopciuc 	};
378ab34357SGhennadi Procopciuc 
388ab34357SGhennadi Procopciuc 	return &driver;
398ab34357SGhennadi Procopciuc }
408ab34357SGhennadi Procopciuc 
418ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth);
428ab34357SGhennadi Procopciuc 
438ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module,
448ab34357SGhennadi Procopciuc 			     const struct s32cc_clk_drv *drv,
458ab34357SGhennadi Procopciuc 			     unsigned int *depth)
468ab34357SGhennadi Procopciuc {
478ab34357SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
488ab34357SGhennadi Procopciuc 	int ret;
498ab34357SGhennadi Procopciuc 
508ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
518ab34357SGhennadi Procopciuc 	if (ret != 0) {
528ab34357SGhennadi Procopciuc 		return ret;
538ab34357SGhennadi Procopciuc 	}
548ab34357SGhennadi Procopciuc 
558ab34357SGhennadi Procopciuc 	if (clk == NULL) {
568ab34357SGhennadi Procopciuc 		return -EINVAL;
578ab34357SGhennadi Procopciuc 	}
588ab34357SGhennadi Procopciuc 
598ab34357SGhennadi Procopciuc 	if (clk->module != NULL) {
608ab34357SGhennadi Procopciuc 		return enable_module(clk->module, depth);
618ab34357SGhennadi Procopciuc 	}
628ab34357SGhennadi Procopciuc 
638ab34357SGhennadi Procopciuc 	if (clk->pclock != NULL) {
648ab34357SGhennadi Procopciuc 		return enable_clk_module(&clk->pclock->desc, drv, depth);
658ab34357SGhennadi Procopciuc 	}
668ab34357SGhennadi Procopciuc 
678ab34357SGhennadi Procopciuc 	return -EINVAL;
688ab34357SGhennadi Procopciuc }
698ab34357SGhennadi Procopciuc 
708ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv)
718ab34357SGhennadi Procopciuc {
728ab34357SGhennadi Procopciuc 	uintptr_t fxosc_base = drv->fxosc_base;
738ab34357SGhennadi Procopciuc 	uint32_t ctrl;
748ab34357SGhennadi Procopciuc 
758ab34357SGhennadi Procopciuc 	ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base));
768ab34357SGhennadi Procopciuc 	if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) {
778ab34357SGhennadi Procopciuc 		return;
788ab34357SGhennadi Procopciuc 	}
798ab34357SGhennadi Procopciuc 
808ab34357SGhennadi Procopciuc 	ctrl = FXOSC_CTRL_COMP_EN;
818ab34357SGhennadi Procopciuc 	ctrl &= ~FXOSC_CTRL_OSC_BYP;
828ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_EOCV(0x1);
838ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_GM_SEL(0x7);
848ab34357SGhennadi Procopciuc 	mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl);
858ab34357SGhennadi Procopciuc 
868ab34357SGhennadi Procopciuc 	/* Switch ON the crystal oscillator. */
878ab34357SGhennadi Procopciuc 	mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON);
888ab34357SGhennadi Procopciuc 
898ab34357SGhennadi Procopciuc 	/* Wait until the clock is stable. */
908ab34357SGhennadi Procopciuc 	while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) {
918ab34357SGhennadi Procopciuc 	}
928ab34357SGhennadi Procopciuc }
938ab34357SGhennadi Procopciuc 
948ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module,
958ab34357SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
968ab34357SGhennadi Procopciuc 		      unsigned int *depth)
978ab34357SGhennadi Procopciuc {
988ab34357SGhennadi Procopciuc 	const struct s32cc_osc *osc = s32cc_obj2osc(module);
998ab34357SGhennadi Procopciuc 	int ret = 0;
1008ab34357SGhennadi Procopciuc 
1018ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1028ab34357SGhennadi Procopciuc 	if (ret != 0) {
1038ab34357SGhennadi Procopciuc 		return ret;
1048ab34357SGhennadi Procopciuc 	}
1058ab34357SGhennadi Procopciuc 
1068ab34357SGhennadi Procopciuc 	switch (osc->source) {
1078ab34357SGhennadi Procopciuc 	case S32CC_FXOSC:
1088ab34357SGhennadi Procopciuc 		enable_fxosc(drv);
1098ab34357SGhennadi Procopciuc 		break;
1108ab34357SGhennadi Procopciuc 	/* FIRC and SIRC oscillators are enabled by default */
1118ab34357SGhennadi Procopciuc 	case S32CC_FIRC:
1128ab34357SGhennadi Procopciuc 		break;
1138ab34357SGhennadi Procopciuc 	case S32CC_SIRC:
1148ab34357SGhennadi Procopciuc 		break;
1158ab34357SGhennadi Procopciuc 	default:
1168ab34357SGhennadi Procopciuc 		ERROR("Invalid oscillator %d\n", osc->source);
1178ab34357SGhennadi Procopciuc 		ret = -EINVAL;
1188ab34357SGhennadi Procopciuc 		break;
1198ab34357SGhennadi Procopciuc 	};
1208ab34357SGhennadi Procopciuc 
1218ab34357SGhennadi Procopciuc 	return ret;
1228ab34357SGhennadi Procopciuc }
1238ab34357SGhennadi Procopciuc 
1248ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
1258ab34357SGhennadi Procopciuc {
1268ab34357SGhennadi Procopciuc 	const struct s32cc_clk_drv *drv = get_drv();
1278ab34357SGhennadi Procopciuc 	int ret = 0;
1288ab34357SGhennadi Procopciuc 
1298ab34357SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1308ab34357SGhennadi Procopciuc 	if (ret != 0) {
1318ab34357SGhennadi Procopciuc 		return ret;
1328ab34357SGhennadi Procopciuc 	}
1338ab34357SGhennadi Procopciuc 
1348ab34357SGhennadi Procopciuc 	if (drv == NULL) {
1358ab34357SGhennadi Procopciuc 		return -EINVAL;
1368ab34357SGhennadi Procopciuc 	}
1378ab34357SGhennadi Procopciuc 
1388ab34357SGhennadi Procopciuc 	switch (module->type) {
1398ab34357SGhennadi Procopciuc 	case s32cc_osc_t:
1408ab34357SGhennadi Procopciuc 		ret = enable_osc(module, drv, depth);
1418ab34357SGhennadi Procopciuc 		break;
1428ab34357SGhennadi Procopciuc 	case s32cc_clk_t:
1438ab34357SGhennadi Procopciuc 		ret = enable_clk_module(module, drv, depth);
1448ab34357SGhennadi Procopciuc 		break;
145a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
146a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
147a8be748aSGhennadi Procopciuc 		break;
1483fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
1493fa91a94SGhennadi Procopciuc 		ret = -ENOTSUP;
1503fa91a94SGhennadi Procopciuc 		break;
151a8be748aSGhennadi Procopciuc 	case s32cc_pll_t:
152a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
153a8be748aSGhennadi Procopciuc 		break;
154a8be748aSGhennadi Procopciuc 	case s32cc_pll_out_div_t:
155*44e2130aSGhennadi Procopciuc 	case s32cc_fixed_div_t:
156a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
157a8be748aSGhennadi Procopciuc 		break;
1588ab34357SGhennadi Procopciuc 	default:
1598ab34357SGhennadi Procopciuc 		ret = -EINVAL;
1608ab34357SGhennadi Procopciuc 		break;
1618ab34357SGhennadi Procopciuc 	}
1628ab34357SGhennadi Procopciuc 
1638ab34357SGhennadi Procopciuc 	return ret;
1648ab34357SGhennadi Procopciuc }
1658ab34357SGhennadi Procopciuc 
1663a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id)
1673a580e9eSGhennadi Procopciuc {
1688ab34357SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
1698ab34357SGhennadi Procopciuc 	const struct s32cc_clk *clk;
1708ab34357SGhennadi Procopciuc 
1718ab34357SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
1728ab34357SGhennadi Procopciuc 	if (clk == NULL) {
1738ab34357SGhennadi Procopciuc 		return -EINVAL;
1748ab34357SGhennadi Procopciuc 	}
1758ab34357SGhennadi Procopciuc 
1768ab34357SGhennadi Procopciuc 	return enable_module(&clk->desc, &depth);
1773a580e9eSGhennadi Procopciuc }
1783a580e9eSGhennadi Procopciuc 
1793a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id)
1803a580e9eSGhennadi Procopciuc {
1813a580e9eSGhennadi Procopciuc }
1823a580e9eSGhennadi Procopciuc 
1833a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id)
1843a580e9eSGhennadi Procopciuc {
1853a580e9eSGhennadi Procopciuc 	return false;
1863a580e9eSGhennadi Procopciuc }
1873a580e9eSGhennadi Procopciuc 
1883a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id)
1893a580e9eSGhennadi Procopciuc {
1903a580e9eSGhennadi Procopciuc 	return 0;
1913a580e9eSGhennadi Procopciuc }
1923a580e9eSGhennadi Procopciuc 
193d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
194d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
195d9373519SGhennadi Procopciuc 			   unsigned int *depth);
196d9373519SGhennadi Procopciuc 
197d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
198d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
199d9373519SGhennadi Procopciuc {
200d9373519SGhennadi Procopciuc 	struct s32cc_osc *osc = s32cc_obj2osc(module);
201d9373519SGhennadi Procopciuc 	int ret;
202d9373519SGhennadi Procopciuc 
203d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
204d9373519SGhennadi Procopciuc 	if (ret != 0) {
205d9373519SGhennadi Procopciuc 		return ret;
206d9373519SGhennadi Procopciuc 	}
207d9373519SGhennadi Procopciuc 
208d9373519SGhennadi Procopciuc 	if ((osc->freq != 0UL) && (rate != osc->freq)) {
209d9373519SGhennadi Procopciuc 		ERROR("Already initialized oscillator. freq = %lu\n",
210d9373519SGhennadi Procopciuc 		      osc->freq);
211d9373519SGhennadi Procopciuc 		return -EINVAL;
212d9373519SGhennadi Procopciuc 	}
213d9373519SGhennadi Procopciuc 
214d9373519SGhennadi Procopciuc 	osc->freq = rate;
215d9373519SGhennadi Procopciuc 	*orate = osc->freq;
216d9373519SGhennadi Procopciuc 
217d9373519SGhennadi Procopciuc 	return 0;
218d9373519SGhennadi Procopciuc }
219d9373519SGhennadi Procopciuc 
220d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
221d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
222d9373519SGhennadi Procopciuc {
223d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
224d9373519SGhennadi Procopciuc 	int ret;
225d9373519SGhennadi Procopciuc 
226d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
227d9373519SGhennadi Procopciuc 	if (ret != 0) {
228d9373519SGhennadi Procopciuc 		return ret;
229d9373519SGhennadi Procopciuc 	}
230d9373519SGhennadi Procopciuc 
231d9373519SGhennadi Procopciuc 	if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
232d9373519SGhennadi Procopciuc 	    ((rate < clk->min_freq) || (rate > clk->max_freq))) {
233d9373519SGhennadi Procopciuc 		ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
234d9373519SGhennadi Procopciuc 		      rate, clk->min_freq, clk->max_freq);
235d9373519SGhennadi Procopciuc 		return -EINVAL;
236d9373519SGhennadi Procopciuc 	}
237d9373519SGhennadi Procopciuc 
238d9373519SGhennadi Procopciuc 	if (clk->module != NULL) {
239d9373519SGhennadi Procopciuc 		return set_module_rate(clk->module, rate, orate, depth);
240d9373519SGhennadi Procopciuc 	}
241d9373519SGhennadi Procopciuc 
242d9373519SGhennadi Procopciuc 	if (clk->pclock != NULL) {
243d9373519SGhennadi Procopciuc 		return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
244d9373519SGhennadi Procopciuc 	}
245d9373519SGhennadi Procopciuc 
246d9373519SGhennadi Procopciuc 	return -EINVAL;
247d9373519SGhennadi Procopciuc }
248d9373519SGhennadi Procopciuc 
2497ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
2507ad4e231SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
2517ad4e231SGhennadi Procopciuc {
2527ad4e231SGhennadi Procopciuc 	struct s32cc_pll *pll = s32cc_obj2pll(module);
2537ad4e231SGhennadi Procopciuc 	int ret;
2547ad4e231SGhennadi Procopciuc 
2557ad4e231SGhennadi Procopciuc 	ret = update_stack_depth(depth);
2567ad4e231SGhennadi Procopciuc 	if (ret != 0) {
2577ad4e231SGhennadi Procopciuc 		return ret;
2587ad4e231SGhennadi Procopciuc 	}
2597ad4e231SGhennadi Procopciuc 
2607ad4e231SGhennadi Procopciuc 	if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) {
2617ad4e231SGhennadi Procopciuc 		ERROR("PLL frequency was already set\n");
2627ad4e231SGhennadi Procopciuc 		return -EINVAL;
2637ad4e231SGhennadi Procopciuc 	}
2647ad4e231SGhennadi Procopciuc 
2657ad4e231SGhennadi Procopciuc 	pll->vco_freq = rate;
2667ad4e231SGhennadi Procopciuc 	*orate = pll->vco_freq;
2677ad4e231SGhennadi Procopciuc 
2687ad4e231SGhennadi Procopciuc 	return 0;
2697ad4e231SGhennadi Procopciuc }
2707ad4e231SGhennadi Procopciuc 
271de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
272de950ef0SGhennadi Procopciuc 			    unsigned long *orate, unsigned int *depth)
273de950ef0SGhennadi Procopciuc {
274de950ef0SGhennadi Procopciuc 	struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
275de950ef0SGhennadi Procopciuc 	const struct s32cc_pll *pll;
276de950ef0SGhennadi Procopciuc 	unsigned long prate, dc;
277de950ef0SGhennadi Procopciuc 	int ret;
278de950ef0SGhennadi Procopciuc 
279de950ef0SGhennadi Procopciuc 	ret = update_stack_depth(depth);
280de950ef0SGhennadi Procopciuc 	if (ret != 0) {
281de950ef0SGhennadi Procopciuc 		return ret;
282de950ef0SGhennadi Procopciuc 	}
283de950ef0SGhennadi Procopciuc 
284de950ef0SGhennadi Procopciuc 	if (pdiv->parent == NULL) {
285de950ef0SGhennadi Procopciuc 		ERROR("Failed to identify PLL divider's parent\n");
286de950ef0SGhennadi Procopciuc 		return -EINVAL;
287de950ef0SGhennadi Procopciuc 	}
288de950ef0SGhennadi Procopciuc 
289de950ef0SGhennadi Procopciuc 	pll = s32cc_obj2pll(pdiv->parent);
290de950ef0SGhennadi Procopciuc 	if (pll == NULL) {
291de950ef0SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
292de950ef0SGhennadi Procopciuc 		return -EINVAL;
293de950ef0SGhennadi Procopciuc 	}
294de950ef0SGhennadi Procopciuc 
295de950ef0SGhennadi Procopciuc 	prate = pll->vco_freq;
296de950ef0SGhennadi Procopciuc 
297de950ef0SGhennadi Procopciuc 	/**
298de950ef0SGhennadi Procopciuc 	 * The PLL is not initialized yet, so let's take a risk
299de950ef0SGhennadi Procopciuc 	 * and accept the proposed rate.
300de950ef0SGhennadi Procopciuc 	 */
301de950ef0SGhennadi Procopciuc 	if (prate == 0UL) {
302de950ef0SGhennadi Procopciuc 		pdiv->freq = rate;
303de950ef0SGhennadi Procopciuc 		*orate = rate;
304de950ef0SGhennadi Procopciuc 		return 0;
305de950ef0SGhennadi Procopciuc 	}
306de950ef0SGhennadi Procopciuc 
307de950ef0SGhennadi Procopciuc 	/* Decline in case the rate cannot fit PLL's requirements. */
308de950ef0SGhennadi Procopciuc 	dc = prate / rate;
309de950ef0SGhennadi Procopciuc 	if ((prate / dc) != rate) {
310de950ef0SGhennadi Procopciuc 		return -EINVAL;
311de950ef0SGhennadi Procopciuc 	}
312de950ef0SGhennadi Procopciuc 
313de950ef0SGhennadi Procopciuc 	pdiv->freq = rate;
314de950ef0SGhennadi Procopciuc 	*orate = pdiv->freq;
315de950ef0SGhennadi Procopciuc 
316de950ef0SGhennadi Procopciuc 	return 0;
317de950ef0SGhennadi Procopciuc }
318de950ef0SGhennadi Procopciuc 
319d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
320d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
321d9373519SGhennadi Procopciuc 			   unsigned int *depth)
322d9373519SGhennadi Procopciuc {
323d9373519SGhennadi Procopciuc 	int ret = 0;
324d9373519SGhennadi Procopciuc 
325d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
326d9373519SGhennadi Procopciuc 	if (ret != 0) {
327d9373519SGhennadi Procopciuc 		return ret;
328d9373519SGhennadi Procopciuc 	}
329d9373519SGhennadi Procopciuc 
330d9373519SGhennadi Procopciuc 	switch (module->type) {
331d9373519SGhennadi Procopciuc 	case s32cc_clk_t:
332d9373519SGhennadi Procopciuc 		ret = set_clk_freq(module, rate, orate, depth);
333d9373519SGhennadi Procopciuc 		break;
334d9373519SGhennadi Procopciuc 	case s32cc_osc_t:
335d9373519SGhennadi Procopciuc 		ret = set_osc_freq(module, rate, orate, depth);
336d9373519SGhennadi Procopciuc 		break;
3377ad4e231SGhennadi Procopciuc 	case s32cc_pll_t:
3387ad4e231SGhennadi Procopciuc 		ret = set_pll_freq(module, rate, orate, depth);
3397ad4e231SGhennadi Procopciuc 		break;
340de950ef0SGhennadi Procopciuc 	case s32cc_pll_out_div_t:
341de950ef0SGhennadi Procopciuc 		ret = set_pll_div_freq(module, rate, orate, depth);
342de950ef0SGhennadi Procopciuc 		break;
343a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
3443fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
345*44e2130aSGhennadi Procopciuc 	case s32cc_fixed_div_t:
346a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
347a8be748aSGhennadi Procopciuc 		break;
348d9373519SGhennadi Procopciuc 	default:
349d9373519SGhennadi Procopciuc 		ret = -EINVAL;
350d9373519SGhennadi Procopciuc 		break;
351d9373519SGhennadi Procopciuc 	}
352d9373519SGhennadi Procopciuc 
353d9373519SGhennadi Procopciuc 	return ret;
354d9373519SGhennadi Procopciuc }
355d9373519SGhennadi Procopciuc 
3563a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
3573a580e9eSGhennadi Procopciuc 			      unsigned long *orate)
3583a580e9eSGhennadi Procopciuc {
359d9373519SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
360d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk;
361d9373519SGhennadi Procopciuc 	int ret;
362d9373519SGhennadi Procopciuc 
363d9373519SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
364d9373519SGhennadi Procopciuc 	if (clk == NULL) {
365d9373519SGhennadi Procopciuc 		return -EINVAL;
366d9373519SGhennadi Procopciuc 	}
367d9373519SGhennadi Procopciuc 
368d9373519SGhennadi Procopciuc 	ret = set_module_rate(&clk->desc, rate, orate, &depth);
369d9373519SGhennadi Procopciuc 	if (ret != 0) {
370d9373519SGhennadi Procopciuc 		ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
371d9373519SGhennadi Procopciuc 		      rate, id);
372d9373519SGhennadi Procopciuc 	}
373d9373519SGhennadi Procopciuc 
374d9373519SGhennadi Procopciuc 	return ret;
3753a580e9eSGhennadi Procopciuc }
3763a580e9eSGhennadi Procopciuc 
3773a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id)
3783a580e9eSGhennadi Procopciuc {
3793a580e9eSGhennadi Procopciuc 	return -ENOTSUP;
3803a580e9eSGhennadi Procopciuc }
3813a580e9eSGhennadi Procopciuc 
3823a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
3833a580e9eSGhennadi Procopciuc {
38412e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *parent;
38512e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *clk;
38612e7a2cdSGhennadi Procopciuc 	bool valid_source = false;
38712e7a2cdSGhennadi Procopciuc 	struct s32cc_clkmux *mux;
38812e7a2cdSGhennadi Procopciuc 	uint8_t i;
38912e7a2cdSGhennadi Procopciuc 
39012e7a2cdSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
39112e7a2cdSGhennadi Procopciuc 	if (clk == NULL) {
39212e7a2cdSGhennadi Procopciuc 		return -EINVAL;
39312e7a2cdSGhennadi Procopciuc 	}
39412e7a2cdSGhennadi Procopciuc 
39512e7a2cdSGhennadi Procopciuc 	parent = s32cc_get_arch_clk(parent_id);
39612e7a2cdSGhennadi Procopciuc 	if (parent == NULL) {
39712e7a2cdSGhennadi Procopciuc 		return -EINVAL;
39812e7a2cdSGhennadi Procopciuc 	}
39912e7a2cdSGhennadi Procopciuc 
40012e7a2cdSGhennadi Procopciuc 	if (!is_s32cc_clk_mux(clk)) {
40112e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a mux\n", id);
40212e7a2cdSGhennadi Procopciuc 		return -EINVAL;
40312e7a2cdSGhennadi Procopciuc 	}
40412e7a2cdSGhennadi Procopciuc 
40512e7a2cdSGhennadi Procopciuc 	mux = s32cc_clk2mux(clk);
40612e7a2cdSGhennadi Procopciuc 	if (mux == NULL) {
40712e7a2cdSGhennadi Procopciuc 		ERROR("Failed to cast clock %lu to clock mux\n", id);
40812e7a2cdSGhennadi Procopciuc 		return -EINVAL;
40912e7a2cdSGhennadi Procopciuc 	}
41012e7a2cdSGhennadi Procopciuc 
41112e7a2cdSGhennadi Procopciuc 	for (i = 0; i < mux->nclks; i++) {
41212e7a2cdSGhennadi Procopciuc 		if (mux->clkids[i] == parent_id) {
41312e7a2cdSGhennadi Procopciuc 			valid_source = true;
41412e7a2cdSGhennadi Procopciuc 			break;
41512e7a2cdSGhennadi Procopciuc 		}
41612e7a2cdSGhennadi Procopciuc 	}
41712e7a2cdSGhennadi Procopciuc 
41812e7a2cdSGhennadi Procopciuc 	if (!valid_source) {
41912e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a valid clock for mux %lu\n",
42012e7a2cdSGhennadi Procopciuc 		      parent_id, id);
42112e7a2cdSGhennadi Procopciuc 		return -EINVAL;
42212e7a2cdSGhennadi Procopciuc 	}
42312e7a2cdSGhennadi Procopciuc 
42412e7a2cdSGhennadi Procopciuc 	mux->source_id = parent_id;
42512e7a2cdSGhennadi Procopciuc 
42612e7a2cdSGhennadi Procopciuc 	return 0;
4273a580e9eSGhennadi Procopciuc }
4283a580e9eSGhennadi Procopciuc 
4293a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void)
4303a580e9eSGhennadi Procopciuc {
4313a580e9eSGhennadi Procopciuc 	static const struct clk_ops s32cc_clk_ops = {
4323a580e9eSGhennadi Procopciuc 		.enable		= s32cc_clk_enable,
4333a580e9eSGhennadi Procopciuc 		.disable	= s32cc_clk_disable,
4343a580e9eSGhennadi Procopciuc 		.is_enabled	= s32cc_clk_is_enabled,
4353a580e9eSGhennadi Procopciuc 		.get_rate	= s32cc_clk_get_rate,
4363a580e9eSGhennadi Procopciuc 		.set_rate	= s32cc_clk_set_rate,
4373a580e9eSGhennadi Procopciuc 		.get_parent	= s32cc_clk_get_parent,
4383a580e9eSGhennadi Procopciuc 		.set_parent	= s32cc_clk_set_parent,
4393a580e9eSGhennadi Procopciuc 	};
4403a580e9eSGhennadi Procopciuc 
4413a580e9eSGhennadi Procopciuc 	clk_register(&s32cc_clk_ops);
4423a580e9eSGhennadi Procopciuc }
4433a580e9eSGhennadi Procopciuc 
444