xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3308.c (revision 9cc336e89e858e0607f7b7c72166345b0a882be5)
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, "gpll"),
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 rkclk_init(struct udevice *dev)
228 {
229 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
230 	struct rk3308_cru *cru = priv->cru;
231 	u32 aclk_div, pclk_div;
232 
233 	/* init pll */
234 	if (rkclk_set_pll(priv, APLL, APLL_HZ))
235 		printf("%s set apll unsuccessfully\n", __func__);
236 
237 	/*
238 	 * select apll as cpu/core clock pll source and
239 	 * set up dependent divisors for PCLK and ACLK clocks.
240 	 * core hz : apll = 1:1
241 	 */
242 	priv->apll_hz = rkclk_pll_get_rate(priv, APLL);
243 	aclk_div = priv->apll_hz / CORE_ACLK_HZ - 1;
244 	pclk_div = priv->apll_hz / CORE_DBG_HZ - 1;
245 	rk_clrsetreg(&cru->clksel_con[0],
246 		     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK |
247 		     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
248 		     aclk_div << CORE_ACLK_DIV_SHIFT |
249 		     pclk_div << CORE_DBG_DIV_SHIFT |
250 		     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
251 		     0 << CORE_DIV_CON_SHIFT);
252 
253 	priv->dpll_hz = rkclk_pll_get_rate(priv, DPLL);
254 	priv->vpll0_hz = rkclk_pll_get_rate(priv, VPLL0);
255 	priv->vpll1_hz = rkclk_pll_get_rate(priv, VPLL1);
256 
257 	rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
258 	rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
259 	rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
260 
261 	rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
262 	rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
263 	rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
264 
265 	rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
266 	rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
267 }
268 
269 static ulong rk3308_i2c_get_clk(struct clk *clk)
270 {
271 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
272 	struct rk3308_cru *cru = priv->cru;
273 	u32 div, con, con_id;
274 
275 	switch (clk->id) {
276 	case SCLK_I2C0:
277 		con_id = 25;
278 		break;
279 	case SCLK_I2C1:
280 		con_id = 26;
281 		break;
282 	case SCLK_I2C2:
283 		con_id = 27;
284 		break;
285 	case SCLK_I2C3:
286 		con_id = 28;
287 		break;
288 	default:
289 		printf("do not support this i2c bus\n");
290 		return -EINVAL;
291 	}
292 
293 	con = readl(&cru->clksel_con[con_id]);
294 	div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
295 
296 	return DIV_TO_RATE(priv->dpll_hz, div);
297 }
298 
299 static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
300 {
301 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
302 	struct rk3308_cru *cru = priv->cru;
303 	u32 src_clk_div, con_id;
304 
305 	src_clk_div = priv->dpll_hz / hz;
306 	assert(src_clk_div - 1 < 127);
307 
308 	switch (clk->id) {
309 	case SCLK_I2C0:
310 		con_id = 25;
311 		break;
312 	case SCLK_I2C1:
313 		con_id = 26;
314 		break;
315 	case SCLK_I2C2:
316 		con_id = 27;
317 		break;
318 	case SCLK_I2C3:
319 		con_id = 28;
320 		break;
321 	default:
322 		printf("do not support this i2c bus\n");
323 		return -EINVAL;
324 	}
325 	rk_clrsetreg(&cru->clksel_con[con_id],
326 		     CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
327 		     CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
328 		     (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
329 
330 	return rk3308_i2c_get_clk(clk);
331 }
332 
333 static ulong rk3308_mmc_get_clk(struct clk *clk)
334 {
335 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
336 	struct rk3308_cru *cru = priv->cru;
337 	u32 div, con, con_id;
338 
339 	switch (clk->id) {
340 	case HCLK_SDMMC:
341 	case SCLK_SDMMC:
342 		con_id = 39;
343 		break;
344 	case HCLK_EMMC:
345 	case SCLK_EMMC:
346 	case SCLK_EMMC_SAMPLE:
347 		con_id = 41;
348 		break;
349 	default:
350 		return -EINVAL;
351 	}
352 
353 	con = readl(&cru->clksel_con[con_id]);
354 	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
355 
356 	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
357 	    == EMMC_SEL_24M)
358 		return DIV_TO_RATE(OSC_HZ, div) / 2;
359 	else
360 		return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
361 }
362 
363 static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
364 {
365 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
366 	struct rk3308_cru *cru = priv->cru;
367 	int src_clk_div;
368 	u32 con_id;
369 
370 	debug("%s %ld %ld\n", __func__, clk->id, set_rate);
371 
372 	switch (clk->id) {
373 	case HCLK_SDMMC:
374 	case SCLK_SDMMC:
375 		con_id = 39;
376 		break;
377 	case HCLK_EMMC:
378 	case SCLK_EMMC:
379 		con_id = 41;
380 		break;
381 	default:
382 		return -EINVAL;
383 	}
384 	/* Select clk_sdmmc/emmc source from VPLL0 by default */
385 	/* mmc clock defaulg div 2 internal, need provide double in cru */
386 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
387 
388 	if (src_clk_div > 127) {
389 		/* use 24MHz source for 400KHz clock */
390 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
391 		rk_clrsetreg(&cru->clksel_con[con_id],
392 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
393 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
394 			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
395 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
396 	} else {
397 		rk_clrsetreg(&cru->clksel_con[con_id],
398 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
399 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
400 			     EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
401 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
402 	}
403 
404 	return rk3308_mmc_get_clk(clk);
405 }
406 
407 static ulong rk3308_saradc_get_clk(struct clk *clk)
408 {
409 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
410 	struct rk3308_cru *cru = priv->cru;
411 	u32 div, con;
412 
413 	con = readl(&cru->clksel_con[34]);
414 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
415 
416 	return DIV_TO_RATE(OSC_HZ, div);
417 }
418 
419 static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
420 {
421 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
422 	struct rk3308_cru *cru = priv->cru;
423 	int src_clk_div;
424 
425 	src_clk_div = OSC_HZ / hz;
426 	assert(src_clk_div - 1 < 2047);
427 
428 	rk_clrsetreg(&cru->clksel_con[34],
429 		     CLK_SARADC_DIV_CON_MASK,
430 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
431 
432 	return rk3308_saradc_get_clk(clk);
433 }
434 
435 static ulong rk3308_spi_get_clk(struct clk *clk)
436 {
437 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
438 	struct rk3308_cru *cru = priv->cru;
439 	u32 div, con, con_id;
440 
441 	switch (clk->id) {
442 	case SCLK_SPI0:
443 		con_id = 30;
444 		break;
445 	case SCLK_SPI1:
446 		con_id = 31;
447 		break;
448 	case SCLK_SPI2:
449 		con_id = 32;
450 		break;
451 	default:
452 		printf("do not support this spi bus\n");
453 		return -EINVAL;
454 	}
455 
456 	con = readl(&cru->clksel_con[con_id]);
457 	div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
458 
459 	return DIV_TO_RATE(priv->dpll_hz, div);
460 }
461 
462 static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
463 {
464 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
465 	struct rk3308_cru *cru = priv->cru;
466 	u32 src_clk_div, con_id;
467 
468 	src_clk_div = priv->dpll_hz / hz;
469 	assert(src_clk_div - 1 < 127);
470 
471 	switch (clk->id) {
472 	case SCLK_SPI0:
473 		con_id = 30;
474 		break;
475 	case SCLK_SPI1:
476 		con_id = 31;
477 		break;
478 	case SCLK_SPI2:
479 		con_id = 32;
480 		break;
481 	default:
482 		printf("do not support this spi bus\n");
483 		return -EINVAL;
484 	}
485 
486 	rk_clrsetreg(&cru->clksel_con[con_id],
487 		     CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
488 		     CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
489 		     (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
490 
491 	return rk3308_spi_get_clk(clk);
492 }
493 
494 static ulong rk3308_pwm_get_clk(struct clk *clk)
495 {
496 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
497 	struct rk3308_cru *cru = priv->cru;
498 	u32 div, con;
499 
500 	con = readl(&cru->clksel_con[29]);
501 	div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
502 
503 	return DIV_TO_RATE(priv->dpll_hz, div);
504 }
505 
506 static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
507 {
508 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
509 	struct rk3308_cru *cru = priv->cru;
510 	int src_clk_div;
511 
512 	src_clk_div = priv->dpll_hz / hz;
513 	assert(src_clk_div - 1 < 127);
514 
515 	rk_clrsetreg(&cru->clksel_con[29],
516 		     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
517 		     CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
518 		     (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
519 
520 	return rk3308_pwm_get_clk(clk);
521 }
522 
523 static ulong rk3308_vop_get_clk(struct clk *clk)
524 {
525 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
526 	struct rk3308_cru *cru = priv->cru;
527 	u32 div, pll_sel, vol_sel, con, parent;
528 
529 	con = readl(&cru->clksel_con[8]);
530 	vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
531 	pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
532 	div = con & DCLK_VOP_DIV_MASK;
533 
534 	if (vol_sel == DCLK_VOP_SEL_24M) {
535 		parent = OSC_HZ;
536 	} else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
537 		switch (pll_sel) {
538 		case DCLK_VOP_PLL_SEL_DPLL:
539 			parent = rkclk_pll_get_rate(priv, DPLL);
540 			break;
541 		case DCLK_VOP_PLL_SEL_VPLL0:
542 			parent = rkclk_pll_get_rate(priv, VPLL0);
543 			break;
544 		case DCLK_VOP_PLL_SEL_VPLL1:
545 			parent = rkclk_pll_get_rate(priv, VPLL1);
546 			break;
547 		default:
548 			printf("do not support this vop pll sel\n");
549 			return -EINVAL;
550 		}
551 	} else {
552 		printf("do not support this vop sel\n");
553 		return -EINVAL;
554 	}
555 
556 	return DIV_TO_RATE(parent, div);
557 }
558 
559 static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
560 {
561 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
562 	struct rk3308_cru *cru = priv->cru;
563 	ulong pll_rate, now, best_rate = 0;
564 	u32 i, div, best_div = 0, best_sel = 0;
565 
566 	for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
567 		switch (i) {
568 		case DCLK_VOP_PLL_SEL_DPLL:
569 			pll_rate = priv->dpll_hz;
570 			break;
571 		case DCLK_VOP_PLL_SEL_VPLL0:
572 			pll_rate = priv->vpll0_hz;
573 			break;
574 		case DCLK_VOP_PLL_SEL_VPLL1:
575 			pll_rate = priv->vpll1_hz;
576 			break;
577 		default:
578 			printf("do not support this vop pll sel\n");
579 			return -EINVAL;
580 		}
581 
582 		div = DIV_ROUND_UP(pll_rate, hz);
583 		if (div > 255)
584 			continue;
585 		now = pll_rate / div;
586 		if (abs(hz - now) < abs(hz - best_rate)) {
587 			best_rate = now;
588 			best_div = div;
589 			best_sel = i;
590 		}
591 		debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
592 		      pll_rate, best_rate, best_div, best_sel);
593 	}
594 
595 	if (best_rate != hz && hz == OSC_HZ) {
596 		rk_clrsetreg(&cru->clksel_con[8],
597 			     DCLK_VOP_SEL_MASK,
598 			     DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
599 	} else if (best_rate) {
600 		rk_clrsetreg(&cru->clksel_con[8],
601 			     DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
602 			     DCLK_VOP_DIV_MASK,
603 			     DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
604 			     best_sel << DCLK_VOP_PLL_SEL_SHIFT |
605 			     (best_div - 1) << DCLK_VOP_DIV_SHIFT);
606 	} else {
607 		printf("do not support this vop freq\n");
608 		return -EINVAL;
609 	}
610 
611 	return rk3308_vop_get_clk(clk);
612 }
613 
614 static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
615 {
616 	struct rk3308_cru *cru = priv->cru;
617 	u32 div, con, parent = priv->dpll_hz;
618 
619 	switch (clk_id) {
620 	case ACLK_BUS:
621 		con = readl(&cru->clksel_con[5]);
622 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
623 		break;
624 	case HCLK_BUS:
625 		con = readl(&cru->clksel_con[6]);
626 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
627 		break;
628 	case PCLK_BUS:
629 		con = readl(&cru->clksel_con[6]);
630 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
631 		break;
632 	default:
633 		return -ENOENT;
634 	}
635 
636 	return DIV_TO_RATE(parent, div);
637 }
638 
639 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
640 				ulong hz)
641 {
642 	struct rk3308_cru *cru = priv->cru;
643 	int src_clk_div;
644 
645 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
646 	assert(src_clk_div - 1 < 31);
647 
648 	/*
649 	 * select dpll as pd_bus bus clock source and
650 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
651 	 */
652 	switch (clk_id) {
653 	case ACLK_BUS:
654 		rk_clrsetreg(&cru->clksel_con[5],
655 			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
656 			     BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
657 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
658 		break;
659 	case HCLK_BUS:
660 		rk_clrsetreg(&cru->clksel_con[6],
661 			     BUS_HCLK_DIV_MASK,
662 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
663 		break;
664 	case PCLK_BUS:
665 		rk_clrsetreg(&cru->clksel_con[6],
666 			     BUS_PCLK_DIV_MASK,
667 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
668 		break;
669 	default:
670 		printf("do not support this bus freq\n");
671 		return -EINVAL;
672 	}
673 
674 	return rk3308_bus_get_clk(priv, clk_id);
675 }
676 
677 static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
678 {
679 	struct rk3308_cru *cru = priv->cru;
680 	u32 div, con, parent = priv->dpll_hz;
681 
682 	switch (clk_id) {
683 	case ACLK_PERI:
684 		con = readl(&cru->clksel_con[36]);
685 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
686 		break;
687 	case HCLK_PERI:
688 		con = readl(&cru->clksel_con[37]);
689 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
690 		break;
691 	case PCLK_PERI:
692 		con = readl(&cru->clksel_con[37]);
693 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
694 		break;
695 	default:
696 		return -ENOENT;
697 	}
698 
699 	return DIV_TO_RATE(parent, div);
700 }
701 
702 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
703 				 ulong hz)
704 {
705 	struct rk3308_cru *cru = priv->cru;
706 	int src_clk_div;
707 
708 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
709 	assert(src_clk_div - 1 < 31);
710 
711 	/*
712 	 * select dpll as pd_peri bus clock source and
713 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
714 	 */
715 	switch (clk_id) {
716 	case ACLK_PERI:
717 		rk_clrsetreg(&cru->clksel_con[36],
718 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
719 			     PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
720 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
721 		break;
722 	case HCLK_PERI:
723 		rk_clrsetreg(&cru->clksel_con[37],
724 			     PERI_HCLK_DIV_MASK,
725 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
726 		break;
727 	case PCLK_PERI:
728 		rk_clrsetreg(&cru->clksel_con[37],
729 			     PERI_PCLK_DIV_MASK,
730 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
731 		break;
732 	default:
733 		printf("do not support this peri freq\n");
734 		return -EINVAL;
735 	}
736 
737 	return rk3308_peri_get_clk(priv, clk_id);
738 }
739 
740 static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
741 {
742 	struct rk3308_cru *cru = priv->cru;
743 	u32 div, con, parent = priv->vpll0_hz;
744 
745 	switch (clk_id) {
746 	case HCLK_AUDIO:
747 		con = readl(&cru->clksel_con[45]);
748 		div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
749 		break;
750 	case PCLK_AUDIO:
751 		con = readl(&cru->clksel_con[45]);
752 		div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
753 		break;
754 	default:
755 		return -ENOENT;
756 	}
757 
758 	return DIV_TO_RATE(parent, div);
759 }
760 
761 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
762 				  ulong hz)
763 {
764 	struct rk3308_cru *cru = priv->cru;
765 	int src_clk_div;
766 
767 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
768 	assert(src_clk_div - 1 < 31);
769 
770 	/*
771 	 * select vpll0 as audio bus clock source and
772 	 * set up dependent divisors for HCLK and PCLK clocks.
773 	 */
774 	switch (clk_id) {
775 	case HCLK_AUDIO:
776 		rk_clrsetreg(&cru->clksel_con[45],
777 			     AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
778 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
779 			     (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
780 		break;
781 	case PCLK_AUDIO:
782 		rk_clrsetreg(&cru->clksel_con[45],
783 			     AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
784 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
785 			     (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
786 		break;
787 	default:
788 		printf("do not support this audio freq\n");
789 		return -EINVAL;
790 	}
791 
792 	return rk3308_peri_get_clk(priv, clk_id);
793 }
794 
795 static ulong rk3308_clk_get_rate(struct clk *clk)
796 {
797 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
798 	ulong rate = 0;
799 
800 	debug("%s id:%ld\n", __func__, clk->id);
801 
802 	switch (clk->id) {
803 	case PLL_APLL:
804 		rate = rkclk_pll_get_rate(priv, APLL);
805 		break;
806 	case PLL_DPLL:
807 		rate = rkclk_pll_get_rate(priv, DPLL);
808 		break;
809 	case PLL_VPLL0:
810 		rate = rkclk_pll_get_rate(priv, VPLL0);
811 		break;
812 	case PLL_VPLL1:
813 		rate = rkclk_pll_get_rate(priv, VPLL1);
814 		break;
815 	case HCLK_SDMMC:
816 	case HCLK_EMMC:
817 	case SCLK_SDMMC:
818 	case SCLK_EMMC:
819 	case SCLK_EMMC_SAMPLE:
820 		rate = rk3308_mmc_get_clk(clk);
821 		break;
822 	case SCLK_I2C0:
823 	case SCLK_I2C1:
824 	case SCLK_I2C2:
825 	case SCLK_I2C3:
826 		rate = rk3308_i2c_get_clk(clk);
827 		break;
828 	case SCLK_SARADC:
829 		rate = rk3308_saradc_get_clk(clk);
830 		break;
831 	case SCLK_SPI0:
832 	case SCLK_SPI1:
833 		rate = rk3308_spi_get_clk(clk);
834 		break;
835 	case SCLK_PWM:
836 		rate = rk3308_pwm_get_clk(clk);
837 		break;
838 	case DCLK_VOP:
839 		rate = rk3308_vop_get_clk(clk);
840 		break;
841 	case ACLK_BUS:
842 	case HCLK_BUS:
843 	case PCLK_BUS:
844 		rate = rk3308_bus_get_clk(priv, clk->id);
845 		break;
846 	case ACLK_PERI:
847 	case HCLK_PERI:
848 	case PCLK_PERI:
849 		rate = rk3308_peri_get_clk(priv, clk->id);
850 		break;
851 	case HCLK_AUDIO:
852 	case PCLK_AUDIO:
853 		rate = rk3308_audio_get_clk(priv, clk->id);
854 		break;
855 	default:
856 		return -ENOENT;
857 	}
858 
859 	return rate;
860 }
861 
862 static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
863 {
864 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
865 	ulong ret = 0;
866 
867 	debug("%s %ld %ld\n", __func__, clk->id, rate);
868 
869 	switch (clk->id) {
870 	case PLL_DPLL:
871 		ret = rkclk_set_pll(priv, DPLL, rate);
872 		break;
873 	case HCLK_SDMMC:
874 	case HCLK_EMMC:
875 	case SCLK_SDMMC:
876 	case SCLK_EMMC:
877 		ret = rk3308_mmc_set_clk(clk, rate);
878 		break;
879 	case SCLK_I2C0:
880 	case SCLK_I2C1:
881 	case SCLK_I2C2:
882 	case SCLK_I2C3:
883 		ret = rk3308_i2c_set_clk(clk, rate);
884 		break;
885 	case SCLK_SARADC:
886 		ret = rk3308_saradc_set_clk(clk, rate);
887 		break;
888 	case SCLK_SPI0:
889 	case SCLK_SPI1:
890 		ret = rk3308_spi_set_clk(clk, rate);
891 		break;
892 	case SCLK_PWM:
893 		ret = rk3308_pwm_set_clk(clk, rate);
894 		break;
895 	case DCLK_VOP:
896 		ret = rk3308_vop_set_clk(clk, rate);
897 		break;
898 	case ACLK_BUS:
899 	case HCLK_BUS:
900 	case PCLK_BUS:
901 		rate = rk3308_bus_set_clk(priv, clk->id, rate);
902 		break;
903 	case ACLK_PERI:
904 	case HCLK_PERI:
905 	case PCLK_PERI:
906 		rate = rk3308_peri_set_clk(priv, clk->id, rate);
907 		break;
908 	case HCLK_AUDIO:
909 	case PCLK_AUDIO:
910 		rate = rk3308_audio_set_clk(priv, clk->id, rate);
911 		break;
912 	default:
913 		return -ENOENT;
914 	}
915 
916 	return ret;
917 }
918 
919 #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
920 #define ROCKCHIP_MMC_DEGREE_OFFSET	1
921 #define ROCKCHIP_MMC_DEGREE_MASK	(0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
922 #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
923 #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
924 
925 #define PSECS_PER_SEC 1000000000000LL
926 /*
927  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
928  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
929  */
930 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
931 
932 int rockchip_mmc_get_phase(struct clk *clk)
933 {
934 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
935 	struct rk3308_cru *cru = priv->cru;
936 	u32 raw_value, delay_num;
937 	u16 degrees = 0;
938 	ulong rate;
939 
940 	rate = rk3308_clk_get_rate(clk);
941 
942 	if (rate < 0)
943 		return rate;
944 
945 	if (clk->id == SCLK_EMMC_SAMPLE)
946 		raw_value = readl(&cru->emmc_con[1]);
947 	else
948 		raw_value = readl(&cru->sdmmc_con[1]);
949 
950 	raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
951 	degrees = (raw_value >>  ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
952 
953 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
954 		/* degrees/delaynum * 10000 */
955 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
956 					36 * (rate / 1000000);
957 
958 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
959 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
960 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
961 	}
962 
963 	return degrees % 360;
964 
965 }
966 
967 int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
968 {
969 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
970 	struct rk3308_cru *cru = priv->cru;
971 	u8 nineties, remainder, delay_num;
972 	u32 raw_value, delay;
973 	ulong rate;
974 
975 	rate = rk3308_clk_get_rate(clk);
976 
977 	if (rate < 0)
978 		return rate;
979 
980 	nineties = degrees / 90;
981 	remainder = (degrees % 90);
982 
983 	/*
984 	 * Convert to delay; do a little extra work to make sure we
985 	 * don't overflow 32-bit / 64-bit numbers.
986 	 */
987 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
988 	delay *= remainder;
989 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
990 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
991 
992 	delay_num = (u8)min_t(u32, delay, 255);
993 
994 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
995 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
996 	raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
997 
998 	if (clk->id == SCLK_EMMC_SAMPLE)
999 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
1000 	else
1001 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
1002 
1003 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1004 	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
1005 
1006 	return 0;
1007 
1008 }
1009 
1010 static int rk3308_clk_get_phase(struct clk *clk)
1011 {
1012 	int ret;
1013 
1014 	switch (clk->id) {
1015 	case SCLK_EMMC_SAMPLE:
1016 	case SCLK_SDMMC_SAMPLE:
1017 		ret = rockchip_mmc_get_phase(clk);
1018 		break;
1019 	default:
1020 		return -ENOENT;
1021 	}
1022 
1023 	return ret;
1024 }
1025 
1026 static int rk3308_clk_set_phase(struct clk *clk, int degrees)
1027 {
1028 	int ret;
1029 
1030 	switch (clk->id) {
1031 	case SCLK_EMMC_SAMPLE:
1032 	case SCLK_SDMMC_SAMPLE:
1033 		ret = rockchip_mmc_set_phase(clk, degrees);
1034 		break;
1035 	default:
1036 		return -ENOENT;
1037 	}
1038 
1039 	return ret;
1040 }
1041 
1042 static struct clk_ops rk3308_clk_ops = {
1043 	.get_rate = rk3308_clk_get_rate,
1044 	.set_rate = rk3308_clk_set_rate,
1045 	.get_phase	= rk3308_clk_get_phase,
1046 	.set_phase	= rk3308_clk_set_phase,
1047 };
1048 
1049 static int rk3308_clk_probe(struct udevice *dev)
1050 {
1051 	rkclk_init(dev);
1052 
1053 	return 0;
1054 }
1055 
1056 static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
1057 {
1058 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
1059 
1060 	priv->cru = dev_read_addr_ptr(dev);
1061 
1062 	return 0;
1063 }
1064 
1065 static int rk3308_clk_bind(struct udevice *dev)
1066 {
1067 	int ret;
1068 	struct udevice *sys_child, *sf_child;
1069 	struct sysreset_reg *priv;
1070 	struct softreset_reg *sf_priv;
1071 
1072 	/* The reset driver does not have a device node, so bind it here */
1073 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1074 				 &sys_child);
1075 	if (ret) {
1076 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1077 	} else {
1078 		priv = malloc(sizeof(struct sysreset_reg));
1079 		priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
1080 						    glb_srst_fst);
1081 		priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
1082 						    glb_srst_snd);
1083 		sys_child->priv = priv;
1084 	}
1085 
1086 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1087 					 dev_ofnode(dev), &sf_child);
1088 	if (ret) {
1089 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1090 	} else {
1091 		sf_priv = malloc(sizeof(struct softreset_reg));
1092 		sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
1093 						    softrst_con[0]);
1094 		sf_priv->sf_reset_num = 12;
1095 		sf_child->priv = sf_priv;
1096 	}
1097 
1098 	return 0;
1099 }
1100 
1101 static const struct udevice_id rk3308_clk_ids[] = {
1102 	{ .compatible = "rockchip,rk3308-cru" },
1103 	{ }
1104 };
1105 
1106 U_BOOT_DRIVER(rockchip_rk3308_cru) = {
1107 	.name		= "rockchip_rk3308_cru",
1108 	.id		= UCLASS_CLK,
1109 	.of_match	= rk3308_clk_ids,
1110 	.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
1111 	.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
1112 	.ops		= &rk3308_clk_ops,
1113 	.bind		= rk3308_clk_bind,
1114 	.probe		= rk3308_clk_probe,
1115 };
1116 
1117 /**
1118  * soc_clk_dump() - Print clock frequencies
1119  * Returns zero on success
1120  *
1121  * Implementation for the clk dump command.
1122  */
1123 int soc_clk_dump(void)
1124 {
1125 	struct udevice *cru_dev;
1126 	const struct rk3308_clk_info *clk_dump;
1127 	struct clk clk;
1128 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1129 	unsigned long rate;
1130 	int i, ret;
1131 
1132 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1133 					  DM_GET_DRIVER(rockchip_rk3308_cru),
1134 					  &cru_dev);
1135 	if (ret) {
1136 		printf("%s failed to get cru device\n", __func__);
1137 		return ret;
1138 	}
1139 
1140 	printf("CLK:");
1141 	for (i = 0; i < clk_count; i++) {
1142 		clk_dump = &clks_dump[i];
1143 		if (clk_dump->name) {
1144 			clk.id = clk_dump->id;
1145 			ret = clk_request(cru_dev, &clk);
1146 			if (ret < 0)
1147 				return ret;
1148 
1149 			rate = clk_get_rate(&clk);
1150 			clk_free(&clk);
1151 			if (i == 0) {
1152 				if (rate < 0)
1153 					printf("%10s%20s\n", clk_dump->name,
1154 					       "unknown");
1155 				else
1156 					printf("%10s%20lu Hz\n", clk_dump->name,
1157 					       rate);
1158 			} else {
1159 				if (rate < 0)
1160 					printf("%14s%20s\n", clk_dump->name,
1161 					       "unknown");
1162 				else
1163 					printf("%14s%20lu Hz\n", clk_dump->name,
1164 					       rate);
1165 			}
1166 		}
1167 	}
1168 
1169 	return 0;
1170 }
1171