diff options
Diffstat (limited to 'arch/arm/plat-s3c64xx/s3c6400-clock.c')
-rw-r--r-- | arch/arm/plat-s3c64xx/s3c6400-clock.c | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 05b17528041e..1debc1f9f987 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c | |||
@@ -133,6 +133,65 @@ static struct clksrc_clk clk_mout_mpll = { | |||
133 | .sources = &clk_src_mpll, | 133 | .sources = &clk_src_mpll, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static unsigned int armclk_mask; | ||
137 | |||
138 | static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk) | ||
139 | { | ||
140 | unsigned long rate = clk_get_rate(clk->parent); | ||
141 | u32 clkdiv; | ||
142 | |||
143 | /* divisor mask starts at bit0, so no need to shift */ | ||
144 | clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask; | ||
145 | |||
146 | return rate / (clkdiv + 1); | ||
147 | } | ||
148 | |||
149 | static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, | ||
150 | unsigned long rate) | ||
151 | { | ||
152 | unsigned long parent = clk_get_rate(clk->parent); | ||
153 | u32 div; | ||
154 | |||
155 | if (parent < rate) | ||
156 | return rate; | ||
157 | |||
158 | div = (parent / rate) - 1; | ||
159 | if (div > armclk_mask) | ||
160 | div = armclk_mask; | ||
161 | |||
162 | return parent / (div + 1); | ||
163 | } | ||
164 | |||
165 | static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) | ||
166 | { | ||
167 | unsigned long parent = clk_get_rate(clk->parent); | ||
168 | u32 div; | ||
169 | u32 val; | ||
170 | |||
171 | if (rate < parent / (armclk_mask + 1)) | ||
172 | return -EINVAL; | ||
173 | |||
174 | rate = clk_round_rate(clk, rate); | ||
175 | div = clk_get_rate(clk->parent) / rate; | ||
176 | |||
177 | val = __raw_readl(S3C_CLK_DIV0); | ||
178 | val &= armclk_mask; | ||
179 | val |= (div - 1); | ||
180 | __raw_writel(val, S3C_CLK_DIV0); | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | } | ||
185 | |||
186 | static struct clk clk_arm = { | ||
187 | .name = "armclk", | ||
188 | .id = -1, | ||
189 | .parent = &clk_mout_apll.clk, | ||
190 | .get_rate = s3c64xx_clk_arm_get_rate, | ||
191 | .set_rate = s3c64xx_clk_arm_set_rate, | ||
192 | .round_rate = s3c64xx_clk_arm_round_rate, | ||
193 | }; | ||
194 | |||
136 | static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) | 195 | static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) |
137 | { | 196 | { |
138 | unsigned long rate = clk_get_rate(clk->parent); | 197 | unsigned long rate = clk_get_rate(clk->parent); |
@@ -520,6 +579,33 @@ static struct clksrc_clk clk_irda = { | |||
520 | .reg_divider = S3C_CLK_DIV2, | 579 | .reg_divider = S3C_CLK_DIV2, |
521 | }; | 580 | }; |
522 | 581 | ||
582 | static struct clk *clkset_camif_list[] = { | ||
583 | &clk_h2, | ||
584 | }; | ||
585 | |||
586 | static struct clk_sources clkset_camif = { | ||
587 | .sources = clkset_camif_list, | ||
588 | .nr_sources = ARRAY_SIZE(clkset_camif_list), | ||
589 | }; | ||
590 | |||
591 | static struct clksrc_clk clk_camif = { | ||
592 | .clk = { | ||
593 | .name = "camera", | ||
594 | .id = -1, | ||
595 | .ctrlbit = S3C_CLKCON_SCLK_CAM, | ||
596 | .enable = s3c64xx_sclk_ctrl, | ||
597 | .set_parent = s3c64xx_setparent_clksrc, | ||
598 | .get_rate = s3c64xx_getrate_clksrc, | ||
599 | .set_rate = s3c64xx_setrate_clksrc, | ||
600 | .round_rate = s3c64xx_roundrate_clksrc, | ||
601 | }, | ||
602 | .shift = 0, | ||
603 | .mask = 0, | ||
604 | .sources = &clkset_camif, | ||
605 | .divider_shift = S3C6400_CLKDIV0_CAM_SHIFT, | ||
606 | .reg_divider = S3C_CLK_DIV0, | ||
607 | }; | ||
608 | |||
523 | /* Clock initialisation code */ | 609 | /* Clock initialisation code */ |
524 | 610 | ||
525 | static struct clksrc_clk *init_parents[] = { | 611 | static struct clksrc_clk *init_parents[] = { |
@@ -536,6 +622,7 @@ static struct clksrc_clk *init_parents[] = { | |||
536 | &clk_audio0, | 622 | &clk_audio0, |
537 | &clk_audio1, | 623 | &clk_audio1, |
538 | &clk_irda, | 624 | &clk_irda, |
625 | &clk_camif, | ||
539 | }; | 626 | }; |
540 | 627 | ||
541 | static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk) | 628 | static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk) |
@@ -608,6 +695,7 @@ void __init_or_cpufreq s3c6400_setup_clocks(void) | |||
608 | clk_fout_epll.rate = epll; | 695 | clk_fout_epll.rate = epll; |
609 | clk_fout_apll.rate = apll; | 696 | clk_fout_apll.rate = apll; |
610 | 697 | ||
698 | clk_h2.rate = hclk2; | ||
611 | clk_h.rate = hclk; | 699 | clk_h.rate = hclk; |
612 | clk_p.rate = pclk; | 700 | clk_p.rate = pclk; |
613 | clk_f.rate = fclk; | 701 | clk_f.rate = fclk; |
@@ -635,14 +723,30 @@ static struct clk *clks[] __initdata = { | |||
635 | &clk_audio0.clk, | 723 | &clk_audio0.clk, |
636 | &clk_audio1.clk, | 724 | &clk_audio1.clk, |
637 | &clk_irda.clk, | 725 | &clk_irda.clk, |
726 | &clk_camif.clk, | ||
727 | &clk_arm, | ||
638 | }; | 728 | }; |
639 | 729 | ||
640 | void __init s3c6400_register_clocks(void) | 730 | /** |
731 | * s3c6400_register_clocks - register clocks for s3c6400 and above | ||
732 | * @armclk_divlimit: Divisor mask for ARMCLK | ||
733 | * | ||
734 | * Register the clocks for the S3C6400 and above SoC range, such | ||
735 | * as ARMCLK and the clocks which have divider chains attached. | ||
736 | * | ||
737 | * This call does not setup the clocks, which is left to the | ||
738 | * s3c6400_setup_clocks() call which may be needed by the cpufreq | ||
739 | * or resume code to re-set the clocks if the bootloader has changed | ||
740 | * them. | ||
741 | */ | ||
742 | void __init s3c6400_register_clocks(unsigned armclk_divlimit) | ||
641 | { | 743 | { |
642 | struct clk *clkp; | 744 | struct clk *clkp; |
643 | int ret; | 745 | int ret; |
644 | int ptr; | 746 | int ptr; |
645 | 747 | ||
748 | armclk_mask = armclk_divlimit; | ||
749 | |||
646 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { | 750 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { |
647 | clkp = clks[ptr]; | 751 | clkp = clks[ptr]; |
648 | ret = s3c24xx_register_clock(clkp); | 752 | ret = s3c24xx_register_clock(clkp); |