blob: 52c032c9d7bcdc8f013b0a4fef120ff6c19763aa [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 *clkset_spi_list[] = {
450 &clk_mout_epll.clk,
451 &clk_dout_mpll2,
452 &clk_fin_epll,
453 &clk_mout_hpll.clk,
454};
455
Ben Dooks45426462010-01-12 12:19:28 +0900456static struct clksrc_sources clkset_spi = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100457 .sources = clkset_spi_list,
458 .nr_sources = ARRAY_SIZE(clkset_spi_list),
459};
460
461static struct clksrc_clk clk_spi0 = {
462 .clk = {
463 .name = "spi_bus",
464 .id = 0,
465 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
466 .enable = s5pc100_sclk0_ctrl,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000467
Kyungmin Parkff916f22009-11-17 08:41:13 +0100468 },
Ben Dooks45426462010-01-12 12:19:28 +0900469 .sources = &clkset_spi,
470 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 4, .size = 4, },
471 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 4, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100472};
473
474static struct clksrc_clk clk_spi1 = {
475 .clk = {
476 .name = "spi_bus",
477 .id = 1,
478 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
479 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100480 },
Ben Dooks45426462010-01-12 12:19:28 +0900481 .sources = &clkset_spi,
482 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 8, .size = 4, },
483 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 8, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100484};
485
486static struct clksrc_clk clk_spi2 = {
487 .clk = {
488 .name = "spi_bus",
489 .id = 2,
490 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
491 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100492 },
Ben Dooks45426462010-01-12 12:19:28 +0900493 .sources = &clkset_spi,
494 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 12, .size = 4, },
495 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 12, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100496};
497
498static struct clk *clkset_uart_list[] = {
499 &clk_mout_epll.clk,
500 &clk_dout_mpll,
501};
502
Ben Dooks45426462010-01-12 12:19:28 +0900503static struct clksrc_sources clkset_uart = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100504 .sources = clkset_uart_list,
505 .nr_sources = ARRAY_SIZE(clkset_uart_list),
506};
507
Byungho Minc1cc3db2009-06-23 21:39:56 +0900508static struct clksrc_clk clk_uart_uclk1 = {
509 .clk = {
510 .name = "uclk1",
511 .id = -1,
512 .ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100513 .enable = s5pc100_sclk0_ctrl,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900514 },
Ben Dooks45426462010-01-12 12:19:28 +0900515 .sources = &clkset_uart,
516 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 0, .size = 3, },
517 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 0, .size = 1, },
Byungho Minc1cc3db2009-06-23 21:39:56 +0900518};
519
Kyungmin Parkff916f22009-11-17 08:41:13 +0100520static struct clk clk_iis_cd0 = {
521 .name = "iis_cdclk0",
522 .id = -1,
523};
524
525static struct clk clk_iis_cd1 = {
526 .name = "iis_cdclk1",
527 .id = -1,
528};
529
530static struct clk clk_iis_cd2 = {
531 .name = "iis_cdclk2",
532 .id = -1,
533};
534
535static struct clk clk_pcm_cd0 = {
536 .name = "pcm_cdclk0",
537 .id = -1,
538};
539
540static struct clk clk_pcm_cd1 = {
541 .name = "pcm_cdclk1",
542 .id = -1,
543};
544
545static struct clk *clkset_audio0_list[] = {
546 &clk_mout_epll.clk,
547 &clk_dout_mpll,
548 &clk_fin_epll,
549 &clk_iis_cd0,
550 &clk_pcm_cd0,
551 &clk_mout_hpll.clk,
552};
553
Ben Dooks45426462010-01-12 12:19:28 +0900554static struct clksrc_sources clkset_audio0 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100555 .sources = clkset_audio0_list,
556 .nr_sources = ARRAY_SIZE(clkset_audio0_list),
557};
558
559static struct clksrc_clk clk_audio0 = {
560 .clk = {
561 .name = "audio-bus",
562 .id = 0,
563 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
564 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100565 },
Ben Dooks45426462010-01-12 12:19:28 +0900566 .sources = &clkset_audio0,
567 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 12, .size = 4, },
568 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 12, .size = 3, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100569};
570
571static struct clk *clkset_audio1_list[] = {
572 &clk_mout_epll.clk,
573 &clk_dout_mpll,
574 &clk_fin_epll,
575 &clk_iis_cd1,
576 &clk_pcm_cd1,
577 &clk_mout_hpll.clk,
578};
579
Ben Dooks45426462010-01-12 12:19:28 +0900580static struct clksrc_sources clkset_audio1 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100581 .sources = clkset_audio1_list,
582 .nr_sources = ARRAY_SIZE(clkset_audio1_list),
583};
584
585static struct clksrc_clk clk_audio1 = {
586 .clk = {
587 .name = "audio-bus",
588 .id = 1,
589 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
590 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100591 },
Ben Dooks45426462010-01-12 12:19:28 +0900592 .sources = &clkset_audio1,
593 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 16, .size = 4, },
594 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 16, .size = 3, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100595};
596
597static struct clk *clkset_audio2_list[] = {
598 &clk_mout_epll.clk,
599 &clk_dout_mpll,
600 &clk_fin_epll,
601 &clk_iis_cd2,
602 &clk_mout_hpll.clk,
603};
604
Ben Dooks45426462010-01-12 12:19:28 +0900605static struct clksrc_sources clkset_audio2 = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100606 .sources = clkset_audio2_list,
607 .nr_sources = ARRAY_SIZE(clkset_audio2_list),
608};
609
610static struct clksrc_clk clk_audio2 = {
611 .clk = {
612 .name = "audio-bus",
613 .id = 2,
614 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
615 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100616 },
Ben Dooks45426462010-01-12 12:19:28 +0900617 .sources = &clkset_audio2,
618 .reg_div = { .reg = S5PC100_CLKDIV4, .shift = 20, .size = 4, },
619 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 20, .size = 3, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100620};
621
622static struct clk *clkset_spdif_list[] = {
623 &clk_audio0.clk,
624 &clk_audio1.clk,
625 &clk_audio2.clk,
626};
627
Ben Dooks45426462010-01-12 12:19:28 +0900628static struct clksrc_sources clkset_spdif = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100629 .sources = clkset_spdif_list,
630 .nr_sources = ARRAY_SIZE(clkset_spdif_list),
631};
632
633static struct clksrc_clk clk_spdif = {
634 .clk = {
635 .name = "spdif",
636 .id = -1,
637 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100638 .sources = &clkset_spdif,
Ben Dooks45426462010-01-12 12:19:28 +0900639 .reg_src = { .reg = S5PC100_CLKSRC3, .shift = 24, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100640};
641
642static struct clk *clkset_lcd_fimc_list[] = {
643 &clk_mout_epll.clk,
644 &clk_dout_mpll,
645 &clk_mout_hpll.clk,
646 &clk_vclk_54m,
647};
648
Ben Dooks45426462010-01-12 12:19:28 +0900649static struct clksrc_sources clkset_lcd_fimc = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100650 .sources = clkset_lcd_fimc_list,
651 .nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list),
652};
653
654static struct clksrc_clk clk_lcd = {
655 .clk = {
656 .name = "lcd",
657 .id = -1,
658 .ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
659 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100660 },
Ben Dooks45426462010-01-12 12:19:28 +0900661 .sources = &clkset_lcd_fimc,
662 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 12, .size = 4, },
663 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 12, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100664};
665
666static struct clksrc_clk clk_fimc0 = {
667 .clk = {
668 .name = "fimc",
669 .id = 0,
670 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
671 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100672 },
Ben Dooks45426462010-01-12 12:19:28 +0900673 .sources = &clkset_lcd_fimc,
674 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 16, .size = 4, },
675 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 16, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100676};
677
678static struct clksrc_clk clk_fimc1 = {
679 .clk = {
680 .name = "fimc",
681 .id = 1,
682 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
683 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100684 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100685 .sources = &clkset_lcd_fimc,
Ben Dooks45426462010-01-12 12:19:28 +0900686 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 20, .size = 4, },
687 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 20, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100688};
689
690static struct clksrc_clk clk_fimc2 = {
691 .clk = {
692 .name = "fimc",
693 .id = 2,
694 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
695 .enable = s5pc100_sclk1_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100696 },
Ben Dooks45426462010-01-12 12:19:28 +0900697 .sources = &clkset_lcd_fimc,
698 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 24, .size = 4, },
699 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 24, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100700};
701
702static struct clk *clkset_mmc_list[] = {
703 &clk_mout_epll.clk,
704 &clk_dout_mpll,
705 &clk_fin_epll,
706 &clk_mout_hpll.clk ,
707};
708
Ben Dooks45426462010-01-12 12:19:28 +0900709static struct clksrc_sources clkset_mmc = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100710 .sources = clkset_mmc_list,
711 .nr_sources = ARRAY_SIZE(clkset_mmc_list),
712};
713
714static struct clksrc_clk clk_mmc0 = {
715 .clk = {
716 .name = "mmc_bus",
717 .id = 0,
718 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
719 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100720 },
Ben Dooks45426462010-01-12 12:19:28 +0900721 .sources = &clkset_mmc,
722 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 0, .size = 4, },
723 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 0, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100724};
725
726static struct clksrc_clk clk_mmc1 = {
727 .clk = {
728 .name = "mmc_bus",
729 .id = 1,
730 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
731 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100732 },
Ben Dooks45426462010-01-12 12:19:28 +0900733 .sources = &clkset_mmc,
734 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 4, .size = 4, },
735 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 4, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100736};
737
738static struct clksrc_clk clk_mmc2 = {
739 .clk = {
740 .name = "mmc_bus",
741 .id = 2,
742 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
743 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100744 },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100745 .sources = &clkset_mmc,
Ben Dooks45426462010-01-12 12:19:28 +0900746 .reg_div = { .reg = S5PC100_CLKDIV3, .shift = 8, .size = 4, },
747 .reg_src = { .reg = S5PC100_CLKSRC2, .shift = 8, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100748};
749
750
751static struct clk *clkset_usbhost_list[] = {
752 &clk_mout_epll.clk,
753 &clk_dout_mpll,
754 &clk_mout_hpll.clk,
755 &clk_48m,
756};
757
Ben Dooks45426462010-01-12 12:19:28 +0900758static struct clksrc_sources clkset_usbhost = {
Kyungmin Parkff916f22009-11-17 08:41:13 +0100759 .sources = clkset_usbhost_list,
760 .nr_sources = ARRAY_SIZE(clkset_usbhost_list),
761};
762
763static struct clksrc_clk clk_usbhost = {
764 .clk = {
765 .name = "usbhost",
766 .id = -1,
767 .ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
768 .enable = s5pc100_sclk0_ctrl,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100769 },
Ben Dooks45426462010-01-12 12:19:28 +0900770 .sources = &clkset_usbhost,
771 .reg_div = { .reg = S5PC100_CLKDIV2, .shift = 20, .size = 4, },
772 .reg_src = { .reg = S5PC100_CLKSRC1, .shift = 20, .size = 2, },
Kyungmin Parkff916f22009-11-17 08:41:13 +0100773};
774
Byungho Minc1cc3db2009-06-23 21:39:56 +0900775/* Clock initialisation code */
776
777static struct clksrc_clk *init_parents[] = {
778 &clk_mout_apll,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900779 &clk_mout_mpll,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100780 &clk_mout_am,
781 &clk_mout_onenand,
782 &clk_mout_epll,
783 &clk_mout_hpll,
784 &clk_spi0,
785 &clk_spi1,
786 &clk_spi2,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900787 &clk_uart_uclk1,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100788 &clk_audio0,
789 &clk_audio1,
790 &clk_audio2,
791 &clk_spdif,
792 &clk_lcd,
793 &clk_fimc0,
794 &clk_fimc1,
795 &clk_fimc2,
796 &clk_mmc0,
797 &clk_mmc1,
798 &clk_mmc2,
799 &clk_usbhost,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900800};
801
Byungho Minc1cc3db2009-06-23 21:39:56 +0900802#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
803
804void __init_or_cpufreq s5pc100_setup_clocks(void)
805{
806 struct clk *xtal_clk;
807 unsigned long xtal;
808 unsigned long armclk;
809 unsigned long hclkd0;
810 unsigned long hclk;
811 unsigned long pclkd0;
812 unsigned long pclk;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100813 unsigned long apll, mpll, epll, hpll;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900814 unsigned int ptr;
815 u32 clkdiv0, clkdiv1;
816
817 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
818
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100819 clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
820 clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900821
Kyungmin Parkff916f22009-11-17 08:41:13 +0100822 printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900823
824 xtal_clk = clk_get(NULL, "xtal");
825 BUG_ON(IS_ERR(xtal_clk));
826
827 xtal = clk_get_rate(xtal_clk);
828 clk_put(xtal_clk);
829
830 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
831
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100832 apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
833 mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
834 epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900835 hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
836
Kyungmin Parkff916f22009-11-17 08:41:13 +0100837 printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
838 ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
839 print_mhz(apll), print_mhz(mpll),
840 print_mhz(epll), print_mhz(hpll));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900841
Kyungmin Park9ebaf2f2009-11-17 08:41:12 +0100842 armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900843 armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
844 hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
845 pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
846 hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
847 pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
848
Kyungmin Parkff916f22009-11-17 08:41:13 +0100849 printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
850 " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
851 " PCLK=%ld.%03ld MHz\n",
852 print_mhz(armclk), print_mhz(hclkd0),
853 print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
Byungho Minc1cc3db2009-06-23 21:39:56 +0900854
855 clk_fout_apll.rate = apll;
856 clk_fout_mpll.rate = mpll;
857 clk_fout_epll.rate = epll;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100858 clk_fout_hpll.rate = hpll;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900859
860 clk_h.rate = hclk;
861 clk_p.rate = pclk;
Kyungmin Parkff916f22009-11-17 08:41:13 +0100862 clk_f.rate = armclk;
Byungho Minc1cc3db2009-06-23 21:39:56 +0900863
864 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
Ben Dooks45426462010-01-12 12:19:28 +0900865 s3c_set_clksrc(init_parents[ptr], true);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900866}
867
868static struct clk *clks[] __initdata = {
869 &clk_ext_xtal_mux,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100870 &clk_dout_apll,
871 &clk_dout_d0_bus,
872 &clk_dout_pclkd0,
873 &clk_dout_apll2,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100874 &clk_mout_am.clk,
875 &clk_dout_d1_bus,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100876 &clk_dout_pclkd1,
877 &clk_dout_mpll2,
878 &clk_dout_cam,
879 &clk_dout_mpll,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900880 &clk_fout_epll,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100881 &clk_iis_cd0,
882 &clk_iis_cd1,
883 &clk_iis_cd2,
884 &clk_pcm_cd0,
885 &clk_pcm_cd1,
Kyungmin Parkff916f22009-11-17 08:41:13 +0100886 &clk_arm,
Byungho Minc1cc3db2009-06-23 21:39:56 +0900887};
888
Ben Dooks45426462010-01-12 12:19:28 +0900889/* simplest change - will aggregate clocks later */
890static struct clksrc_clk *clks_src[] = {
891 &clk_mout_apll,
892 &clk_mout_mpll,
893 &clk_mout_onenand,
894 &clk_mout_epll,
895 &clk_spi0,
896 &clk_spi1,
897 &clk_spi2,
898 &clk_uart_uclk1,
899 &clk_audio0,
900 &clk_audio1,
901 &clk_audio2,
902 &clk_spdif,
903 &clk_lcd,
904 &clk_fimc0,
905 &clk_fimc1,
906 &clk_fimc2,
907 &clk_mmc0,
908 &clk_mmc1,
909 &clk_mmc2,
910 &clk_usbhost,
911};
912
Byungho Minc1cc3db2009-06-23 21:39:56 +0900913void __init s5pc100_register_clocks(void)
914{
915 struct clk *clkp;
916 int ret;
917 int ptr;
918
919 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
920 clkp = clks[ptr];
921 ret = s3c24xx_register_clock(clkp);
922 if (ret < 0) {
923 printk(KERN_ERR "Failed to register clock %s (%d)\n",
924 clkp->name, ret);
925 }
926 }
Ben Dooks45426462010-01-12 12:19:28 +0900927
928 for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++)
929 s3c_register_clksrc(clks_src[ptr], 1);
Byungho Minc1cc3db2009-06-23 21:39:56 +0900930}