aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/clk/cpg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sh/clk/cpg.c')
-rw-r--r--drivers/sh/clk/cpg.c86
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 */
366static 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
379static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
380{
381 return clk_rate_div_range_round(clk, 1, 0xffff, rate);
382}
383
384static void fsidiv_disable(struct clk *clk)
385{
386 __raw_writel(0, clk->mapping->base);
387}
388
389static 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
402static 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
416static 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
424int __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}