diff options
Diffstat (limited to 'arch/arm/mach-s3c2443')
-rw-r--r-- | arch/arm/mach-s3c2443/clock.c | 187 |
1 files changed, 62 insertions, 125 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c index f89e71f50345..1307f69abf98 100644 --- a/arch/arm/mach-s3c2443/clock.c +++ b/arch/arm/mach-s3c2443/clock.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/clock.c | 1 | /* linux/arch/arm/mach-s3c2443/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2007,2010 Simtec Electronics | 3 | * Copyright (c) 2007, 2010 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C2443 Clock control support | 6 | * S3C2443 Clock control support |
@@ -145,33 +145,24 @@ static struct clk clk_mdivclk = { | |||
145 | }, | 145 | }, |
146 | }; | 146 | }; |
147 | 147 | ||
148 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) | 148 | static struct clk *clk_msysclk_sources[] = { |
149 | { | 149 | [0] = &clk_mpllref, |
150 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 150 | [1] = &clk_mpll, |
151 | 151 | [2] = &clk_mdivclk, | |
152 | clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | | 152 | [3] = &clk_mpllref, |
153 | S3C2443_CLKSRC_EXTCLK_DIV); | 153 | }; |
154 | |||
155 | if (parent == &clk_mpll) | ||
156 | clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL; | ||
157 | else if (parent == &clk_mdivclk) | ||
158 | clksrc |= S3C2443_CLKSRC_EXTCLK_DIV; | ||
159 | else if (parent != &clk_mpllref) | ||
160 | return -EINVAL; | ||
161 | |||
162 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
163 | clk->parent = parent; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | 154 | ||
168 | static struct clk clk_msysclk = { | 155 | static struct clksrc_clk clk_msysclk = { |
169 | .name = "msysclk", | 156 | .clk = { |
170 | .parent = &clk_xtal, | 157 | .name = "msysclk", |
171 | .id = -1, | 158 | .parent = &clk_xtal, |
172 | .ops = &(struct clk_ops) { | 159 | .id = -1, |
173 | .set_parent = s3c2443_setparent_msysclk, | 160 | }, |
161 | .sources = &(struct clksrc_sources) { | ||
162 | .sources = clk_msysclk_sources, | ||
163 | .nr_sources = ARRAY_SIZE(clk_msysclk_sources), | ||
174 | }, | 164 | }, |
165 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, | ||
175 | }; | 166 | }; |
176 | 167 | ||
177 | /* armdiv | 168 | /* armdiv |
@@ -183,38 +174,29 @@ static struct clk clk_msysclk = { | |||
183 | static struct clk clk_armdiv = { | 174 | static struct clk clk_armdiv = { |
184 | .name = "armdiv", | 175 | .name = "armdiv", |
185 | .id = -1, | 176 | .id = -1, |
186 | .parent = &clk_msysclk, | 177 | .parent = &clk_msysclk.clk, |
187 | }; | 178 | }; |
188 | 179 | ||
189 | /* armclk | 180 | /* armclk |
190 | * | 181 | * |
191 | * this is the clock fed into the ARM core itself, either from | 182 | * this is the clock fed into the ARM core itself, from armdiv or from hclk. |
192 | * armdiv or from hclk. | ||
193 | */ | 183 | */ |
194 | 184 | ||
195 | static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) | 185 | static struct clk *clk_arm_sources[] = { |
196 | { | 186 | [0] = &clk_armdiv, |
197 | unsigned long clkdiv0; | 187 | [1] = &clk_h, |
198 | 188 | }; | |
199 | clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | ||
200 | |||
201 | if (parent == &clk_armdiv) | ||
202 | clkdiv0 &= ~S3C2443_CLKDIV0_DVS; | ||
203 | else if (parent == &clk_h) | ||
204 | clkdiv0 |= S3C2443_CLKDIV0_DVS; | ||
205 | else | ||
206 | return -EINVAL; | ||
207 | |||
208 | __raw_writel(clkdiv0, S3C2443_CLKDIV0); | ||
209 | return 0; | ||
210 | } | ||
211 | 189 | ||
212 | static struct clk clk_arm = { | 190 | static struct clksrc_clk clk_arm = { |
213 | .name = "armclk", | 191 | .clk = { |
214 | .id = -1, | 192 | .name = "armclk", |
215 | .ops = &(struct clk_ops) { | 193 | .id = -1, |
216 | .set_parent = s3c2443_setparent_armclk, | ||
217 | }, | 194 | }, |
195 | .sources = &(struct clksrc_sources) { | ||
196 | .sources = clk_arm_sources, | ||
197 | .nr_sources = ARRAY_SIZE(clk_arm_sources), | ||
198 | }, | ||
199 | .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, | ||
218 | }; | 200 | }; |
219 | 201 | ||
220 | /* esysclk | 202 | /* esysclk |
@@ -222,30 +204,22 @@ static struct clk clk_arm = { | |||
222 | * this is sourced from either the EPLL or the EPLLref clock | 204 | * this is sourced from either the EPLL or the EPLLref clock |
223 | */ | 205 | */ |
224 | 206 | ||
225 | static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) | 207 | static struct clk *clk_sysclk_sources[] = { |
226 | { | 208 | [0] = &clk_epllref.clk, |
227 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 209 | [1] = &clk_epll, |
228 | 210 | }; | |
229 | if (parent == &clk_epll) | ||
230 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; | ||
231 | else if (parent == &clk_epllref.clk) | ||
232 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; | ||
233 | else | ||
234 | return -EINVAL; | ||
235 | |||
236 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
237 | clk->parent = parent; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | 211 | ||
242 | static struct clk clk_esysclk = { | 212 | static struct clksrc_clk clk_esysclk = { |
243 | .name = "esysclk", | 213 | .clk = { |
244 | .parent = &clk_epll, | 214 | .name = "esysclk", |
245 | .id = -1, | 215 | .parent = &clk_epll, |
246 | .ops = &(struct clk_ops) { | 216 | .id = -1, |
247 | .set_parent = s3c2443_setparent_esysclk, | ||
248 | }, | 217 | }, |
218 | .sources = &(struct clksrc_sources) { | ||
219 | .sources = clk_sysclk_sources, | ||
220 | .nr_sources = ARRAY_SIZE(clk_sysclk_sources), | ||
221 | }, | ||
222 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, | ||
249 | }; | 223 | }; |
250 | 224 | ||
251 | /* uartclk | 225 | /* uartclk |
@@ -257,7 +231,7 @@ static struct clksrc_clk clk_uart = { | |||
257 | .clk = { | 231 | .clk = { |
258 | .name = "uartclk", | 232 | .name = "uartclk", |
259 | .id = -1, | 233 | .id = -1, |
260 | .parent = &clk_esysclk, | 234 | .parent = &clk_esysclk.clk, |
261 | }, | 235 | }, |
262 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, | 236 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, |
263 | }; | 237 | }; |
@@ -272,7 +246,7 @@ static struct clksrc_clk clk_hsspi = { | |||
272 | .clk = { | 246 | .clk = { |
273 | .name = "hsspi", | 247 | .name = "hsspi", |
274 | .id = -1, | 248 | .id = -1, |
275 | .parent = &clk_esysclk, | 249 | .parent = &clk_esysclk.clk, |
276 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, | 250 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, |
277 | .enable = s3c2443_clkcon_enable_s, | 251 | .enable = s3c2443_clkcon_enable_s, |
278 | }, | 252 | }, |
@@ -288,7 +262,7 @@ static struct clksrc_clk clk_usb_bus_host = { | |||
288 | .clk = { | 262 | .clk = { |
289 | .name = "usb-bus-host-parent", | 263 | .name = "usb-bus-host-parent", |
290 | .id = -1, | 264 | .id = -1, |
291 | .parent = &clk_esysclk, | 265 | .parent = &clk_esysclk.clk, |
292 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | 266 | .ctrlbit = S3C2443_SCLKCON_USBHOST, |
293 | .enable = s3c2443_clkcon_enable_s, | 267 | .enable = s3c2443_clkcon_enable_s, |
294 | }, | 268 | }, |
@@ -306,7 +280,7 @@ static struct clksrc_clk clk_hsmmc_div = { | |||
306 | .clk = { | 280 | .clk = { |
307 | .name = "hsmmc-div", | 281 | .name = "hsmmc-div", |
308 | .id = -1, | 282 | .id = -1, |
309 | .parent = &clk_esysclk, | 283 | .parent = &clk_esysclk.clk, |
310 | }, | 284 | }, |
311 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, | 285 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, |
312 | }; | 286 | }; |
@@ -358,7 +332,7 @@ static struct clksrc_clk clk_i2s_eplldiv = { | |||
358 | .clk = { | 332 | .clk = { |
359 | .name = "i2s-eplldiv", | 333 | .name = "i2s-eplldiv", |
360 | .id = -1, | 334 | .id = -1, |
361 | .parent = &clk_esysclk, | 335 | .parent = &clk_esysclk.clk, |
362 | }, | 336 | }, |
363 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, | 337 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, |
364 | }; | 338 | }; |
@@ -401,7 +375,7 @@ static struct clksrc_clk clk_cam = { | |||
401 | .clk = { | 375 | .clk = { |
402 | .name = "camif-upll", /* same as 2440 name */ | 376 | .name = "camif-upll", /* same as 2440 name */ |
403 | .id = -1, | 377 | .id = -1, |
404 | .parent = &clk_esysclk, | 378 | .parent = &clk_esysclk.clk, |
405 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | 379 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, |
406 | .enable = s3c2443_clkcon_enable_s, | 380 | .enable = s3c2443_clkcon_enable_s, |
407 | }, | 381 | }, |
@@ -417,7 +391,7 @@ static struct clksrc_clk clk_display = { | |||
417 | .clk = { | 391 | .clk = { |
418 | .name = "display-if", | 392 | .name = "display-if", |
419 | .id = -1, | 393 | .id = -1, |
420 | .parent = &clk_esysclk, | 394 | .parent = &clk_esysclk.clk, |
421 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | 395 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, |
422 | .enable = s3c2443_clkcon_enable_s, | 396 | .enable = s3c2443_clkcon_enable_s, |
423 | }, | 397 | }, |
@@ -443,7 +417,7 @@ static unsigned long s3c2443_prediv_getrate(struct clk *clk) | |||
443 | static struct clk clk_prediv = { | 417 | static struct clk clk_prediv = { |
444 | .name = "prediv", | 418 | .name = "prediv", |
445 | .id = -1, | 419 | .id = -1, |
446 | .parent = &clk_msysclk, | 420 | .parent = &clk_msysclk.clk, |
447 | .ops = &(struct clk_ops) { | 421 | .ops = &(struct clk_ops) { |
448 | .get_rate = s3c2443_prediv_getrate, | 422 | .get_rate = s3c2443_prediv_getrate, |
449 | }, | 423 | }, |
@@ -629,19 +603,11 @@ static struct clk init_clocks[] = { | |||
629 | 603 | ||
630 | /* clocks to add where we need to check their parentage */ | 604 | /* clocks to add where we need to check their parentage */ |
631 | 605 | ||
632 | /* s3c2443_clk_initparents | ||
633 | * | ||
634 | * Initialise the parents for the clocks that we get at start-time | ||
635 | */ | ||
636 | |||
637 | static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) | ||
638 | { | ||
639 | printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); | ||
640 | return clk_set_parent(clk, parent); | ||
641 | } | ||
642 | |||
643 | static struct clksrc_clk __initdata *init_list[] = { | 606 | static struct clksrc_clk __initdata *init_list[] = { |
644 | &clk_epllref, /* should be first */ | 607 | &clk_epllref, /* should be first */ |
608 | &clk_esysclk, | ||
609 | &clk_msysclk, | ||
610 | &clk_arm, | ||
645 | &clk_i2s_eplldiv, | 611 | &clk_i2s_eplldiv, |
646 | &clk_i2s, | 612 | &clk_i2s, |
647 | &clk_cam, | 613 | &clk_cam, |
@@ -653,39 +619,10 @@ static struct clksrc_clk __initdata *init_list[] = { | |||
653 | 619 | ||
654 | static void __init s3c2443_clk_initparents(void) | 620 | static void __init s3c2443_clk_initparents(void) |
655 | { | 621 | { |
656 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
657 | struct clk *parent; | ||
658 | int ptr; | 622 | int ptr; |
659 | 623 | ||
660 | /* esysclk source */ | ||
661 | |||
662 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? | ||
663 | &clk_epll : &clk_epllref.clk; | ||
664 | |||
665 | clk_init_set_parent(&clk_esysclk, parent); | ||
666 | |||
667 | /* msysclk source */ | ||
668 | |||
669 | if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) { | ||
670 | parent = &clk_mpll; | ||
671 | } else { | ||
672 | parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ? | ||
673 | &clk_mdivclk : &clk_mpllref; | ||
674 | } | ||
675 | |||
676 | clk_init_set_parent(&clk_msysclk, parent); | ||
677 | |||
678 | /* arm */ | ||
679 | |||
680 | if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS) | ||
681 | parent = &clk_h; | ||
682 | else | ||
683 | parent = &clk_armdiv; | ||
684 | |||
685 | clk_init_set_parent(&clk_arm, parent); | ||
686 | |||
687 | for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++) | 624 | for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++) |
688 | s3c_set_clksrc(init_list[ptr], false); | 625 | s3c_set_clksrc(init_list[ptr], true); |
689 | } | 626 | } |
690 | 627 | ||
691 | /* armdiv divisor table */ | 628 | /* armdiv divisor table */ |
@@ -720,6 +657,9 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) | |||
720 | static struct clksrc_clk *clksrcs[] __initdata = { | 657 | static struct clksrc_clk *clksrcs[] __initdata = { |
721 | &clk_usb_bus_host, | 658 | &clk_usb_bus_host, |
722 | &clk_epllref, | 659 | &clk_epllref, |
660 | &clk_esysclk, | ||
661 | &clk_msysclk, | ||
662 | &clk_arm, | ||
723 | &clk_uart, | 663 | &clk_uart, |
724 | &clk_display, | 664 | &clk_display, |
725 | &clk_cam, | 665 | &clk_cam, |
@@ -733,12 +673,9 @@ static struct clk *clks[] __initdata = { | |||
733 | &clk_ext, | 673 | &clk_ext, |
734 | &clk_epll, | 674 | &clk_epll, |
735 | &clk_usb_bus, | 675 | &clk_usb_bus, |
736 | &clk_esysclk, | ||
737 | &clk_mpllref, | 676 | &clk_mpllref, |
738 | &clk_msysclk, | ||
739 | &clk_hsmmc, | 677 | &clk_hsmmc, |
740 | &clk_armdiv, | 678 | &clk_armdiv, |
741 | &clk_arm, | ||
742 | &clk_prediv, | 679 | &clk_prediv, |
743 | }; | 680 | }; |
744 | 681 | ||
@@ -758,7 +695,7 @@ void __init_or_cpufreq s3c2443_setup_clocks(void) | |||
758 | clk_put(xtal_clk); | 695 | clk_put(xtal_clk); |
759 | 696 | ||
760 | pll = s3c2443_get_mpll(mpllcon, xtal); | 697 | pll = s3c2443_get_mpll(mpllcon, xtal); |
761 | clk_msysclk.rate = pll; | 698 | clk_msysclk.clk.rate = pll; |
762 | 699 | ||
763 | fclk = pll / s3c2443_fclk_div(clkdiv0); | 700 | fclk = pll / s3c2443_fclk_div(clkdiv0); |
764 | hclk = s3c2443_prediv_getrate(&clk_prediv); | 701 | hclk = s3c2443_prediv_getrate(&clk_prediv); |