diff options
Diffstat (limited to 'drivers/sh/clk/cpg.c')
-rw-r--r-- | drivers/sh/clk/cpg.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 07e9fb4f8041..b3dc44146ca0 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c | |||
@@ -361,3 +361,89 @@ int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, | |||
361 | return sh_clk_div_register_ops(clks, nr, table, | 361 | return sh_clk_div_register_ops(clks, nr, table, |
362 | &sh_clk_div4_reparent_clk_ops); | 362 | &sh_clk_div4_reparent_clk_ops); |
363 | } | 363 | } |
364 | |||
365 | /* FSI-DIV */ | ||
366 | static unsigned long fsidiv_recalc(struct clk *clk) | ||
367 | { | ||
368 | u32 value; | ||
369 | |||
370 | value = __raw_readl(clk->mapping->base); | ||
371 | |||
372 | value >>= 16; | ||
373 | if (value < 2) | ||
374 | return clk->parent->rate; | ||
375 | |||
376 | return clk->parent->rate / value; | ||
377 | } | ||
378 | |||
379 | static long fsidiv_round_rate(struct clk *clk, unsigned long rate) | ||
380 | { | ||
381 | return clk_rate_div_range_round(clk, 1, 0xffff, rate); | ||
382 | } | ||
383 | |||
384 | static void fsidiv_disable(struct clk *clk) | ||
385 | { | ||
386 | __raw_writel(0, clk->mapping->base); | ||
387 | } | ||
388 | |||
389 | static int fsidiv_enable(struct clk *clk) | ||
390 | { | ||
391 | u32 value; | ||
392 | |||
393 | value = __raw_readl(clk->mapping->base) >> 16; | ||
394 | if (value < 2) | ||
395 | return 0; | ||
396 | |||
397 | __raw_writel((value << 16) | 0x3, clk->mapping->base); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int fsidiv_set_rate(struct clk *clk, unsigned long rate) | ||
403 | { | ||
404 | u32 val; | ||
405 | int idx; | ||
406 | |||
407 | idx = (clk->parent->rate / rate) & 0xffff; | ||
408 | if (idx < 2) | ||
409 | __raw_writel(0, clk->mapping->base); | ||
410 | else | ||
411 | __raw_writel(idx << 16, clk->mapping->base); | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static struct sh_clk_ops fsidiv_clk_ops = { | ||
417 | .recalc = fsidiv_recalc, | ||
418 | .round_rate = fsidiv_round_rate, | ||
419 | .set_rate = fsidiv_set_rate, | ||
420 | .enable = fsidiv_enable, | ||
421 | .disable = fsidiv_disable, | ||
422 | }; | ||
423 | |||
424 | int __init sh_clk_fsidiv_register(struct clk *clks, int nr) | ||
425 | { | ||
426 | struct clk_mapping *map; | ||
427 | int i; | ||
428 | |||
429 | for (i = 0; i < nr; i++) { | ||
430 | |||
431 | map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL); | ||
432 | if (!map) { | ||
433 | pr_err("%s: unable to alloc memory\n", __func__); | ||
434 | return -ENOMEM; | ||
435 | } | ||
436 | |||
437 | /* clks[i].enable_reg came from SH_CLK_FSIDIV() */ | ||
438 | map->phys = (phys_addr_t)clks[i].enable_reg; | ||
439 | map->len = 8; | ||
440 | |||
441 | clks[i].enable_reg = 0; /* remove .enable_reg */ | ||
442 | clks[i].ops = &fsidiv_clk_ops; | ||
443 | clks[i].mapping = map; | ||
444 | |||
445 | clk_register(&clks[i]); | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||