diff options
Diffstat (limited to 'arch/arm/mach-shmobile/clock-sh7372.c')
| -rw-r--r-- | arch/arm/mach-shmobile/clock-sh7372.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 8565aefa21fd..7db31e6c6bf2 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c | |||
| @@ -50,6 +50,9 @@ | |||
| 50 | #define SMSTPCR3 0xe615013c | 50 | #define SMSTPCR3 0xe615013c |
| 51 | #define SMSTPCR4 0xe6150140 | 51 | #define SMSTPCR4 0xe6150140 |
| 52 | 52 | ||
| 53 | #define FSIDIVA 0xFE1F8000 | ||
| 54 | #define FSIDIVB 0xFE1F8008 | ||
| 55 | |||
| 53 | /* Platforms must set frequency on their DV_CLKI pin */ | 56 | /* Platforms must set frequency on their DV_CLKI pin */ |
| 54 | struct clk sh7372_dv_clki_clk = { | 57 | struct clk sh7372_dv_clki_clk = { |
| 55 | }; | 58 | }; |
| @@ -288,6 +291,7 @@ struct clk sh7372_pllc2_clk = { | |||
| 288 | .ops = &pllc2_clk_ops, | 291 | .ops = &pllc2_clk_ops, |
| 289 | .parent = &extal1_div2_clk, | 292 | .parent = &extal1_div2_clk, |
| 290 | .freq_table = pllc2_freq_table, | 293 | .freq_table = pllc2_freq_table, |
| 294 | .nr_freqs = ARRAY_SIZE(pllc2_freq_table) - 1, | ||
| 291 | .parent_table = pllc2_parent, | 295 | .parent_table = pllc2_parent, |
| 292 | .parent_num = ARRAY_SIZE(pllc2_parent), | 296 | .parent_num = ARRAY_SIZE(pllc2_parent), |
| 293 | }; | 297 | }; |
| @@ -417,6 +421,101 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { | |||
| 417 | fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2), | 421 | fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2), |
| 418 | }; | 422 | }; |
| 419 | 423 | ||
| 424 | /* FSI DIV */ | ||
| 425 | static unsigned long fsidiv_recalc(struct clk *clk) | ||
| 426 | { | ||
| 427 | unsigned long value; | ||
| 428 | |||
| 429 | value = __raw_readl(clk->mapping->base); | ||
| 430 | |||
| 431 | if ((value & 0x3) != 0x3) | ||
| 432 | return 0; | ||
| 433 | |||
| 434 | value >>= 16; | ||
| 435 | if (value < 2) | ||
| 436 | return 0; | ||
| 437 | |||
| 438 | return clk->parent->rate / value; | ||
| 439 | } | ||
| 440 | |||
| 441 | static long fsidiv_round_rate(struct clk *clk, unsigned long rate) | ||
| 442 | { | ||
| 443 | return clk_rate_div_range_round(clk, 2, 0xffff, rate); | ||
| 444 | } | ||
| 445 | |||
| 446 | static void fsidiv_disable(struct clk *clk) | ||
| 447 | { | ||
| 448 | __raw_writel(0, clk->mapping->base); | ||
| 449 | } | ||
| 450 | |||
| 451 | static int fsidiv_enable(struct clk *clk) | ||
| 452 | { | ||
| 453 | unsigned long value; | ||
| 454 | |||
| 455 | value = __raw_readl(clk->mapping->base) >> 16; | ||
| 456 | if (value < 2) { | ||
| 457 | fsidiv_disable(clk); | ||
| 458 | return -ENOENT; | ||
| 459 | } | ||
| 460 | |||
| 461 | __raw_writel((value << 16) | 0x3, clk->mapping->base); | ||
| 462 | |||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int fsidiv_set_rate(struct clk *clk, | ||
| 467 | unsigned long rate, int algo_id) | ||
| 468 | { | ||
| 469 | int idx; | ||
| 470 | |||
| 471 | if (clk->parent->rate == rate) { | ||
| 472 | fsidiv_disable(clk); | ||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 476 | idx = (clk->parent->rate / rate) & 0xffff; | ||
| 477 | if (idx < 2) | ||
| 478 | return -ENOENT; | ||
| 479 | |||
| 480 | __raw_writel(idx << 16, clk->mapping->base); | ||
| 481 | return fsidiv_enable(clk); | ||
| 482 | } | ||
| 483 | |||
| 484 | static struct clk_ops fsidiv_clk_ops = { | ||
| 485 | .recalc = fsidiv_recalc, | ||
| 486 | .round_rate = fsidiv_round_rate, | ||
| 487 | .set_rate = fsidiv_set_rate, | ||
| 488 | .enable = fsidiv_enable, | ||
| 489 | .disable = fsidiv_disable, | ||
| 490 | }; | ||
| 491 | |||
| 492 | static struct clk_mapping sh7372_fsidiva_clk_mapping = { | ||
| 493 | .phys = FSIDIVA, | ||
| 494 | .len = 8, | ||
| 495 | }; | ||
| 496 | |||
| 497 | struct clk sh7372_fsidiva_clk = { | ||
| 498 | .ops = &fsidiv_clk_ops, | ||
| 499 | .parent = &div6_reparent_clks[DIV6_FSIA], /* late install */ | ||
| 500 | .mapping = &sh7372_fsidiva_clk_mapping, | ||
| 501 | }; | ||
| 502 | |||
| 503 | static struct clk_mapping sh7372_fsidivb_clk_mapping = { | ||
| 504 | .phys = FSIDIVB, | ||
| 505 | .len = 8, | ||
| 506 | }; | ||
| 507 | |||
| 508 | struct clk sh7372_fsidivb_clk = { | ||
| 509 | .ops = &fsidiv_clk_ops, | ||
| 510 | .parent = &div6_reparent_clks[DIV6_FSIB], /* late install */ | ||
| 511 | .mapping = &sh7372_fsidivb_clk_mapping, | ||
| 512 | }; | ||
| 513 | |||
| 514 | static struct clk *late_main_clks[] = { | ||
| 515 | &sh7372_fsidiva_clk, | ||
| 516 | &sh7372_fsidivb_clk, | ||
| 517 | }; | ||
| 518 | |||
| 420 | enum { MSTP001, | 519 | enum { MSTP001, |
| 421 | MSTP131, MSTP130, | 520 | MSTP131, MSTP130, |
| 422 | MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, | 521 | MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, |
| @@ -585,6 +684,9 @@ void __init sh7372_clock_init(void) | |||
| 585 | if (!ret) | 684 | if (!ret) |
| 586 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); | 685 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); |
| 587 | 686 | ||
| 687 | for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++) | ||
| 688 | ret = clk_register(late_main_clks[k]); | ||
| 689 | |||
| 588 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | 690 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); |
| 589 | 691 | ||
| 590 | if (!ret) | 692 | if (!ret) |
