xref: /rk3399_ARM-atf/drivers/nxp/clk/s32cc/s32cc_clk_drv.c (revision 7ad4e2312f58606ee74ac7c655a655bd85148582)
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:
155a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
156a8be748aSGhennadi Procopciuc 		break;
1578ab34357SGhennadi Procopciuc 	default:
1588ab34357SGhennadi Procopciuc 		ret = -EINVAL;
1598ab34357SGhennadi Procopciuc 		break;
1608ab34357SGhennadi Procopciuc 	}
1618ab34357SGhennadi Procopciuc 
1628ab34357SGhennadi Procopciuc 	return ret;
1638ab34357SGhennadi Procopciuc }
1648ab34357SGhennadi Procopciuc 
1653a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id)
1663a580e9eSGhennadi Procopciuc {
1678ab34357SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
1688ab34357SGhennadi Procopciuc 	const struct s32cc_clk *clk;
1698ab34357SGhennadi Procopciuc 
1708ab34357SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
1718ab34357SGhennadi Procopciuc 	if (clk == NULL) {
1728ab34357SGhennadi Procopciuc 		return -EINVAL;
1738ab34357SGhennadi Procopciuc 	}
1748ab34357SGhennadi Procopciuc 
1758ab34357SGhennadi Procopciuc 	return enable_module(&clk->desc, &depth);
1763a580e9eSGhennadi Procopciuc }
1773a580e9eSGhennadi Procopciuc 
1783a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id)
1793a580e9eSGhennadi Procopciuc {
1803a580e9eSGhennadi Procopciuc }
1813a580e9eSGhennadi Procopciuc 
1823a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id)
1833a580e9eSGhennadi Procopciuc {
1843a580e9eSGhennadi Procopciuc 	return false;
1853a580e9eSGhennadi Procopciuc }
1863a580e9eSGhennadi Procopciuc 
1873a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id)
1883a580e9eSGhennadi Procopciuc {
1893a580e9eSGhennadi Procopciuc 	return 0;
1903a580e9eSGhennadi Procopciuc }
1913a580e9eSGhennadi Procopciuc 
192d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
193d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
194d9373519SGhennadi Procopciuc 			   unsigned int *depth);
195d9373519SGhennadi Procopciuc 
196d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
197d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
198d9373519SGhennadi Procopciuc {
199d9373519SGhennadi Procopciuc 	struct s32cc_osc *osc = s32cc_obj2osc(module);
200d9373519SGhennadi Procopciuc 	int ret;
201d9373519SGhennadi Procopciuc 
202d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
203d9373519SGhennadi Procopciuc 	if (ret != 0) {
204d9373519SGhennadi Procopciuc 		return ret;
205d9373519SGhennadi Procopciuc 	}
206d9373519SGhennadi Procopciuc 
207d9373519SGhennadi Procopciuc 	if ((osc->freq != 0UL) && (rate != osc->freq)) {
208d9373519SGhennadi Procopciuc 		ERROR("Already initialized oscillator. freq = %lu\n",
209d9373519SGhennadi Procopciuc 		      osc->freq);
210d9373519SGhennadi Procopciuc 		return -EINVAL;
211d9373519SGhennadi Procopciuc 	}
212d9373519SGhennadi Procopciuc 
213d9373519SGhennadi Procopciuc 	osc->freq = rate;
214d9373519SGhennadi Procopciuc 	*orate = osc->freq;
215d9373519SGhennadi Procopciuc 
216d9373519SGhennadi Procopciuc 	return 0;
217d9373519SGhennadi Procopciuc }
218d9373519SGhennadi Procopciuc 
219d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
220d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
221d9373519SGhennadi Procopciuc {
222d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
223d9373519SGhennadi Procopciuc 	int ret;
224d9373519SGhennadi Procopciuc 
225d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
226d9373519SGhennadi Procopciuc 	if (ret != 0) {
227d9373519SGhennadi Procopciuc 		return ret;
228d9373519SGhennadi Procopciuc 	}
229d9373519SGhennadi Procopciuc 
230d9373519SGhennadi Procopciuc 	if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
231d9373519SGhennadi Procopciuc 	    ((rate < clk->min_freq) || (rate > clk->max_freq))) {
232d9373519SGhennadi Procopciuc 		ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
233d9373519SGhennadi Procopciuc 		      rate, clk->min_freq, clk->max_freq);
234d9373519SGhennadi Procopciuc 		return -EINVAL;
235d9373519SGhennadi Procopciuc 	}
236d9373519SGhennadi Procopciuc 
237d9373519SGhennadi Procopciuc 	if (clk->module != NULL) {
238d9373519SGhennadi Procopciuc 		return set_module_rate(clk->module, rate, orate, depth);
239d9373519SGhennadi Procopciuc 	}
240d9373519SGhennadi Procopciuc 
241d9373519SGhennadi Procopciuc 	if (clk->pclock != NULL) {
242d9373519SGhennadi Procopciuc 		return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
243d9373519SGhennadi Procopciuc 	}
244d9373519SGhennadi Procopciuc 
245d9373519SGhennadi Procopciuc 	return -EINVAL;
246d9373519SGhennadi Procopciuc }
247d9373519SGhennadi Procopciuc 
248*7ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
249*7ad4e231SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
250*7ad4e231SGhennadi Procopciuc {
251*7ad4e231SGhennadi Procopciuc 	struct s32cc_pll *pll = s32cc_obj2pll(module);
252*7ad4e231SGhennadi Procopciuc 	int ret;
253*7ad4e231SGhennadi Procopciuc 
254*7ad4e231SGhennadi Procopciuc 	ret = update_stack_depth(depth);
255*7ad4e231SGhennadi Procopciuc 	if (ret != 0) {
256*7ad4e231SGhennadi Procopciuc 		return ret;
257*7ad4e231SGhennadi Procopciuc 	}
258*7ad4e231SGhennadi Procopciuc 
259*7ad4e231SGhennadi Procopciuc 	if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) {
260*7ad4e231SGhennadi Procopciuc 		ERROR("PLL frequency was already set\n");
261*7ad4e231SGhennadi Procopciuc 		return -EINVAL;
262*7ad4e231SGhennadi Procopciuc 	}
263*7ad4e231SGhennadi Procopciuc 
264*7ad4e231SGhennadi Procopciuc 	pll->vco_freq = rate;
265*7ad4e231SGhennadi Procopciuc 	*orate = pll->vco_freq;
266*7ad4e231SGhennadi Procopciuc 
267*7ad4e231SGhennadi Procopciuc 	return 0;
268*7ad4e231SGhennadi Procopciuc }
269*7ad4e231SGhennadi Procopciuc 
270d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
271d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
272d9373519SGhennadi Procopciuc 			   unsigned int *depth)
273d9373519SGhennadi Procopciuc {
274d9373519SGhennadi Procopciuc 	int ret = 0;
275d9373519SGhennadi Procopciuc 
276d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
277d9373519SGhennadi Procopciuc 	if (ret != 0) {
278d9373519SGhennadi Procopciuc 		return ret;
279d9373519SGhennadi Procopciuc 	}
280d9373519SGhennadi Procopciuc 
281d9373519SGhennadi Procopciuc 	switch (module->type) {
282d9373519SGhennadi Procopciuc 	case s32cc_clk_t:
283d9373519SGhennadi Procopciuc 		ret = set_clk_freq(module, rate, orate, depth);
284d9373519SGhennadi Procopciuc 		break;
285d9373519SGhennadi Procopciuc 	case s32cc_osc_t:
286d9373519SGhennadi Procopciuc 		ret = set_osc_freq(module, rate, orate, depth);
287d9373519SGhennadi Procopciuc 		break;
288*7ad4e231SGhennadi Procopciuc 	case s32cc_pll_t:
289*7ad4e231SGhennadi Procopciuc 		ret = set_pll_freq(module, rate, orate, depth);
290*7ad4e231SGhennadi Procopciuc 		break;
291a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
2923fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
293a8be748aSGhennadi Procopciuc 	case s32cc_pll_out_div_t:
294a8be748aSGhennadi Procopciuc 		ret = -ENOTSUP;
295a8be748aSGhennadi Procopciuc 		break;
296d9373519SGhennadi Procopciuc 	default:
297d9373519SGhennadi Procopciuc 		ret = -EINVAL;
298d9373519SGhennadi Procopciuc 		break;
299d9373519SGhennadi Procopciuc 	}
300d9373519SGhennadi Procopciuc 
301d9373519SGhennadi Procopciuc 	return ret;
302d9373519SGhennadi Procopciuc }
303d9373519SGhennadi Procopciuc 
3043a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
3053a580e9eSGhennadi Procopciuc 			      unsigned long *orate)
3063a580e9eSGhennadi Procopciuc {
307d9373519SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
308d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk;
309d9373519SGhennadi Procopciuc 	int ret;
310d9373519SGhennadi Procopciuc 
311d9373519SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
312d9373519SGhennadi Procopciuc 	if (clk == NULL) {
313d9373519SGhennadi Procopciuc 		return -EINVAL;
314d9373519SGhennadi Procopciuc 	}
315d9373519SGhennadi Procopciuc 
316d9373519SGhennadi Procopciuc 	ret = set_module_rate(&clk->desc, rate, orate, &depth);
317d9373519SGhennadi Procopciuc 	if (ret != 0) {
318d9373519SGhennadi Procopciuc 		ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
319d9373519SGhennadi Procopciuc 		      rate, id);
320d9373519SGhennadi Procopciuc 	}
321d9373519SGhennadi Procopciuc 
322d9373519SGhennadi Procopciuc 	return ret;
3233a580e9eSGhennadi Procopciuc }
3243a580e9eSGhennadi Procopciuc 
3253a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id)
3263a580e9eSGhennadi Procopciuc {
3273a580e9eSGhennadi Procopciuc 	return -ENOTSUP;
3283a580e9eSGhennadi Procopciuc }
3293a580e9eSGhennadi Procopciuc 
3303a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
3313a580e9eSGhennadi Procopciuc {
33212e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *parent;
33312e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *clk;
33412e7a2cdSGhennadi Procopciuc 	bool valid_source = false;
33512e7a2cdSGhennadi Procopciuc 	struct s32cc_clkmux *mux;
33612e7a2cdSGhennadi Procopciuc 	uint8_t i;
33712e7a2cdSGhennadi Procopciuc 
33812e7a2cdSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
33912e7a2cdSGhennadi Procopciuc 	if (clk == NULL) {
34012e7a2cdSGhennadi Procopciuc 		return -EINVAL;
34112e7a2cdSGhennadi Procopciuc 	}
34212e7a2cdSGhennadi Procopciuc 
34312e7a2cdSGhennadi Procopciuc 	parent = s32cc_get_arch_clk(parent_id);
34412e7a2cdSGhennadi Procopciuc 	if (parent == NULL) {
34512e7a2cdSGhennadi Procopciuc 		return -EINVAL;
34612e7a2cdSGhennadi Procopciuc 	}
34712e7a2cdSGhennadi Procopciuc 
34812e7a2cdSGhennadi Procopciuc 	if (!is_s32cc_clk_mux(clk)) {
34912e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a mux\n", id);
35012e7a2cdSGhennadi Procopciuc 		return -EINVAL;
35112e7a2cdSGhennadi Procopciuc 	}
35212e7a2cdSGhennadi Procopciuc 
35312e7a2cdSGhennadi Procopciuc 	mux = s32cc_clk2mux(clk);
35412e7a2cdSGhennadi Procopciuc 	if (mux == NULL) {
35512e7a2cdSGhennadi Procopciuc 		ERROR("Failed to cast clock %lu to clock mux\n", id);
35612e7a2cdSGhennadi Procopciuc 		return -EINVAL;
35712e7a2cdSGhennadi Procopciuc 	}
35812e7a2cdSGhennadi Procopciuc 
35912e7a2cdSGhennadi Procopciuc 	for (i = 0; i < mux->nclks; i++) {
36012e7a2cdSGhennadi Procopciuc 		if (mux->clkids[i] == parent_id) {
36112e7a2cdSGhennadi Procopciuc 			valid_source = true;
36212e7a2cdSGhennadi Procopciuc 			break;
36312e7a2cdSGhennadi Procopciuc 		}
36412e7a2cdSGhennadi Procopciuc 	}
36512e7a2cdSGhennadi Procopciuc 
36612e7a2cdSGhennadi Procopciuc 	if (!valid_source) {
36712e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a valid clock for mux %lu\n",
36812e7a2cdSGhennadi Procopciuc 		      parent_id, id);
36912e7a2cdSGhennadi Procopciuc 		return -EINVAL;
37012e7a2cdSGhennadi Procopciuc 	}
37112e7a2cdSGhennadi Procopciuc 
37212e7a2cdSGhennadi Procopciuc 	mux->source_id = parent_id;
37312e7a2cdSGhennadi Procopciuc 
37412e7a2cdSGhennadi Procopciuc 	return 0;
3753a580e9eSGhennadi Procopciuc }
3763a580e9eSGhennadi Procopciuc 
3773a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void)
3783a580e9eSGhennadi Procopciuc {
3793a580e9eSGhennadi Procopciuc 	static const struct clk_ops s32cc_clk_ops = {
3803a580e9eSGhennadi Procopciuc 		.enable		= s32cc_clk_enable,
3813a580e9eSGhennadi Procopciuc 		.disable	= s32cc_clk_disable,
3823a580e9eSGhennadi Procopciuc 		.is_enabled	= s32cc_clk_is_enabled,
3833a580e9eSGhennadi Procopciuc 		.get_rate	= s32cc_clk_get_rate,
3843a580e9eSGhennadi Procopciuc 		.set_rate	= s32cc_clk_set_rate,
3853a580e9eSGhennadi Procopciuc 		.get_parent	= s32cc_clk_get_parent,
3863a580e9eSGhennadi Procopciuc 		.set_parent	= s32cc_clk_set_parent,
3873a580e9eSGhennadi Procopciuc 	};
3883a580e9eSGhennadi Procopciuc 
3893a580e9eSGhennadi Procopciuc 	clk_register(&s32cc_clk_ops);
3903a580e9eSGhennadi Procopciuc }
3913a580e9eSGhennadi Procopciuc 
392