aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s3c24xx/s3c2443-clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-s3c24xx/s3c2443-clock.c')
-rw-r--r--arch/arm/plat-s3c24xx/s3c2443-clock.c192
1 files changed, 187 insertions, 5 deletions
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c
index 59552c0ea5fb..5a21b15b2a97 100644
--- a/arch/arm/plat-s3c24xx/s3c2443-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c2443-clock.c
@@ -160,6 +160,124 @@ static struct clk clk_prediv = {
160 }, 160 },
161}; 161};
162 162
163/* armdiv
164 *
165 * this clock is sourced from msysclk and can have a number of
166 * divider values applied to it to then be fed into armclk.
167*/
168
169static unsigned int *armdiv;
170static int nr_armdiv;
171static int armdivmask;
172
173static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
174 unsigned long rate)
175{
176 unsigned long parent = clk_get_rate(clk->parent);
177 unsigned long calc;
178 unsigned best = 256; /* bigger than any value */
179 unsigned div;
180 int ptr;
181
182 if (!nr_armdiv)
183 return -EINVAL;
184
185 for (ptr = 0; ptr < nr_armdiv; ptr++) {
186 div = armdiv[ptr];
187 if (div) {
188 /* cpufreq provides 266mhz as 266666000 not 266666666 */
189 calc = (parent / div / 1000) * 1000;
190 if (calc <= rate && div < best)
191 best = div;
192 }
193 }
194
195 return parent / best;
196}
197
198static unsigned long s3c2443_armclk_getrate(struct clk *clk)
199{
200 unsigned long rate = clk_get_rate(clk->parent);
201 unsigned long clkcon0;
202 int val;
203
204 if (!nr_armdiv || !armdivmask)
205 return -EINVAL;
206
207 clkcon0 = __raw_readl(S3C2443_CLKDIV0);
208 clkcon0 &= armdivmask;
209 val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
210
211 return rate / armdiv[val];
212}
213
214static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
215{
216 unsigned long parent = clk_get_rate(clk->parent);
217 unsigned long calc;
218 unsigned div;
219 unsigned best = 256; /* bigger than any value */
220 int ptr;
221 int val = -1;
222
223 if (!nr_armdiv || !armdivmask)
224 return -EINVAL;
225
226 for (ptr = 0; ptr < nr_armdiv; ptr++) {
227 div = armdiv[ptr];
228 if (div) {
229 /* cpufreq provides 266mhz as 266666000 not 266666666 */
230 calc = (parent / div / 1000) * 1000;
231 if (calc <= rate && div < best) {
232 best = div;
233 val = ptr;
234 }
235 }
236 }
237
238 if (val >= 0) {
239 unsigned long clkcon0;
240
241 clkcon0 = __raw_readl(S3C2443_CLKDIV0);
242 clkcon0 &= ~armdivmask;
243 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
244 __raw_writel(clkcon0, S3C2443_CLKDIV0);
245 }
246
247 return (val == -1) ? -EINVAL : 0;
248}
249
250static struct clk clk_armdiv = {
251 .name = "armdiv",
252 .parent = &clk_msysclk.clk,
253 .ops = &(struct clk_ops) {
254 .round_rate = s3c2443_armclk_roundrate,
255 .get_rate = s3c2443_armclk_getrate,
256 .set_rate = s3c2443_armclk_setrate,
257 },
258};
259
260/* armclk
261 *
262 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
263 */
264
265static struct clk *clk_arm_sources[] = {
266 [0] = &clk_armdiv,
267 [1] = &clk_h,
268};
269
270static struct clksrc_clk clk_arm = {
271 .clk = {
272 .name = "armclk",
273 },
274 .sources = &(struct clksrc_sources) {
275 .sources = clk_arm_sources,
276 .nr_sources = ARRAY_SIZE(clk_arm_sources),
277 },
278 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
279};
280
163/* usbhost 281/* usbhost
164 * 282 *
165 * usb host bus-clock, usually 48MHz to provide USB bus clock timing 283 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
@@ -205,9 +323,64 @@ static struct clksrc_clk clksrc_clks[] = {
205 }, 323 },
206}; 324};
207 325
326static struct clk clk_i2s_ext = {
327 .name = "i2s-ext",
328};
329
330/* i2s_eplldiv
331 *
332 * This clock is the output from the I2S divisor of ESYSCLK, and is separate
333 * from the mux that comes after it (cannot merge into one single clock)
334*/
335
336static struct clksrc_clk clk_i2s_eplldiv = {
337 .clk = {
338 .name = "i2s-eplldiv",
339 .parent = &clk_esysclk.clk,
340 },
341 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
342};
343
344/* i2s-ref
345 *
346 * i2s bus reference clock, selectable from external, esysclk or epllref
347 *
348 * Note, this used to be two clocks, but was compressed into one.
349*/
350
351static struct clk *clk_i2s_srclist[] = {
352 [0] = &clk_i2s_eplldiv.clk,
353 [1] = &clk_i2s_ext,
354 [2] = &clk_epllref.clk,
355 [3] = &clk_epllref.clk,
356};
357
358static struct clksrc_clk clk_i2s = {
359 .clk = {
360 .name = "i2s-if",
361 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
362 .enable = s3c2443_clkcon_enable_s,
363
364 },
365 .sources = &(struct clksrc_sources) {
366 .sources = clk_i2s_srclist,
367 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
368 },
369 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
370};
208 371
209static struct clk init_clocks_off[] = { 372static struct clk init_clocks_off[] = {
210 { 373 {
374 .name = "iis",
375 .parent = &clk_p,
376 .enable = s3c2443_clkcon_enable_p,
377 .ctrlbit = S3C2443_PCLKCON_IIS,
378 }, {
379 .name = "hsspi",
380 .parent = &clk_p,
381 .enable = s3c2443_clkcon_enable_p,
382 .ctrlbit = S3C2443_PCLKCON_HSSPI,
383 }, {
211 .name = "adc", 384 .name = "adc",
212 .parent = &clk_p, 385 .parent = &clk_p,
213 .enable = s3c2443_clkcon_enable_p, 386 .enable = s3c2443_clkcon_enable_p,
@@ -253,6 +426,7 @@ static struct clk init_clocks[] = {
253 .ctrlbit = S3C2443_HCLKCON_DMA5, 426 .ctrlbit = S3C2443_HCLKCON_DMA5,
254 }, { 427 }, {
255 .name = "hsmmc", 428 .name = "hsmmc",
429 .devname = "s3c-sdhci.1",
256 .parent = &clk_h, 430 .parent = &clk_h,
257 .enable = s3c2443_clkcon_enable_h, 431 .enable = s3c2443_clkcon_enable_h,
258 .ctrlbit = S3C2443_HCLKCON_HSMMC, 432 .ctrlbit = S3C2443_HCLKCON_HSMMC,
@@ -347,8 +521,7 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
347 521
348/* EPLLCON compatible enough to get on/off information */ 522/* EPLLCON compatible enough to get on/off information */
349 523
350void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll, 524void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
351 fdiv_fn get_fdiv)
352{ 525{
353 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); 526 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
354 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); 527 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
@@ -368,7 +541,7 @@ void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll,
368 pll = get_mpll(mpllcon, xtal); 541 pll = get_mpll(mpllcon, xtal);
369 clk_msysclk.clk.rate = pll; 542 clk_msysclk.clk.rate = pll;
370 543
371 fclk = pll / get_fdiv(clkdiv0); 544 fclk = clk_get_rate(&clk_armdiv);
372 hclk = s3c2443_prediv_getrate(&clk_prediv); 545 hclk = s3c2443_prediv_getrate(&clk_prediv);
373 hclk /= s3c2443_get_hdiv(clkdiv0); 546 hclk /= s3c2443_get_hdiv(clkdiv0);
374 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); 547 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
@@ -403,20 +576,29 @@ static struct clk *clks[] __initdata = {
403 &clk_ext, 576 &clk_ext,
404 &clk_epll, 577 &clk_epll,
405 &clk_usb_bus, 578 &clk_usb_bus,
579 &clk_armdiv,
406}; 580};
407 581
408static struct clksrc_clk *clksrcs[] __initdata = { 582static struct clksrc_clk *clksrcs[] __initdata = {
583 &clk_i2s_eplldiv,
584 &clk_i2s,
409 &clk_usb_bus_host, 585 &clk_usb_bus_host,
410 &clk_epllref, 586 &clk_epllref,
411 &clk_esysclk, 587 &clk_esysclk,
412 &clk_msysclk, 588 &clk_msysclk,
589 &clk_arm,
413}; 590};
414 591
415void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, 592void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
416 fdiv_fn get_fdiv) 593 unsigned int *divs, int nr_divs,
594 int divmask)
417{ 595{
418 int ptr; 596 int ptr;
419 597
598 armdiv = divs;
599 nr_armdiv = nr_divs;
600 armdivmask = divmask;
601
420 /* s3c2443 parents h and p clocks from prediv */ 602 /* s3c2443 parents h and p clocks from prediv */
421 clk_h.parent = &clk_prediv; 603 clk_h.parent = &clk_prediv;
422 clk_p.parent = &clk_prediv; 604 clk_p.parent = &clk_prediv;
@@ -437,5 +619,5 @@ void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
437 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 619 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
438 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 620 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
439 621
440 s3c2443_common_setup_clocks(get_mpll, get_fdiv); 622 s3c2443_common_setup_clocks(get_mpll);
441} 623}