blob: a9e37302f82fe6fc7a6e63c067ef99d2e5de020e [file] [log] [blame]
Byungho Minc1cc3db2009-06-23 21:39:56 +09001/* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
2 *
3 * Copyright 2009 Samsung Electronics, Co.
4 * Byungho Min <bhmin@samsung.com>
5 *
6 * S5PC100 based common clock support
7 *
8 * Based on plat-s3c64xx/s3c6400-clock.c
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/errno.h>
20#include <linux/err.h>
21#include <linux/clk.h>
22#include <linux/sysdev.h>
23#include <linux/io.h>
24
25#include <mach/hardware.h>
26#include <mach/map.h>
27
28#include <plat/cpu-freq.h>
29
30#include <plat/regs-clock.h>
31#include <plat/clock.h>
Ben Dooks45426462010-01-12 12:19:28 +090032#include <plat/clock-clksrc.h>
Byungho Minc1cc3db2009-06-23 21:39:56 +090033#include <plat/cpu.h>
34#include <plat/pll.h>
35#include <plat/devs.h>
36#include <plat/s5pc100.h>
37
38/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
39 * ext_xtal_mux for want of an actual name from the manual.
40*/
41
42static struct clk clk_ext_xtal_mux = {
43 .name = "ext_xtal",
44 .id = -1,
45};
46
47#define clk_fin_apll clk_ext_xtal_mux
48#define clk_fin_mpll clk_ext_xtal_mux
49#define clk_fin_epll clk_ext_xtal_mux
50#define clk_fin_hpll clk_ext_xtal_mux
51
52#define clk_fout_mpll clk_mpll
Kyungmin Parkff916f22009-11-17 08:41:13 +010053#define clk_vclk_54m clk_54m
Byungho Minc1cc3db2009-06-23 21:39:56 +090054
Kyungmin Parkff916f22009-11-17 08:41:13 +010055/* APLL */
Byungho Minc1cc3db2009-06-23 21:39:56 +090056static struct clk clk_fout_apll = {
57 .name = "fout_apll",
58 .id = -1,
Kyungmin Parkff916f22009-11-17 08:41:13 +010059 .rate = 27000000,
Byungho Minc1cc3db2009-06-23 21:39:56 +090060};
61
62static struct clk *clk_src_apll_list[] = {
63 [0] = &clk_fin_apll,
64 [1] = &clk_fout_apll,
65};
66
Ben Dooks45426462010-01-12 12:19:28 +090067static struct clksrc_sources clk_src_apll = {
Byungho Minc1cc3db2009-06-23 21:39:56 +090068 .sources = clk_src_apll_list,
69 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
70};
71
72static struct clksrc_clk clk_mout_apll = {
73 .clk = {
74 .name = "mout_apll",
75 .id = -1,
76 },
Byungho Minc1cc3db2009-06-23 21:39:56 +090077 .sources = &clk_src_apll,
Ben Dooks45426462010-01-12 12:19:28 +090078 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 0, .size = 1, },
Byungho Minc1cc3db2009-06-23 21:39:56 +090079};
80
Kyungmin Parkff916f22009-11-17 08:41:13 +010081static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
82{
83 unsigned long rate = clk_get_rate(clk->parent);
84 unsigned int ratio;
85
86 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
87 ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
88
89 return rate / (ratio + 1);
90}
91
92static struct clk clk_dout_apll = {
93 .name = "dout_apll",
94 .id = -1,
95 .parent = &clk_mout_apll.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +000096 .ops = &(struct clk_ops) {
97 .get_rate = s5pc100_clk_dout_apll_get_rate,
98 },
Kyungmin Parkff916f22009-11-17 08:41:13 +010099};
100
101static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
102{
103 unsigned long rate = clk_get_rate(clk->parent);
104 unsigned int ratio;
105
106 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
107 ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
108
109 return rate / (ratio + 1);
110}
111
112static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
113 unsigned long rate)
114{
115 unsigned long parent = clk_get_rate(clk->parent);
116 u32 div;
117
118 if (parent < rate)
119 return rate;
120
121 div = (parent / rate) - 1;
122 if (div > S5PC100_CLKDIV0_ARM_MASK)
123 div = S5PC100_CLKDIV0_ARM_MASK;
124
125 return parent / (div + 1);
126}
127
128static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
129{
130 unsigned long parent = clk_get_rate(clk->parent);
131 u32 div;
132 u32 val;
133
134 if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
135 return -EINVAL;
136
137 rate = clk_round_rate(clk, rate);
138 div = clk_get_rate(clk->parent) / rate;
139
140 val = __raw_readl(S5PC100_CLKDIV0);
141 val &= S5PC100_CLKDIV0_ARM_MASK;
142 val |= (div - 1);
143 __raw_writel(val, S5PC100_CLKDIV0);
144
145 return 0;
146}
147
148static struct clk clk_arm = {
149 .name = "armclk",
150 .id = -1,
151 .parent = &clk_dout_apll,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000152 .ops = &(struct clk_ops) {
153 .get_rate = s5pc100_clk_arm_get_rate,
154 .set_rate = s5pc100_clk_arm_set_rate,
155 .round_rate = s5pc100_clk_arm_round_rate,
156 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100157};
158
159static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
160{
161 unsigned long rate = clk_get_rate(clk->parent);
162 unsigned int ratio;
163
164 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
165 ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
166
167 return rate / (ratio + 1);
168}
169
170static struct clk clk_dout_d0_bus = {
171 .name = "dout_d0_bus",
172 .id = -1,
173 .parent = &clk_arm,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000174 .ops = &(struct clk_ops) {
175 .get_rate = s5pc100_clk_dout_d0_bus_get_rate,
176 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100177};
178
179static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
180{
181 unsigned long rate = clk_get_rate(clk->parent);
182 unsigned int ratio;
183
184 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
185 ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
186
187 return rate / (ratio + 1);
188}
189
190static struct clk clk_dout_pclkd0 = {
191 .name = "dout_pclkd0",
192 .id = -1,
193 .parent = &clk_dout_d0_bus,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000194 .ops = &(struct clk_ops) {
195 .get_rate = s5pc100_clk_dout_pclkd0_get_rate,
196 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100197};
198
199static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
200{
201 unsigned long rate = clk_get_rate(clk->parent);
202 unsigned int ratio;
203
204 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
205 ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
206
207 return rate / (ratio + 1);
208}
209
210static struct clk clk_dout_apll2 = {
211 .name = "dout_apll2",
212 .id = -1,
213 .parent = &clk_mout_apll.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000214 .ops = &(struct clk_ops) {
215 .get_rate = s5pc100_clk_dout_apll2_get_rate,
216 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100217};
218
219/* MPLL */
220static struct clk *clk_src_mpll_list[] = {
221 [0] = &clk_fin_mpll,
222 [1] = &clk_fout_mpll,
223};
224
Ben Dooks45426462010-01-12 12:19:28 +0900225static struct clksrc_sources clk_src_mpll = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100226 .sources = clk_src_mpll_list,
227 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
228};
229
230static struct clksrc_clk clk_mout_mpll = {
231 .clk = {
232 .name = "mout_mpll",
233 .id = -1,
234 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100235 .sources = &clk_src_mpll,
Ben Dooks45426462010-01-12 12:19:28 +0900236 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 4, .size = 1, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100237};
238
239static struct clk *clkset_am_list[] = {
240 [0] = &clk_mout_mpll.clk,
241 [1] = &clk_dout_apll2,
242};
243
Ben Dooks45426462010-01-12 12:19:28 +0900244static struct clksrc_sources clk_src_am = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100245 .sources = clkset_am_list,
246 .nr_sources = ARRAY_SIZE(clkset_am_list),
247};
248
249static struct clksrc_clk clk_mout_am = {
250 .clk = {
251 .name = "mout_am",
252 .id = -1,
253 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100254 .sources = &clk_src_am,
Ben Dooks45426462010-01-12 12:19:28 +0900255 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 16, .size = 1, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100256};
257
258static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
259{
260 unsigned long rate = clk_get_rate(clk->parent);
261 unsigned int ratio;
262
263 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
264
265 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
266 ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
267
268 return rate / (ratio + 1);
269}
270
271static struct clk clk_dout_d1_bus = {
272 .name = "dout_d1_bus",
273 .id = -1,
274 .parent = &clk_mout_am.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000275 .ops = &(struct clk_ops) {
276 .get_rate = s5pc100_clk_dout_d1_bus_get_rate,
277 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100278};
279
280static struct clk *clkset_onenand_list[] = {
281 [0] = &clk_dout_d0_bus,
282 [1] = &clk_dout_d1_bus,
283};
284
Ben Dooks45426462010-01-12 12:19:28 +0900285static struct clksrc_sources clk_src_onenand = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100286 .sources = clkset_onenand_list,
287 .nr_sources = ARRAY_SIZE(clkset_onenand_list),
288};
289
290static struct clksrc_clk clk_mout_onenand = {
291 .clk = {
292 .name = "mout_onenand",
293 .id = -1,
294 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100295 .sources = &clk_src_onenand,
Ben Dooks45426462010-01-12 12:19:28 +0900296 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 24, .size = 1, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100297};
298
299static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
300{
301 unsigned long rate = clk_get_rate(clk->parent);
302 unsigned int ratio;
303
304 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
305
306 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
307 ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
308
309 return rate / (ratio + 1);
310}
311
312static struct clk clk_dout_pclkd1 = {
313 .name = "dout_pclkd1",
314 .id = -1,
315 .parent = &clk_dout_d1_bus,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000316 .ops = &(struct clk_ops) {
317 .get_rate = s5pc100_clk_dout_pclkd1_get_rate,
318 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100319};
320
321static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
322{
323 unsigned long rate = clk_get_rate(clk->parent);
324 unsigned int ratio;
325
326 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
327
328 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
329 ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
330
331 return rate / (ratio + 1);
332}
333
334static struct clk clk_dout_mpll2 = {
335 .name = "dout_mpll2",
336 .id = -1,
337 .parent = &clk_mout_am.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000338 .ops = &(struct clk_ops) {
339 .get_rate = s5pc100_clk_dout_mpll2_get_rate,
340 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100341};
342
343static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
344{
345 unsigned long rate = clk_get_rate(clk->parent);
346 unsigned int ratio;
347
348 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
349
350 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
351 ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
352
353 return rate / (ratio + 1);
354}
355
356static struct clk clk_dout_cam = {
357 .name = "dout_cam",
358 .id = -1,
359 .parent = &clk_dout_mpll2,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000360 .ops = &(struct clk_ops) {
361 .get_rate = s5pc100_clk_dout_cam_get_rate,
362 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100363};
364
365static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
366{
367 unsigned long rate = clk_get_rate(clk->parent);
368 unsigned int ratio;
369
370 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
371
372 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
373 ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
374
375 return rate / (ratio + 1);
376}
377
378static struct clk clk_dout_mpll = {
379 .name = "dout_mpll",
380 .id = -1,
381 .parent = &clk_mout_am.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000382 .ops = &(struct clk_ops) {
383 .get_rate = s5pc100_clk_dout_mpll_get_rate,
384 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100385};
386
387/* EPLL */
Byungho Minc1cc3db2009-06-23 21:39:56 +0900388static struct clk clk_fout_epll = {
389 .name = "fout_epll",
390 .id = -1,
391};
392
393static struct clk *clk_src_epll_list[] = {
394 [0] = &clk_fin_epll,
395 [1] = &clk_fout_epll,
396};
397
Ben Dooks45426462010-01-12 12:19:28 +0900398static struct clksrc_sources clk_src_epll = {
Byungho Minc1cc3db2009-06-23 21:39:56 +0900399 .sources = clk_src_epll_list,
400 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
401};
402
403static struct clksrc_clk clk_mout_epll = {
404 .clk = {
405 .name = "mout_epll",
406 .id = -1,
407 },
Ben Dooks45426462010-01-12 12:19:28 +0900408 .sources = &clk_src_epll,
409 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 8, .size = 1, },
Byungho Minc1cc3db2009-06-23 21:39:56 +0900410};
411
Kyungmin Parkff916f22009-11-17 08:41:13 +0100412/* HPLL */
413static struct clk clk_fout_hpll = {
414 .name = "fout_hpll",
415 .id = -1,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900416};
417
Kyungmin Parkff916f22009-11-17 08:41:13 +0100418static struct clk *clk_src_hpll_list[] = {
419 [0] = &clk_27m,
420 [1] = &clk_fout_hpll,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900421};
422
Ben Dooks45426462010-01-12 12:19:28 +0900423static struct clksrc_sources clk_src_hpll = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100424 .sources = clk_src_hpll_list,
425 .nr_sources = ARRAY_SIZE(clk_src_hpll_list),
426};
427
428static struct clksrc_clk clk_mout_hpll = {
429 .clk = {
430 .name = "mout_hpll",
Byungho Minc1cc3db2009-06-23 21:39:56 +0900431 .id = -1,
432 },
Ben Dooks45426462010-01-12 12:19:28 +0900433 .sources = &clk_src_hpll,
434 .reg_src = { .reg = S5PC100_CLKSRC0, .shift = 12, .size = 1, },
Byungho Minc1cc3db2009-06-23 21:39:56 +0900435};
436
Kyungmin Parkff916f22009-11-17 08:41:13 +0100437/* Peripherals */
438/*
439 * The peripheral clocks are all controlled via clocksource followed
440 * by an optional divider and gate stage. We currently roll this into
441 * one clock which hides the intermediate clock from the mux.
442 *
443 * Note, the JPEG clock can only be an even divider...
444 *
445 * The scaler and LCD clocks depend on the S5PC100 version, and also
446 * have a common parent divisor so are not included here.
447 */
Byungho Minc1cc3db2009-06-23 21:39:56 +0900448
Kyungmin Parkff916f22009-11-17 08:41:13 +0100449static struct clk clk_iis_cd0 = {
450 .name = "iis_cdclk0",
451 .id = -1,
452};
453
454static struct clk clk_iis_cd1 = {
455 .name = "iis_cdclk1",
456 .id = -1,
457};
458
459static struct clk clk_iis_cd2 = {
460 .name = "iis_cdclk2",
461 .id = -1,
462};
463
464static struct clk clk_pcm_cd0 = {
465 .name = "pcm_cdclk0",
466 .id = -1,
467};
468
469static struct clk clk_pcm_cd1 = {
470 .name = "pcm_cdclk1",
471 .id = -1,
472};
473
474static struct clk *clkset_audio0_list[] = {
475 &clk_mout_epll.clk,
476 &clk_dout_mpll,
477 &clk_fin_epll,
478 &clk_iis_cd0,
479 &clk_pcm_cd0,
480 &clk_mout_hpll.clk,
481};
482
Ben Dooks45426462010-01-12 12:19:28 +0900483static struct clksrc_sources clkset_audio0 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100484 .sources = clkset_audio0_list,
485 .nr_sources = ARRAY_SIZE(clkset_audio0_list),
486};
487
Ben Dooks1d026d92010-01-12 12:39:58 +0900488static struct clk *clkset_spi_list[] = {
489 &clk_mout_epll.clk,
490 &clk_dout_mpll2,
491 &clk_fin_epll,
492 &clk_mout_hpll.clk,
493};
494
495static struct clksrc_sources clkset_spi = {
496 .sources = clkset_spi_list,
497 .nr_sources = ARRAY_SIZE(clkset_spi_list),
498};
499
500static struct clk *clkset_uart_list[] = {
501 &clk_mout_epll.clk,
502 &clk_dout_mpll,
503};
504
505static struct clksrc_sources clkset_uart = {
506 .sources = clkset_uart_list,
507 .nr_sources = ARRAY_SIZE(clkset_uart_list),
Kyungmin Parkff916f22009-11-17 08:41:13 +0100508};
509
510static struct clk *clkset_audio1_list[] = {
511 &clk_mout_epll.clk,
512 &clk_dout_mpll,
513 &clk_fin_epll,
514 &clk_iis_cd1,
515 &clk_pcm_cd1,
516 &clk_mout_hpll.clk,
517};
518
Ben Dooks45426462010-01-12 12:19:28 +0900519static struct clksrc_sources clkset_audio1 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100520 .sources = clkset_audio1_list,
521 .nr_sources = ARRAY_SIZE(clkset_audio1_list),
522};
523
Kyungmin Parkff916f22009-11-17 08:41:13 +0100524static struct clk *clkset_audio2_list[] = {
525 &clk_mout_epll.clk,
526 &clk_dout_mpll,
527 &clk_fin_epll,
528 &clk_iis_cd2,
529 &clk_mout_hpll.clk,
530};
531
Ben Dooks45426462010-01-12 12:19:28 +0900532static struct clksrc_sources clkset_audio2 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100533 .sources = clkset_audio2_list,
534 .nr_sources = ARRAY_SIZE(clkset_audio2_list),
535};
536
Ben Dooks1d026d92010-01-12 12:39:58 +0900537static struct clksrc_clk clk_audio0;
538static struct clksrc_clk clk_audio1;
539static struct clksrc_clk clk_audio2;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100540
541static struct clk *clkset_spdif_list[] = {
542 &clk_audio0.clk,
543 &clk_audio1.clk,
544 &clk_audio2.clk,
545};
546
Ben Dooks45426462010-01-12 12:19:28 +0900547static struct clksrc_sources clkset_spdif = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100548 .sources = clkset_spdif_list,
549 .nr_sources = ARRAY_SIZE(clkset_spdif_list),
550};
551
Kyungmin Parkff916f22009-11-17 08:41:13 +0100552static struct clk *clkset_lcd_fimc_list[] = {
553 &clk_mout_epll.clk,
554 &clk_dout_mpll,
555 &clk_mout_hpll.clk,
556 &clk_vclk_54m,
557};
558
Ben Dooks45426462010-01-12 12:19:28 +0900559static struct clksrc_sources clkset_lcd_fimc = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100560 .sources = clkset_lcd_fimc_list,
561 .nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list),
562};
563
Ben Dooks1d026d92010-01-12 12:39:58 +0900564static struct clk *clkset_mmc_list[] = {
565 &clk_mout_epll.clk,
566 &clk_dout_mpll,
567 &clk_fin_epll,
568 &clk_mout_hpll.clk ,
569};
570
571static struct clksrc_sources clkset_mmc = {
572 .sources = clkset_mmc_list,
573 .nr_sources = ARRAY_SIZE(clkset_mmc_list),
574};
575
576static struct clk *clkset_usbhost_list[] = {
577 &clk_mout_epll.clk,
578 &clk_dout_mpll,
579 &clk_mout_hpll.clk,
580 &clk_48m,
581};
582
583static struct clksrc_sources clkset_usbhost = {
584 .sources = clkset_usbhost_list,
585 .nr_sources = ARRAY_SIZE(clkset_usbhost_list),
586};
587
588static struct clksrc_clk clk_spi0 = {
589 .clk = {
590 .name = "spi_bus",
591 .id = 0,
592 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
593 .enable = s5pc100_sclk0_ctrl,
594
595 },
596 .sources = &clkset_spi,
597 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 4, .size = 4, },
598 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 4, .size = 2, },
599};
600
601static struct clksrc_clk clk_spi1 = {
602 .clk = {
603 .name = "spi_bus",
604 .id = 1,
605 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
606 .enable = s5pc100_sclk0_ctrl,
607 },
608 .sources = &clkset_spi,
609 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 8, .size = 4, },
610 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 8, .size = 2, },
611};
612
613static struct clksrc_clk clk_spi2 = {
614 .clk = {
615 .name = "spi_bus",
616 .id = 2,
617 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
618 .enable = s5pc100_sclk0_ctrl,
619 },
620 .sources = &clkset_spi,
621 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 12, .size = 4, },
622 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 12, .size = 2, },
623};
624
625static struct clksrc_clk clk_uart_uclk1 = {
626 .clk = {
627 .name = "uclk1",
628 .id = -1,
629 .ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
630 .enable = s5pc100_sclk0_ctrl,
631 },
632 .sources = &clkset_uart,
633 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 0, .size = 3, },
634 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 0, .size = 1, },
635};
636
637static struct clksrc_clk clk_audio0 = {
638 .clk = {
639 .name = "audio-bus",
640 .id = 0,
641 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
642 .enable = s5pc100_sclk1_ctrl,
643 },
644 .sources = &clkset_audio0,
645 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 12, .size = 4, },
646 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 12, .size = 3, },
647};
648
649static struct clksrc_clk clk_audio1 = {
650 .clk = {
651 .name = "audio-bus",
652 .id = 1,
653 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
654 .enable = s5pc100_sclk1_ctrl,
655 },
656 .sources = &clkset_audio1,
657 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 16, .size = 4, },
658 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 16, .size = 3, },
659};
660
661
662static struct clksrc_clk clk_audio2 = {
663 .clk = {
664 .name = "audio-bus",
665 .id = 2,
666 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
667 .enable = s5pc100_sclk1_ctrl,
668 },
669 .sources = &clkset_audio2,
670 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 20, .size = 4, },
671 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 20, .size = 3, },
672};
673
674static struct clksrc_clk clk_spdif = {
675 .clk = {
676 .name = "spdif",
677 .id = -1,
678 },
679 .sources = &clkset_spdif,
680 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 24, .size = 2, },
681};
682
Kyungmin Parkff916f22009-11-17 08:41:13 +0100683static struct clksrc_clk clk_lcd = {
684 .clk = {
685 .name = "lcd",
686 .id = -1,
687 .ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
688 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100689 },
Ben Dooks45426462010-01-12 12:19:28 +0900690 .sources = &clkset_lcd_fimc,
691 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 12, .size = 4, },
692 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 12, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100693};
694
695static struct clksrc_clk clk_fimc0 = {
696 .clk = {
697 .name = "fimc",
698 .id = 0,
699 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
700 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100701 },
Ben Dooks45426462010-01-12 12:19:28 +0900702 .sources = &clkset_lcd_fimc,
703 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 16, .size = 4, },
704 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 16, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100705};
706
707static struct clksrc_clk clk_fimc1 = {
708 .clk = {
709 .name = "fimc",
710 .id = 1,
711 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
712 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100713 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100714 .sources = &clkset_lcd_fimc,
Ben Dooks45426462010-01-12 12:19:28 +0900715 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 20, .size = 4, },
716 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 20, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100717};
718
719static struct clksrc_clk clk_fimc2 = {
720 .clk = {
721 .name = "fimc",
722 .id = 2,
723 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
724 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100725 },
Ben Dooks45426462010-01-12 12:19:28 +0900726 .sources = &clkset_lcd_fimc,
727 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 24, .size = 4, },
728 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 24, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100729};
730
Kyungmin Parkff916f22009-11-17 08:41:13 +0100731static struct clksrc_clk clk_mmc0 = {
732 .clk = {
733 .name = "mmc_bus",
734 .id = 0,
735 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
736 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100737 },
Ben Dooks45426462010-01-12 12:19:28 +0900738 .sources = &clkset_mmc,
739 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 0, .size = 4, },
740 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 0, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100741};
742
743static struct clksrc_clk clk_mmc1 = {
744 .clk = {
745 .name = "mmc_bus",
746 .id = 1,
747 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
748 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100749 },
Ben Dooks45426462010-01-12 12:19:28 +0900750 .sources = &clkset_mmc,
751 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 4, .size = 4, },
752 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 4, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100753};
754
755static struct clksrc_clk clk_mmc2 = {
756 .clk = {
757 .name = "mmc_bus",
758 .id = 2,
759 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
760 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100761 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100762 .sources = &clkset_mmc,
Ben Dooks45426462010-01-12 12:19:28 +0900763 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 8, .size = 4, },
764 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 8, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100765};
766
Kyungmin Parkff916f22009-11-17 08:41:13 +0100767static struct clksrc_clk clk_usbhost = {
768 .clk = {
769 .name = "usbhost",
770 .id = -1,
771 .ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
772 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100773 },
Ben Dooks45426462010-01-12 12:19:28 +0900774 .sources = &clkset_usbhost,
775 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 20, .size = 4, },
776 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 20, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100777};
778
Byungho Minc1cc3db2009-06-23 21:39:56 +0900779/* Clock initialisation code */
780
781static struct clksrc_clk *init_parents[] = {
782 &clk_mout_apll,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900783 &clk_mout_mpll,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100784 &clk_mout_am,
785 &clk_mout_onenand,
786 &clk_mout_epll,
787 &clk_mout_hpll,
788 &clk_spi0,
789 &clk_spi1,
790 &clk_spi2,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900791 &clk_uart_uclk1,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100792 &clk_audio0,
793 &clk_audio1,
794 &clk_audio2,
795 &clk_spdif,
796 &clk_lcd,
797 &clk_fimc0,
798 &clk_fimc1,
799 &clk_fimc2,
800 &clk_mmc0,
801 &clk_mmc1,
802 &clk_mmc2,
803 &clk_usbhost,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900804};
805
Byungho Minc1cc3db2009-06-23 21:39:56 +0900806#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
807
808void __init_or_cpufreq s5pc100_setup_clocks(void)
809{
810 struct clk *xtal_clk;
811 unsigned long xtal;
812 unsigned long armclk;
813 unsigned long hclkd0;
814 unsigned long hclk;
815 unsigned long pclkd0;
816 unsigned long pclk;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100817 unsigned long apll, mpll, epll, hpll;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900818 unsigned int ptr;
819 u32 clkdiv0, clkdiv1;
820
821 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
822
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100823 clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
824 clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900825
Kyungmin Parkff916f22009-11-17 08:41:13 +0100826 printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900827
828 xtal_clk = clk_get(NULL, "xtal");
829 BUG_ON(IS_ERR(xtal_clk));
830
831 xtal = clk_get_rate(xtal_clk);
832 clk_put(xtal_clk);
833
834 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
835
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100836 apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
837 mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
838 epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900839 hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
840
Kyungmin Parkff916f22009-11-17 08:41:13 +0100841 printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
842 ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
843 print_mhz(apll), print_mhz(mpll),
844 print_mhz(epll), print_mhz(hpll));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900845
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100846 armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900847 armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
848 hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
849 pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
850 hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
851 pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
852
Kyungmin Parkff916f22009-11-17 08:41:13 +0100853 printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
854 " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
855 " PCLK=%ld.%03ld MHz\n",
856 print_mhz(armclk), print_mhz(hclkd0),
857 print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900858
859 clk_fout_apll.rate = apll;
860 clk_fout_mpll.rate = mpll;
861 clk_fout_epll.rate = epll;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100862 clk_fout_hpll.rate = hpll;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900863
864 clk_h.rate = hclk;
865 clk_p.rate = pclk;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100866 clk_f.rate = armclk;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900867
868 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
Ben Dooks45426462010-01-12 12:19:28 +0900869 s3c_set_clksrc(init_parents[ptr], true);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900870}
871
872static struct clk *clks[] __initdata = {
873 &clk_ext_xtal_mux,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100874 &clk_dout_apll,
875 &clk_dout_d0_bus,
876 &clk_dout_pclkd0,
877 &clk_dout_apll2,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100878 &clk_mout_am.clk,
879 &clk_dout_d1_bus,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100880 &clk_dout_pclkd1,
881 &clk_dout_mpll2,
882 &clk_dout_cam,
883 &clk_dout_mpll,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900884 &clk_fout_epll,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100885 &clk_iis_cd0,
886 &clk_iis_cd1,
887 &clk_iis_cd2,
888 &clk_pcm_cd0,
889 &clk_pcm_cd1,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100890 &clk_arm,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900891};
892
Ben Dooks45426462010-01-12 12:19:28 +0900893/* simplest change - will aggregate clocks later */
894static struct clksrc_clk *clks_src[] = {
895 &clk_mout_apll,
896 &clk_mout_mpll,
897 &clk_mout_onenand,
898 &clk_mout_epll,
899 &clk_spi0,
900 &clk_spi1,
901 &clk_spi2,
902 &clk_uart_uclk1,
903 &clk_audio0,
904 &clk_audio1,
905 &clk_audio2,
906 &clk_spdif,
907 &clk_lcd,
908 &clk_fimc0,
909 &clk_fimc1,
910 &clk_fimc2,
911 &clk_mmc0,
912 &clk_mmc1,
913 &clk_mmc2,
914 &clk_usbhost,
915};
916
Byungho Minc1cc3db2009-06-23 21:39:56 +0900917void __init s5pc100_register_clocks(void)
918{
919 struct clk *clkp;
920 int ret;
921 int ptr;
922
923 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
924 clkp = clks[ptr];
925 ret = s3c24xx_register_clock(clkp);
926 if (ret < 0) {
927 printk(KERN_ERR "Failed to register clock %s (%d)\n",
928 clkp->name, ret);
929 }
930 }
Ben Dooks45426462010-01-12 12:19:28 +0900931
932 for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++)
933 s3c_register_clksrc(clks_src[ptr], 1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900934}