aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2443')
-rw-r--r--arch/arm/mach-s3c2443/clock.c187
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
148static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) 148static 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
168static struct clk clk_msysclk = { 155static 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 = {
183static struct clk clk_armdiv = { 174static 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
195static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) 185static 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
212static struct clk clk_arm = { 190static 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
225static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) 207static 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
242static struct clk clk_esysclk = { 212static 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)
443static struct clk clk_prediv = { 417static 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
637static 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
643static struct clksrc_clk __initdata *init_list[] = { 606static 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
654static void __init s3c2443_clk_initparents(void) 620static 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)
720static struct clksrc_clk *clksrcs[] __initdata = { 657static 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);