xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3308.c (revision e7b5bb3cc9527752c2c01acb4325fc0721fb75aa)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 #include <common.h>
7 #include <bitfield.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <div64.h>
11 #include <errno.h>
12 #include <syscon.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk3308.h>
15 #include <asm/arch/hardware.h>
16 #include <asm/io.h>
17 #include <dm/lists.h>
18 #include <dt-bindings/clock/rk3308-cru.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 enum {
23 	VCO_MAX_HZ	= 3200U * 1000000,
24 	VCO_MIN_HZ	= 800 * 1000000,
25 	OUTPUT_MAX_HZ	= 3200U * 1000000,
26 	OUTPUT_MIN_HZ	= 24 * 1000000,
27 };
28 
29 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
30 
31 #define RK3308_CLK_DUMP(_id, _name)		\
32 {						\
33 	.id = _id,				\
34 	.name = _name,				\
35 }
36 
37 #define RK3308_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
38 			_postdiv2, _dsmpd, _frac)		\
39 {								\
40 	.rate	= _rate##U,					\
41 	.fbdiv = _fbdiv,					\
42 	.postdiv1 = _postdiv1,					\
43 	.refdiv = _refdiv,					\
44 	.postdiv2 = _postdiv2,					\
45 	.dsmpd = _dsmpd,					\
46 	.frac = _frac,						\
47 }
48 
49 static struct pll_rate_table rk3308_pll_rates[] = {
50 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
51 	RK3308_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
52 	RK3308_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
53 	RK3308_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
54 	RK3308_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
55 };
56 
57 static u8 pll_mode_shift[PLL_COUNT] = {
58 	APLL_MODE_SHIFT, DPLL_MODE_SHIFT, VPLL0_MODE_SHIFT,
59 	VPLL1_MODE_SHIFT
60 };
61 
62 static u32 pll_mode_mask[PLL_COUNT] = {
63 	APLL_MODE_MASK, DPLL_MODE_MASK, VPLL0_MODE_MASK,
64 	VPLL1_MODE_MASK
65 };
66 
67 static const struct rk3308_clk_info clks_dump[] = {
68 	RK3308_CLK_DUMP(PLL_APLL, "apll"),
69 	RK3308_CLK_DUMP(PLL_DPLL, "dpll"),
70 	RK3308_CLK_DUMP(PLL_VPLL0, "vpll0"),
71 	RK3308_CLK_DUMP(PLL_VPLL1, "vpll1"),
72 	RK3308_CLK_DUMP(ACLK_BUS, "aclk_bus"),
73 	RK3308_CLK_DUMP(HCLK_BUS, "hclk_bus"),
74 	RK3308_CLK_DUMP(PCLK_BUS, "pclk_bus"),
75 	RK3308_CLK_DUMP(ACLK_PERI, "aclk_peri"),
76 	RK3308_CLK_DUMP(HCLK_PERI, "hclk_peri"),
77 	RK3308_CLK_DUMP(PCLK_PERI, "pclk_peri"),
78 	RK3308_CLK_DUMP(HCLK_AUDIO, "hclk_audio"),
79 	RK3308_CLK_DUMP(PCLK_AUDIO, "pclk_audio"),
80 };
81 
82 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
83 				ulong hz);
84 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
85 				 ulong hz);
86 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv,
87 				  ulong clk_id, ulong hz);
88 
89 static const struct pll_rate_table *get_pll_settings(unsigned long rate)
90 {
91 	unsigned int rate_count = ARRAY_SIZE(rk3308_pll_rates);
92 	int i;
93 
94 	for (i = 0; i < rate_count; i++) {
95 		if (rate == rk3308_pll_rates[i].rate)
96 			return &rk3308_pll_rates[i];
97 	}
98 
99 	return NULL;
100 }
101 
102 /*
103  * How to calculate the PLL:
104  * Formulas also embedded within the Fractional PLL Verilog model:
105  * If DSMPD = 1 (DSM is disabled, "integer mode")
106  * FOUTVCO = FREF / REFDIV * FBDIV
107  * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
108  * Where:
109  * FOUTVCO = Fractional PLL non-divided output frequency
110  * FOUTPOSTDIV = Fractional PLL divided output frequency
111  *               (output of second post divider)
112  * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
113  * REFDIV = Fractional PLL input reference clock divider
114  * FBDIV = Integer value programmed into feedback divide
115  *
116  */
117 
118 static int rkclk_set_pll(struct rk3308_clk_priv *priv,
119 			 enum rk3308_pll_id pll_id,
120 			 unsigned long drate)
121 {
122 	struct rk3308_cru *cru = priv->cru;
123 	struct rk3308_pll *pll;
124 	unsigned int *mode;
125 	const struct pll_rate_table *rate;
126 	uint vco_hz, output_hz;
127 
128 	rate = get_pll_settings(drate);
129 	if (!rate) {
130 		printf("%s unsupport rate\n", __func__);
131 		return -EINVAL;
132 	}
133 
134 	/* All PLLs have same VCO and output frequency range restrictions. */
135 	vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000;
136 	output_hz = vco_hz / rate->postdiv1 / rate->postdiv2;
137 
138 	pll = &cru->pll[pll_id];
139 	mode = &cru->mode;
140 
141 	debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
142 	      pll, rate->fbdiv, rate->refdiv, rate->postdiv1,
143 	      rate->postdiv2, vco_hz, output_hz);
144 	assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
145 	       output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
146 
147 	/*
148 	 * When power on or changing PLL setting,
149 	 * we must force PLL into slow mode to ensure output stable clock.
150 	 */
151 	rk_clrsetreg(mode, pll_mode_mask[pll_id],
152 		     PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]);
153 
154 	/* use integer mode */
155 	rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
156 	/* Power down */
157 	rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT);
158 
159 	rk_clrsetreg(&pll->con0,
160 		     PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
161 		     (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv);
162 	rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
163 		     (rate->postdiv2 << PLL_POSTDIV2_SHIFT |
164 		     rate->refdiv << PLL_REFDIV_SHIFT));
165 
166 	/* Power Up */
167 	rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
168 
169 	/* waiting for pll lock */
170 	while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)))
171 		udelay(1);
172 
173 	rk_clrsetreg(mode, pll_mode_mask[pll_id],
174 		     PLLMUX_FROM_PLL << pll_mode_shift[pll_id]);
175 
176 	return 0;
177 }
178 
179 static uint32_t rkclk_pll_get_rate(struct rk3308_clk_priv *priv,
180 				   enum rk3308_pll_id pll_id)
181 {
182 	struct rk3308_cru *cru = priv->cru;
183 	struct rk3308_pll *pll;
184 	u32 con, refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac;
185 	u32 rate = 0;
186 	u64 frac_rate64 = 0;
187 	uint shift;
188 	uint mask;
189 
190 	pll = &cru->pll[pll_id];
191 	con = readl(&cru->mode);
192 
193 	shift = pll_mode_shift[pll_id];
194 	mask = pll_mode_mask[pll_id];
195 
196 	switch ((con & mask) >> shift) {
197 	case PLLMUX_FROM_XIN24M:
198 		return OSC_HZ;
199 	case PLLMUX_FROM_PLL:
200 		/* normal mode */
201 		con = readl(&pll->con0);
202 		postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
203 		fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
204 		con = readl(&pll->con1);
205 		postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
206 		refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
207 		dsmpd = (con & PLL_DSMPD_MASK) >> PLL_DSMPD_SHIFT;
208 		con = readl(&pll->con2);
209 		frac = con & PLL_FRAC_DIV;
210 		rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
211 		if (dsmpd == 0) {
212 			/* fractional mode */
213 			frac_rate64 = 24000000 * (u64)frac;
214 			do_div(frac_rate64, refdiv);
215 			frac_rate64 >>= 24;
216 			do_div(frac_rate64, postdiv1);
217 			do_div(frac_rate64, postdiv2);
218 			rate += (uint32_t)frac_rate64;
219 		}
220 		return rate;
221 	case PLLMUX_FROM_RTC32K:
222 	default:
223 		return 32768;
224 	}
225 }
226 
227 static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
228 {
229 	if (!priv->dpll_hz)
230 		priv->dpll_hz = rkclk_pll_get_rate(priv, DPLL);
231 	if (!priv->vpll0_hz)
232 		priv->vpll0_hz = rkclk_pll_get_rate(priv, VPLL0);
233 	if (!priv->vpll1_hz)
234 		priv->vpll1_hz = rkclk_pll_get_rate(priv, VPLL1);
235 }
236 
237 static void rkclk_init(struct udevice *dev)
238 {
239 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
240 	struct rk3308_cru *cru = priv->cru;
241 	u32 aclk_div, pclk_div;
242 
243 	/* init pll */
244 	if (rkclk_set_pll(priv, APLL, APLL_HZ))
245 		printf("%s set apll unsuccessfully\n", __func__);
246 
247 	/*
248 	 * select apll as cpu/core clock pll source and
249 	 * set up dependent divisors for PCLK and ACLK clocks.
250 	 * core hz : apll = 1:1
251 	 */
252 	priv->apll_hz = rkclk_pll_get_rate(priv, APLL);
253 	aclk_div = priv->apll_hz / CORE_ACLK_HZ - 1;
254 	pclk_div = priv->apll_hz / CORE_DBG_HZ - 1;
255 	rk_clrsetreg(&cru->clksel_con[0],
256 		     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK |
257 		     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
258 		     aclk_div << CORE_ACLK_DIV_SHIFT |
259 		     pclk_div << CORE_DBG_DIV_SHIFT |
260 		     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
261 		     0 << CORE_DIV_CON_SHIFT);
262 
263 #ifndef CONFIG_USING_KERNEL_DTB
264 	rk3308_clk_get_pll_rate(priv);
265 
266 	rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
267 	rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
268 	rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
269 
270 	rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
271 	rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
272 	rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
273 
274 	rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
275 	rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
276 #endif
277 }
278 
279 static ulong rk3308_i2c_get_clk(struct clk *clk)
280 {
281 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
282 	struct rk3308_cru *cru = priv->cru;
283 	u32 div, con, con_id;
284 
285 	switch (clk->id) {
286 	case SCLK_I2C0:
287 		con_id = 25;
288 		break;
289 	case SCLK_I2C1:
290 		con_id = 26;
291 		break;
292 	case SCLK_I2C2:
293 		con_id = 27;
294 		break;
295 	case SCLK_I2C3:
296 		con_id = 28;
297 		break;
298 	default:
299 		printf("do not support this i2c bus\n");
300 		return -EINVAL;
301 	}
302 
303 	con = readl(&cru->clksel_con[con_id]);
304 	div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
305 
306 	return DIV_TO_RATE(priv->dpll_hz, div);
307 }
308 
309 static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
310 {
311 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
312 	struct rk3308_cru *cru = priv->cru;
313 	u32 src_clk_div, con_id;
314 
315 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
316 	assert(src_clk_div - 1 < 127);
317 
318 	switch (clk->id) {
319 	case SCLK_I2C0:
320 		con_id = 25;
321 		break;
322 	case SCLK_I2C1:
323 		con_id = 26;
324 		break;
325 	case SCLK_I2C2:
326 		con_id = 27;
327 		break;
328 	case SCLK_I2C3:
329 		con_id = 28;
330 		break;
331 	default:
332 		printf("do not support this i2c bus\n");
333 		return -EINVAL;
334 	}
335 	rk_clrsetreg(&cru->clksel_con[con_id],
336 		     CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
337 		     CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
338 		     (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
339 
340 	return rk3308_i2c_get_clk(clk);
341 }
342 
343 static ulong rk3308_mmc_get_clk(struct clk *clk)
344 {
345 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
346 	struct rk3308_cru *cru = priv->cru;
347 	u32 div, con, con_id;
348 
349 	switch (clk->id) {
350 	case HCLK_SDMMC:
351 	case SCLK_SDMMC:
352 		con_id = 39;
353 		break;
354 	case HCLK_EMMC:
355 	case SCLK_EMMC:
356 	case SCLK_EMMC_SAMPLE:
357 		con_id = 41;
358 		break;
359 	default:
360 		return -EINVAL;
361 	}
362 
363 	con = readl(&cru->clksel_con[con_id]);
364 	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
365 
366 	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
367 	    == EMMC_SEL_24M)
368 		return DIV_TO_RATE(OSC_HZ, div) / 2;
369 	else
370 		return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
371 }
372 
373 static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
374 {
375 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
376 	struct rk3308_cru *cru = priv->cru;
377 	int src_clk_div;
378 	u32 con_id;
379 
380 	debug("%s %ld %ld\n", __func__, clk->id, set_rate);
381 
382 	switch (clk->id) {
383 	case HCLK_SDMMC:
384 	case SCLK_SDMMC:
385 		con_id = 39;
386 		break;
387 	case HCLK_EMMC:
388 	case SCLK_EMMC:
389 		con_id = 41;
390 		break;
391 	default:
392 		return -EINVAL;
393 	}
394 	/* Select clk_sdmmc/emmc source from VPLL0 by default */
395 	/* mmc clock defaulg div 2 internal, need provide double in cru */
396 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
397 
398 	if (src_clk_div > 127) {
399 		/* use 24MHz source for 400KHz clock */
400 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
401 		rk_clrsetreg(&cru->clksel_con[con_id],
402 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
403 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
404 			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
405 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
406 	} else {
407 		rk_clrsetreg(&cru->clksel_con[con_id],
408 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
409 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
410 			     EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
411 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
412 	}
413 
414 	return rk3308_mmc_get_clk(clk);
415 }
416 
417 static ulong rk3308_saradc_get_clk(struct clk *clk)
418 {
419 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
420 	struct rk3308_cru *cru = priv->cru;
421 	u32 div, con;
422 
423 	con = readl(&cru->clksel_con[34]);
424 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
425 
426 	return DIV_TO_RATE(OSC_HZ, div);
427 }
428 
429 static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
430 {
431 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
432 	struct rk3308_cru *cru = priv->cru;
433 	int src_clk_div;
434 
435 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
436 	assert(src_clk_div - 1 < 2047);
437 
438 	rk_clrsetreg(&cru->clksel_con[34],
439 		     CLK_SARADC_DIV_CON_MASK,
440 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
441 
442 	return rk3308_saradc_get_clk(clk);
443 }
444 
445 static ulong rk3308_spi_get_clk(struct clk *clk)
446 {
447 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
448 	struct rk3308_cru *cru = priv->cru;
449 	u32 div, con, con_id;
450 
451 	switch (clk->id) {
452 	case SCLK_SPI0:
453 		con_id = 30;
454 		break;
455 	case SCLK_SPI1:
456 		con_id = 31;
457 		break;
458 	case SCLK_SPI2:
459 		con_id = 32;
460 		break;
461 	default:
462 		printf("do not support this spi bus\n");
463 		return -EINVAL;
464 	}
465 
466 	con = readl(&cru->clksel_con[con_id]);
467 	div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
468 
469 	return DIV_TO_RATE(priv->dpll_hz, div);
470 }
471 
472 static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
473 {
474 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
475 	struct rk3308_cru *cru = priv->cru;
476 	u32 src_clk_div, con_id;
477 
478 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
479 	assert(src_clk_div - 1 < 127);
480 
481 	switch (clk->id) {
482 	case SCLK_SPI0:
483 		con_id = 30;
484 		break;
485 	case SCLK_SPI1:
486 		con_id = 31;
487 		break;
488 	case SCLK_SPI2:
489 		con_id = 32;
490 		break;
491 	default:
492 		printf("do not support this spi bus\n");
493 		return -EINVAL;
494 	}
495 
496 	rk_clrsetreg(&cru->clksel_con[con_id],
497 		     CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
498 		     CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
499 		     (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
500 
501 	return rk3308_spi_get_clk(clk);
502 }
503 
504 static ulong rk3308_pwm_get_clk(struct clk *clk)
505 {
506 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
507 	struct rk3308_cru *cru = priv->cru;
508 	u32 div, con;
509 
510 	con = readl(&cru->clksel_con[29]);
511 	div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
512 
513 	return DIV_TO_RATE(priv->dpll_hz, div);
514 }
515 
516 static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
517 {
518 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
519 	struct rk3308_cru *cru = priv->cru;
520 	int src_clk_div;
521 
522 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
523 	assert(src_clk_div - 1 < 127);
524 
525 	rk_clrsetreg(&cru->clksel_con[29],
526 		     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
527 		     CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
528 		     (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
529 
530 	return rk3308_pwm_get_clk(clk);
531 }
532 
533 static ulong rk3308_vop_get_clk(struct clk *clk)
534 {
535 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
536 	struct rk3308_cru *cru = priv->cru;
537 	u32 div, pll_sel, vol_sel, con, parent;
538 
539 	con = readl(&cru->clksel_con[8]);
540 	vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
541 	pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
542 	div = con & DCLK_VOP_DIV_MASK;
543 
544 	if (vol_sel == DCLK_VOP_SEL_24M) {
545 		parent = OSC_HZ;
546 	} else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
547 		switch (pll_sel) {
548 		case DCLK_VOP_PLL_SEL_DPLL:
549 			parent = priv->dpll_hz;
550 			break;
551 		case DCLK_VOP_PLL_SEL_VPLL0:
552 			parent = priv->vpll0_hz;
553 			break;
554 		case DCLK_VOP_PLL_SEL_VPLL1:
555 			parent = priv->vpll0_hz;
556 			break;
557 		default:
558 			printf("do not support this vop pll sel\n");
559 			return -EINVAL;
560 		}
561 	} else {
562 		printf("do not support this vop sel\n");
563 		return -EINVAL;
564 	}
565 
566 	return DIV_TO_RATE(parent, div);
567 }
568 
569 static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
570 {
571 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
572 	struct rk3308_cru *cru = priv->cru;
573 	ulong pll_rate, now, best_rate = 0;
574 	u32 i, div, best_div = 0, best_sel = 0;
575 
576 	for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
577 		switch (i) {
578 		case DCLK_VOP_PLL_SEL_DPLL:
579 			pll_rate = priv->dpll_hz;
580 			break;
581 		case DCLK_VOP_PLL_SEL_VPLL0:
582 			pll_rate = priv->vpll0_hz;
583 			break;
584 		case DCLK_VOP_PLL_SEL_VPLL1:
585 			pll_rate = priv->vpll1_hz;
586 			break;
587 		default:
588 			printf("do not support this vop pll sel\n");
589 			return -EINVAL;
590 		}
591 
592 		div = DIV_ROUND_UP(pll_rate, hz);
593 		if (div > 255)
594 			continue;
595 		now = pll_rate / div;
596 		if (abs(hz - now) < abs(hz - best_rate)) {
597 			best_rate = now;
598 			best_div = div;
599 			best_sel = i;
600 		}
601 		debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
602 		      pll_rate, best_rate, best_div, best_sel);
603 	}
604 
605 	if (best_rate != hz && hz == OSC_HZ) {
606 		rk_clrsetreg(&cru->clksel_con[8],
607 			     DCLK_VOP_SEL_MASK,
608 			     DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
609 	} else if (best_rate) {
610 		rk_clrsetreg(&cru->clksel_con[8],
611 			     DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
612 			     DCLK_VOP_DIV_MASK,
613 			     DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
614 			     best_sel << DCLK_VOP_PLL_SEL_SHIFT |
615 			     (best_div - 1) << DCLK_VOP_DIV_SHIFT);
616 	} else {
617 		printf("do not support this vop freq\n");
618 		return -EINVAL;
619 	}
620 
621 	return rk3308_vop_get_clk(clk);
622 }
623 
624 static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
625 {
626 	struct rk3308_cru *cru = priv->cru;
627 	u32 div, con, parent = priv->dpll_hz;
628 
629 	switch (clk_id) {
630 	case ACLK_BUS:
631 		con = readl(&cru->clksel_con[5]);
632 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
633 		break;
634 	case HCLK_BUS:
635 		con = readl(&cru->clksel_con[6]);
636 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
637 		break;
638 	case PCLK_BUS:
639 		con = readl(&cru->clksel_con[6]);
640 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
641 		break;
642 	default:
643 		return -ENOENT;
644 	}
645 
646 	return DIV_TO_RATE(parent, div);
647 }
648 
649 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
650 				ulong hz)
651 {
652 	struct rk3308_cru *cru = priv->cru;
653 	int src_clk_div;
654 
655 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
656 	assert(src_clk_div - 1 < 31);
657 
658 	/*
659 	 * select dpll as pd_bus bus clock source and
660 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
661 	 */
662 	switch (clk_id) {
663 	case ACLK_BUS:
664 		rk_clrsetreg(&cru->clksel_con[5],
665 			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
666 			     BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
667 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
668 		break;
669 	case HCLK_BUS:
670 		rk_clrsetreg(&cru->clksel_con[6],
671 			     BUS_HCLK_DIV_MASK,
672 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
673 		break;
674 	case PCLK_BUS:
675 		rk_clrsetreg(&cru->clksel_con[6],
676 			     BUS_PCLK_DIV_MASK,
677 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
678 		break;
679 	default:
680 		printf("do not support this bus freq\n");
681 		return -EINVAL;
682 	}
683 
684 	return rk3308_bus_get_clk(priv, clk_id);
685 }
686 
687 static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
688 {
689 	struct rk3308_cru *cru = priv->cru;
690 	u32 div, con, parent = priv->dpll_hz;
691 
692 	switch (clk_id) {
693 	case ACLK_PERI:
694 		con = readl(&cru->clksel_con[36]);
695 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
696 		break;
697 	case HCLK_PERI:
698 		con = readl(&cru->clksel_con[37]);
699 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
700 		break;
701 	case PCLK_PERI:
702 		con = readl(&cru->clksel_con[37]);
703 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
704 		break;
705 	default:
706 		return -ENOENT;
707 	}
708 
709 	return DIV_TO_RATE(parent, div);
710 }
711 
712 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
713 				 ulong hz)
714 {
715 	struct rk3308_cru *cru = priv->cru;
716 	int src_clk_div;
717 
718 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
719 	assert(src_clk_div - 1 < 31);
720 
721 	/*
722 	 * select dpll as pd_peri bus clock source and
723 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
724 	 */
725 	switch (clk_id) {
726 	case ACLK_PERI:
727 		rk_clrsetreg(&cru->clksel_con[36],
728 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
729 			     PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
730 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
731 		break;
732 	case HCLK_PERI:
733 		rk_clrsetreg(&cru->clksel_con[37],
734 			     PERI_HCLK_DIV_MASK,
735 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
736 		break;
737 	case PCLK_PERI:
738 		rk_clrsetreg(&cru->clksel_con[37],
739 			     PERI_PCLK_DIV_MASK,
740 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
741 		break;
742 	default:
743 		printf("do not support this peri freq\n");
744 		return -EINVAL;
745 	}
746 
747 	return rk3308_peri_get_clk(priv, clk_id);
748 }
749 
750 static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
751 {
752 	struct rk3308_cru *cru = priv->cru;
753 	u32 div, con, parent = priv->vpll0_hz;
754 
755 	switch (clk_id) {
756 	case HCLK_AUDIO:
757 		con = readl(&cru->clksel_con[45]);
758 		div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
759 		break;
760 	case PCLK_AUDIO:
761 		con = readl(&cru->clksel_con[45]);
762 		div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
763 		break;
764 	default:
765 		return -ENOENT;
766 	}
767 
768 	return DIV_TO_RATE(parent, div);
769 }
770 
771 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
772 				  ulong hz)
773 {
774 	struct rk3308_cru *cru = priv->cru;
775 	int src_clk_div;
776 
777 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
778 	assert(src_clk_div - 1 < 31);
779 
780 	/*
781 	 * select vpll0 as audio bus clock source and
782 	 * set up dependent divisors for HCLK and PCLK clocks.
783 	 */
784 	switch (clk_id) {
785 	case HCLK_AUDIO:
786 		rk_clrsetreg(&cru->clksel_con[45],
787 			     AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
788 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
789 			     (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
790 		break;
791 	case PCLK_AUDIO:
792 		rk_clrsetreg(&cru->clksel_con[45],
793 			     AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
794 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
795 			     (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
796 		break;
797 	default:
798 		printf("do not support this audio freq\n");
799 		return -EINVAL;
800 	}
801 
802 	return rk3308_peri_get_clk(priv, clk_id);
803 }
804 
805 static ulong rk3308_clk_get_rate(struct clk *clk)
806 {
807 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
808 	ulong rate = 0;
809 
810 	rk3308_clk_get_pll_rate(priv);
811 
812 	debug("%s id:%ld\n", __func__, clk->id);
813 
814 	switch (clk->id) {
815 	case PLL_APLL:
816 		rate = rkclk_pll_get_rate(priv, APLL);
817 		break;
818 	case PLL_DPLL:
819 		rate = rkclk_pll_get_rate(priv, DPLL);
820 		break;
821 	case PLL_VPLL0:
822 		rate = rkclk_pll_get_rate(priv, VPLL0);
823 		break;
824 	case PLL_VPLL1:
825 		rate = rkclk_pll_get_rate(priv, VPLL1);
826 		break;
827 	case HCLK_SDMMC:
828 	case HCLK_EMMC:
829 	case SCLK_SDMMC:
830 	case SCLK_EMMC:
831 	case SCLK_EMMC_SAMPLE:
832 		rate = rk3308_mmc_get_clk(clk);
833 		break;
834 	case SCLK_I2C0:
835 	case SCLK_I2C1:
836 	case SCLK_I2C2:
837 	case SCLK_I2C3:
838 		rate = rk3308_i2c_get_clk(clk);
839 		break;
840 	case SCLK_SARADC:
841 		rate = rk3308_saradc_get_clk(clk);
842 		break;
843 	case SCLK_SPI0:
844 	case SCLK_SPI1:
845 		rate = rk3308_spi_get_clk(clk);
846 		break;
847 	case SCLK_PWM:
848 		rate = rk3308_pwm_get_clk(clk);
849 		break;
850 	case DCLK_VOP:
851 		rate = rk3308_vop_get_clk(clk);
852 		break;
853 	case ACLK_BUS:
854 	case HCLK_BUS:
855 	case PCLK_BUS:
856 		rate = rk3308_bus_get_clk(priv, clk->id);
857 		break;
858 	case ACLK_PERI:
859 	case HCLK_PERI:
860 	case PCLK_PERI:
861 		rate = rk3308_peri_get_clk(priv, clk->id);
862 		break;
863 	case HCLK_AUDIO:
864 	case PCLK_AUDIO:
865 		rate = rk3308_audio_get_clk(priv, clk->id);
866 		break;
867 	default:
868 		return -ENOENT;
869 	}
870 
871 	return rate;
872 }
873 
874 static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
875 {
876 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
877 	ulong ret = 0;
878 
879 	rk3308_clk_get_pll_rate(priv);
880 
881 	debug("%s %ld %ld\n", __func__, clk->id, rate);
882 
883 	switch (clk->id) {
884 	case PLL_DPLL:
885 		ret = rkclk_set_pll(priv, DPLL, rate);
886 		priv->dpll_hz = rkclk_pll_get_rate(priv, DPLL);
887 		break;
888 	case HCLK_SDMMC:
889 	case HCLK_EMMC:
890 	case SCLK_SDMMC:
891 	case SCLK_EMMC:
892 		ret = rk3308_mmc_set_clk(clk, rate);
893 		break;
894 	case SCLK_I2C0:
895 	case SCLK_I2C1:
896 	case SCLK_I2C2:
897 	case SCLK_I2C3:
898 		ret = rk3308_i2c_set_clk(clk, rate);
899 		break;
900 	case SCLK_SARADC:
901 		ret = rk3308_saradc_set_clk(clk, rate);
902 		break;
903 	case SCLK_SPI0:
904 	case SCLK_SPI1:
905 		ret = rk3308_spi_set_clk(clk, rate);
906 		break;
907 	case SCLK_PWM:
908 		ret = rk3308_pwm_set_clk(clk, rate);
909 		break;
910 	case DCLK_VOP:
911 		ret = rk3308_vop_set_clk(clk, rate);
912 		break;
913 	case ACLK_BUS:
914 	case HCLK_BUS:
915 	case PCLK_BUS:
916 		rate = rk3308_bus_set_clk(priv, clk->id, rate);
917 		break;
918 	case ACLK_PERI:
919 	case HCLK_PERI:
920 	case PCLK_PERI:
921 		rate = rk3308_peri_set_clk(priv, clk->id, rate);
922 		break;
923 	case HCLK_AUDIO:
924 	case PCLK_AUDIO:
925 		rate = rk3308_audio_set_clk(priv, clk->id, rate);
926 		break;
927 	default:
928 		return -ENOENT;
929 	}
930 
931 	return ret;
932 }
933 
934 #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
935 #define ROCKCHIP_MMC_DEGREE_OFFSET	1
936 #define ROCKCHIP_MMC_DEGREE_MASK	(0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
937 #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
938 #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
939 
940 #define PSECS_PER_SEC 1000000000000LL
941 /*
942  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
943  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
944  */
945 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
946 
947 int rockchip_mmc_get_phase(struct clk *clk)
948 {
949 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
950 	struct rk3308_cru *cru = priv->cru;
951 	u32 raw_value, delay_num;
952 	u16 degrees = 0;
953 	ulong rate;
954 
955 	rate = rk3308_clk_get_rate(clk);
956 
957 	if (rate < 0)
958 		return rate;
959 
960 	if (clk->id == SCLK_EMMC_SAMPLE)
961 		raw_value = readl(&cru->emmc_con[1]);
962 	else
963 		raw_value = readl(&cru->sdmmc_con[1]);
964 
965 	raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
966 	degrees = (raw_value >>  ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
967 
968 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
969 		/* degrees/delaynum * 10000 */
970 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
971 					36 * (rate / 1000000);
972 
973 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
974 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
975 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
976 	}
977 
978 	return degrees % 360;
979 
980 }
981 
982 int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
983 {
984 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
985 	struct rk3308_cru *cru = priv->cru;
986 	u8 nineties, remainder, delay_num;
987 	u32 raw_value, delay;
988 	ulong rate;
989 
990 	rate = rk3308_clk_get_rate(clk);
991 
992 	if (rate < 0)
993 		return rate;
994 
995 	nineties = degrees / 90;
996 	remainder = (degrees % 90);
997 
998 	/*
999 	 * Convert to delay; do a little extra work to make sure we
1000 	 * don't overflow 32-bit / 64-bit numbers.
1001 	 */
1002 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
1003 	delay *= remainder;
1004 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
1005 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
1006 
1007 	delay_num = (u8)min_t(u32, delay, 255);
1008 
1009 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
1010 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
1011 	raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
1012 
1013 	if (clk->id == SCLK_EMMC_SAMPLE)
1014 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
1015 	else
1016 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
1017 
1018 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1019 	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
1020 
1021 	return 0;
1022 
1023 }
1024 
1025 static int rk3308_clk_get_phase(struct clk *clk)
1026 {
1027 	int ret;
1028 
1029 	switch (clk->id) {
1030 	case SCLK_EMMC_SAMPLE:
1031 	case SCLK_SDMMC_SAMPLE:
1032 		ret = rockchip_mmc_get_phase(clk);
1033 		break;
1034 	default:
1035 		return -ENOENT;
1036 	}
1037 
1038 	return ret;
1039 }
1040 
1041 static int rk3308_clk_set_phase(struct clk *clk, int degrees)
1042 {
1043 	int ret;
1044 
1045 	switch (clk->id) {
1046 	case SCLK_EMMC_SAMPLE:
1047 	case SCLK_SDMMC_SAMPLE:
1048 		ret = rockchip_mmc_set_phase(clk, degrees);
1049 		break;
1050 	default:
1051 		return -ENOENT;
1052 	}
1053 
1054 	return ret;
1055 }
1056 
1057 static struct clk_ops rk3308_clk_ops = {
1058 	.get_rate = rk3308_clk_get_rate,
1059 	.set_rate = rk3308_clk_set_rate,
1060 	.get_phase	= rk3308_clk_get_phase,
1061 	.set_phase	= rk3308_clk_set_phase,
1062 };
1063 
1064 static int rk3308_clk_probe(struct udevice *dev)
1065 {
1066 	rkclk_init(dev);
1067 
1068 	return 0;
1069 }
1070 
1071 static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
1072 {
1073 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
1074 
1075 	priv->cru = dev_read_addr_ptr(dev);
1076 
1077 	return 0;
1078 }
1079 
1080 static int rk3308_clk_bind(struct udevice *dev)
1081 {
1082 	int ret;
1083 	struct udevice *sys_child, *sf_child;
1084 	struct sysreset_reg *priv;
1085 	struct softreset_reg *sf_priv;
1086 
1087 	/* The reset driver does not have a device node, so bind it here */
1088 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1089 				 &sys_child);
1090 	if (ret) {
1091 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1092 	} else {
1093 		priv = malloc(sizeof(struct sysreset_reg));
1094 		priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
1095 						    glb_srst_fst);
1096 		priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
1097 						    glb_srst_snd);
1098 		sys_child->priv = priv;
1099 	}
1100 
1101 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1102 					 dev_ofnode(dev), &sf_child);
1103 	if (ret) {
1104 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1105 	} else {
1106 		sf_priv = malloc(sizeof(struct softreset_reg));
1107 		sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
1108 						    softrst_con[0]);
1109 		sf_priv->sf_reset_num = 12;
1110 		sf_child->priv = sf_priv;
1111 	}
1112 
1113 	return 0;
1114 }
1115 
1116 static const struct udevice_id rk3308_clk_ids[] = {
1117 	{ .compatible = "rockchip,rk3308-cru" },
1118 	{ }
1119 };
1120 
1121 U_BOOT_DRIVER(rockchip_rk3308_cru) = {
1122 	.name		= "rockchip_rk3308_cru",
1123 	.id		= UCLASS_CLK,
1124 	.of_match	= rk3308_clk_ids,
1125 	.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
1126 	.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
1127 	.ops		= &rk3308_clk_ops,
1128 	.bind		= rk3308_clk_bind,
1129 	.probe		= rk3308_clk_probe,
1130 };
1131 
1132 /**
1133  * soc_clk_dump() - Print clock frequencies
1134  * Returns zero on success
1135  *
1136  * Implementation for the clk dump command.
1137  */
1138 int soc_clk_dump(void)
1139 {
1140 	struct udevice *cru_dev;
1141 	const struct rk3308_clk_info *clk_dump;
1142 	struct clk clk;
1143 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1144 	unsigned long rate;
1145 	int i, ret;
1146 
1147 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1148 					  DM_GET_DRIVER(rockchip_rk3308_cru),
1149 					  &cru_dev);
1150 	if (ret) {
1151 		printf("%s failed to get cru device\n", __func__);
1152 		return ret;
1153 	}
1154 
1155 	printf("CLK:");
1156 	for (i = 0; i < clk_count; i++) {
1157 		clk_dump = &clks_dump[i];
1158 		if (clk_dump->name) {
1159 			clk.id = clk_dump->id;
1160 			ret = clk_request(cru_dev, &clk);
1161 			if (ret < 0)
1162 				return ret;
1163 
1164 			rate = clk_get_rate(&clk);
1165 			clk_free(&clk);
1166 			if (i == 0) {
1167 				if (rate < 0)
1168 					printf("%10s%20s\n", clk_dump->name,
1169 					       "unknown");
1170 				else
1171 					printf("%10s%20lu Hz\n", clk_dump->name,
1172 					       rate);
1173 			} else {
1174 				if (rate < 0)
1175 					printf("%14s%20s\n", clk_dump->name,
1176 					       "unknown");
1177 				else
1178 					printf("%14s%20lu Hz\n", clk_dump->name,
1179 					       rate);
1180 			}
1181 		}
1182 	}
1183 
1184 	return 0;
1185 }
1186