diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:18:39 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:18:39 -0500 |
commit | 59b8175c771040afcd4ad67022b0cc80c216b866 (patch) | |
tree | 4ef5935bee1e342716d49b9d4b99e3fa835526e6 /arch/arm/mach-s3c2410/clock.c | |
parent | 920841d8d1d61bc12b43f95a579a5374f6d98f81 (diff) | |
parent | 3b0eb4a195a124567cd0dd6f700f8388def542c6 (diff) |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (117 commits)
[ARM] 4058/2: iop32x: set ->broken_parity_status on n2100 onboard r8169 ports
[ARM] 4140/1: AACI stability add ac97 timeout and retries
[ARM] 4139/1: AACI record support
[ARM] 4138/1: AACI: multiple channel support for IRQ handling
[ARM] 4211/1: Provide a defconfig for ns9xxx
[ARM] 4210/1: base for new machine type "NetSilicon NS9360"
[ARM] 4222/1: S3C2443: Remove reference to missing S3C2443_PM
[ARM] 4221/1: S3C2443: DMA support
[ARM] 4220/1: S3C24XX: DMA system initialised from sysdev
[ARM] 4219/1: S3C2443: DMA source definitions
[ARM] 4218/1: S3C2412: fix CONFIG_CPU_S3C2412_ONLY wrt to S3C2443
[ARM] 4217/1: S3C24XX: remove the dma channel show at startup
[ARM] 4090/2: avoid clash between PXA and SA1111 defines
[ARM] 4216/1: add .gitignore entries for ARM specific files
[ARM] 4214/2: S3C2410: Add Armzone QT2410
[ARM] 4215/1: s3c2410 usb device: per-platform vbus_draw
[ARM] 4213/1: S3C2410 - Update definition of ADCTSC_XY_PST
[ARM] 4098/1: ARM: rtc_lock only used with rtc_cmos
[ARM] 4137/1: Add kexec support
[ARM] 4201/1: SMP barriers pair needed for the secondary boot process
...
Fix up conflict due to typedef removal in sound/arm/aaci.h
Diffstat (limited to 'arch/arm/mach-s3c2410/clock.c')
-rw-r--r-- | arch/arm/mach-s3c2410/clock.c | 565 |
1 files changed, 196 insertions, 369 deletions
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index e13fb6778890..5b4831c4c1d8 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c | |||
@@ -1,15 +1,9 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/clock.c | 1 | /* linux/arch/arm/mach-s3c2410/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C24XX Core clock control support | 6 | * S3C2410,S3C2440,S3C2442 Clock control support |
7 | * | ||
8 | * Based on, and code from linux/arch/arm/mach-versatile/clock.c | ||
9 | ** | ||
10 | ** Copyright (C) 2004 ARM Limited. | ||
11 | ** Written by Deep Blue Solutions Limited. | ||
12 | * | ||
13 | * | 7 | * |
14 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -32,418 +26,251 @@ | |||
32 | #include <linux/list.h> | 26 | #include <linux/list.h> |
33 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
34 | #include <linux/err.h> | 28 | #include <linux/err.h> |
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/sysdev.h> | 29 | #include <linux/sysdev.h> |
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/ioport.h> | ||
39 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
40 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
41 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/serial_core.h> | ||
34 | |||
35 | #include <asm/mach/map.h> | ||
42 | 36 | ||
43 | #include <asm/hardware.h> | 37 | #include <asm/hardware.h> |
44 | #include <asm/irq.h> | ||
45 | #include <asm/io.h> | 38 | #include <asm/io.h> |
46 | 39 | ||
40 | #include <asm/arch/regs-serial.h> | ||
47 | #include <asm/arch/regs-clock.h> | 41 | #include <asm/arch/regs-clock.h> |
48 | #include <asm/arch/regs-gpio.h> | 42 | #include <asm/arch/regs-gpio.h> |
49 | 43 | ||
50 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/s3c2410.h> |
51 | #include "cpu.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
52 | 46 | #include <asm/plat-s3c24xx/cpu.h> | |
53 | /* clock information */ | ||
54 | 47 | ||
55 | static LIST_HEAD(clocks); | 48 | int s3c2410_clkcon_enable(struct clk *clk, int enable) |
56 | |||
57 | DEFINE_MUTEX(clocks_mutex); | ||
58 | |||
59 | /* enable and disable calls for use with the clk struct */ | ||
60 | |||
61 | static int clk_null_enable(struct clk *clk, int enable) | ||
62 | { | 49 | { |
63 | return 0; | 50 | unsigned int clocks = clk->ctrlbit; |
64 | } | 51 | unsigned long clkcon; |
65 | |||
66 | /* Clock API calls */ | ||
67 | 52 | ||
68 | struct clk *clk_get(struct device *dev, const char *id) | 53 | clkcon = __raw_readl(S3C2410_CLKCON); |
69 | { | ||
70 | struct clk *p; | ||
71 | struct clk *clk = ERR_PTR(-ENOENT); | ||
72 | int idno; | ||
73 | 54 | ||
74 | if (dev == NULL || dev->bus != &platform_bus_type) | 55 | if (enable) |
75 | idno = -1; | 56 | clkcon |= clocks; |
76 | else | 57 | else |
77 | idno = to_platform_device(dev)->id; | 58 | clkcon &= ~clocks; |
78 | |||
79 | mutex_lock(&clocks_mutex); | ||
80 | |||
81 | list_for_each_entry(p, &clocks, list) { | ||
82 | if (p->id == idno && | ||
83 | strcmp(id, p->name) == 0 && | ||
84 | try_module_get(p->owner)) { | ||
85 | clk = p; | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* check for the case where a device was supplied, but the | ||
91 | * clock that was being searched for is not device specific */ | ||
92 | |||
93 | if (IS_ERR(clk)) { | ||
94 | list_for_each_entry(p, &clocks, list) { | ||
95 | if (p->id == -1 && strcmp(id, p->name) == 0 && | ||
96 | try_module_get(p->owner)) { | ||
97 | clk = p; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | 59 | ||
103 | mutex_unlock(&clocks_mutex); | 60 | /* ensure none of the special function bits set */ |
104 | return clk; | 61 | clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); |
105 | } | ||
106 | 62 | ||
107 | void clk_put(struct clk *clk) | 63 | __raw_writel(clkcon, S3C2410_CLKCON); |
108 | { | ||
109 | module_put(clk->owner); | ||
110 | } | ||
111 | 64 | ||
112 | int clk_enable(struct clk *clk) | ||
113 | { | ||
114 | if (IS_ERR(clk) || clk == NULL) | ||
115 | return -EINVAL; | ||
116 | |||
117 | clk_enable(clk->parent); | ||
118 | |||
119 | mutex_lock(&clocks_mutex); | ||
120 | |||
121 | if ((clk->usage++) == 0) | ||
122 | (clk->enable)(clk, 1); | ||
123 | |||
124 | mutex_unlock(&clocks_mutex); | ||
125 | return 0; | 65 | return 0; |
126 | } | 66 | } |
127 | 67 | ||
128 | void clk_disable(struct clk *clk) | 68 | static int s3c2410_upll_enable(struct clk *clk, int enable) |
129 | { | ||
130 | if (IS_ERR(clk) || clk == NULL) | ||
131 | return; | ||
132 | |||
133 | mutex_lock(&clocks_mutex); | ||
134 | |||
135 | if ((--clk->usage) == 0) | ||
136 | (clk->enable)(clk, 0); | ||
137 | |||
138 | mutex_unlock(&clocks_mutex); | ||
139 | clk_disable(clk->parent); | ||
140 | } | ||
141 | |||
142 | |||
143 | unsigned long clk_get_rate(struct clk *clk) | ||
144 | { | ||
145 | if (IS_ERR(clk)) | ||
146 | return 0; | ||
147 | |||
148 | if (clk->rate != 0) | ||
149 | return clk->rate; | ||
150 | |||
151 | if (clk->get_rate != NULL) | ||
152 | return (clk->get_rate)(clk); | ||
153 | |||
154 | if (clk->parent != NULL) | ||
155 | return clk_get_rate(clk->parent); | ||
156 | |||
157 | return clk->rate; | ||
158 | } | ||
159 | |||
160 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
161 | { | ||
162 | if (!IS_ERR(clk) && clk->round_rate) | ||
163 | return (clk->round_rate)(clk, rate); | ||
164 | |||
165 | return rate; | ||
166 | } | ||
167 | |||
168 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | if (IS_ERR(clk)) | ||
173 | return -EINVAL; | ||
174 | |||
175 | mutex_lock(&clocks_mutex); | ||
176 | ret = (clk->set_rate)(clk, rate); | ||
177 | mutex_unlock(&clocks_mutex); | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | struct clk *clk_get_parent(struct clk *clk) | ||
183 | { | 69 | { |
184 | return clk->parent; | 70 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); |
185 | } | 71 | unsigned long orig = clkslow; |
186 | |||
187 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
188 | { | ||
189 | int ret = 0; | ||
190 | |||
191 | if (IS_ERR(clk)) | ||
192 | return -EINVAL; | ||
193 | |||
194 | mutex_lock(&clocks_mutex); | ||
195 | |||
196 | if (clk->set_parent) | ||
197 | ret = (clk->set_parent)(clk, parent); | ||
198 | |||
199 | mutex_unlock(&clocks_mutex); | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | EXPORT_SYMBOL(clk_get); | ||
205 | EXPORT_SYMBOL(clk_put); | ||
206 | EXPORT_SYMBOL(clk_enable); | ||
207 | EXPORT_SYMBOL(clk_disable); | ||
208 | EXPORT_SYMBOL(clk_get_rate); | ||
209 | EXPORT_SYMBOL(clk_round_rate); | ||
210 | EXPORT_SYMBOL(clk_set_rate); | ||
211 | EXPORT_SYMBOL(clk_get_parent); | ||
212 | EXPORT_SYMBOL(clk_set_parent); | ||
213 | |||
214 | /* base clocks */ | ||
215 | |||
216 | struct clk clk_xtal = { | ||
217 | .name = "xtal", | ||
218 | .id = -1, | ||
219 | .rate = 0, | ||
220 | .parent = NULL, | ||
221 | .ctrlbit = 0, | ||
222 | }; | ||
223 | |||
224 | struct clk clk_mpll = { | ||
225 | .name = "mpll", | ||
226 | .id = -1, | ||
227 | }; | ||
228 | |||
229 | struct clk clk_upll = { | ||
230 | .name = "upll", | ||
231 | .id = -1, | ||
232 | .parent = NULL, | ||
233 | .ctrlbit = 0, | ||
234 | }; | ||
235 | |||
236 | struct clk clk_f = { | ||
237 | .name = "fclk", | ||
238 | .id = -1, | ||
239 | .rate = 0, | ||
240 | .parent = &clk_mpll, | ||
241 | .ctrlbit = 0, | ||
242 | }; | ||
243 | |||
244 | struct clk clk_h = { | ||
245 | .name = "hclk", | ||
246 | .id = -1, | ||
247 | .rate = 0, | ||
248 | .parent = NULL, | ||
249 | .ctrlbit = 0, | ||
250 | }; | ||
251 | |||
252 | struct clk clk_p = { | ||
253 | .name = "pclk", | ||
254 | .id = -1, | ||
255 | .rate = 0, | ||
256 | .parent = NULL, | ||
257 | .ctrlbit = 0, | ||
258 | }; | ||
259 | |||
260 | struct clk clk_usb_bus = { | ||
261 | .name = "usb-bus", | ||
262 | .id = -1, | ||
263 | .rate = 0, | ||
264 | .parent = &clk_upll, | ||
265 | }; | ||
266 | |||
267 | /* clocks that could be registered by external code */ | ||
268 | |||
269 | static int s3c24xx_dclk_enable(struct clk *clk, int enable) | ||
270 | { | ||
271 | unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
272 | 72 | ||
273 | if (enable) | 73 | if (enable) |
274 | dclkcon |= clk->ctrlbit; | 74 | clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; |
275 | else | 75 | else |
276 | dclkcon &= ~clk->ctrlbit; | 76 | clkslow |= S3C2410_CLKSLOW_UCLK_OFF; |
277 | 77 | ||
278 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | 78 | __raw_writel(clkslow, S3C2410_CLKSLOW); |
279 | 79 | ||
280 | return 0; | 80 | /* if we started the UPLL, then allow to settle */ |
281 | } | ||
282 | 81 | ||
283 | static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) | 82 | if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) |
284 | { | 83 | udelay(200); |
285 | unsigned long dclkcon; | ||
286 | unsigned int uclk; | ||
287 | |||
288 | if (parent == &clk_upll) | ||
289 | uclk = 1; | ||
290 | else if (parent == &clk_p) | ||
291 | uclk = 0; | ||
292 | else | ||
293 | return -EINVAL; | ||
294 | |||
295 | clk->parent = parent; | ||
296 | |||
297 | dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
298 | |||
299 | if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { | ||
300 | if (uclk) | ||
301 | dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; | ||
302 | else | ||
303 | dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; | ||
304 | } else { | ||
305 | if (uclk) | ||
306 | dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; | ||
307 | else | ||
308 | dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; | ||
309 | } | ||
310 | |||
311 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | ||
312 | 84 | ||
313 | return 0; | 85 | return 0; |
314 | } | 86 | } |
315 | 87 | ||
316 | 88 | /* standard clock definitions */ | |
317 | static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) | 89 | |
318 | { | 90 | static struct clk init_clocks_disable[] = { |
319 | unsigned long mask; | 91 | { |
320 | unsigned long source; | 92 | .name = "nand", |
321 | 93 | .id = -1, | |
322 | /* calculate the MISCCR setting for the clock */ | 94 | .parent = &clk_h, |
323 | 95 | .enable = s3c2410_clkcon_enable, | |
324 | if (parent == &clk_xtal) | 96 | .ctrlbit = S3C2410_CLKCON_NAND, |
325 | source = S3C2410_MISCCR_CLK0_MPLL; | 97 | }, { |
326 | else if (parent == &clk_upll) | 98 | .name = "sdi", |
327 | source = S3C2410_MISCCR_CLK0_UPLL; | 99 | .id = -1, |
328 | else if (parent == &clk_f) | 100 | .parent = &clk_p, |
329 | source = S3C2410_MISCCR_CLK0_FCLK; | 101 | .enable = s3c2410_clkcon_enable, |
330 | else if (parent == &clk_h) | 102 | .ctrlbit = S3C2410_CLKCON_SDI, |
331 | source = S3C2410_MISCCR_CLK0_HCLK; | 103 | }, { |
332 | else if (parent == &clk_p) | 104 | .name = "adc", |
333 | source = S3C2410_MISCCR_CLK0_PCLK; | 105 | .id = -1, |
334 | else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) | 106 | .parent = &clk_p, |
335 | source = S3C2410_MISCCR_CLK0_DCLK0; | 107 | .enable = s3c2410_clkcon_enable, |
336 | else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) | 108 | .ctrlbit = S3C2410_CLKCON_ADC, |
337 | source = S3C2410_MISCCR_CLK0_DCLK0; | 109 | }, { |
338 | else | 110 | .name = "i2c", |
339 | return -EINVAL; | 111 | .id = -1, |
340 | 112 | .parent = &clk_p, | |
341 | clk->parent = parent; | 113 | .enable = s3c2410_clkcon_enable, |
342 | 114 | .ctrlbit = S3C2410_CLKCON_IIC, | |
343 | if (clk == &s3c24xx_dclk0) | 115 | }, { |
344 | mask = S3C2410_MISCCR_CLK0_MASK; | 116 | .name = "iis", |
345 | else { | 117 | .id = -1, |
346 | source <<= 4; | 118 | .parent = &clk_p, |
347 | mask = S3C2410_MISCCR_CLK1_MASK; | 119 | .enable = s3c2410_clkcon_enable, |
120 | .ctrlbit = S3C2410_CLKCON_IIS, | ||
121 | }, { | ||
122 | .name = "spi", | ||
123 | .id = -1, | ||
124 | .parent = &clk_p, | ||
125 | .enable = s3c2410_clkcon_enable, | ||
126 | .ctrlbit = S3C2410_CLKCON_SPI, | ||
348 | } | 127 | } |
349 | |||
350 | s3c2410_modify_misccr(mask, source); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* external clock definitions */ | ||
355 | |||
356 | struct clk s3c24xx_dclk0 = { | ||
357 | .name = "dclk0", | ||
358 | .id = -1, | ||
359 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
360 | .enable = s3c24xx_dclk_enable, | ||
361 | .set_parent = s3c24xx_dclk_setparent, | ||
362 | }; | ||
363 | |||
364 | struct clk s3c24xx_dclk1 = { | ||
365 | .name = "dclk1", | ||
366 | .id = -1, | ||
367 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
368 | .enable = s3c24xx_dclk_enable, | ||
369 | .set_parent = s3c24xx_dclk_setparent, | ||
370 | }; | 128 | }; |
371 | 129 | ||
372 | struct clk s3c24xx_clkout0 = { | 130 | static struct clk init_clocks[] = { |
373 | .name = "clkout0", | 131 | { |
374 | .id = -1, | 132 | .name = "lcd", |
375 | .set_parent = s3c24xx_clkout_setparent, | 133 | .id = -1, |
134 | .parent = &clk_h, | ||
135 | .enable = s3c2410_clkcon_enable, | ||
136 | .ctrlbit = S3C2410_CLKCON_LCDC, | ||
137 | }, { | ||
138 | .name = "gpio", | ||
139 | .id = -1, | ||
140 | .parent = &clk_p, | ||
141 | .enable = s3c2410_clkcon_enable, | ||
142 | .ctrlbit = S3C2410_CLKCON_GPIO, | ||
143 | }, { | ||
144 | .name = "usb-host", | ||
145 | .id = -1, | ||
146 | .parent = &clk_h, | ||
147 | .enable = s3c2410_clkcon_enable, | ||
148 | .ctrlbit = S3C2410_CLKCON_USBH, | ||
149 | }, { | ||
150 | .name = "usb-device", | ||
151 | .id = -1, | ||
152 | .parent = &clk_h, | ||
153 | .enable = s3c2410_clkcon_enable, | ||
154 | .ctrlbit = S3C2410_CLKCON_USBD, | ||
155 | }, { | ||
156 | .name = "timers", | ||
157 | .id = -1, | ||
158 | .parent = &clk_p, | ||
159 | .enable = s3c2410_clkcon_enable, | ||
160 | .ctrlbit = S3C2410_CLKCON_PWMT, | ||
161 | }, { | ||
162 | .name = "uart", | ||
163 | .id = 0, | ||
164 | .parent = &clk_p, | ||
165 | .enable = s3c2410_clkcon_enable, | ||
166 | .ctrlbit = S3C2410_CLKCON_UART0, | ||
167 | }, { | ||
168 | .name = "uart", | ||
169 | .id = 1, | ||
170 | .parent = &clk_p, | ||
171 | .enable = s3c2410_clkcon_enable, | ||
172 | .ctrlbit = S3C2410_CLKCON_UART1, | ||
173 | }, { | ||
174 | .name = "uart", | ||
175 | .id = 2, | ||
176 | .parent = &clk_p, | ||
177 | .enable = s3c2410_clkcon_enable, | ||
178 | .ctrlbit = S3C2410_CLKCON_UART2, | ||
179 | }, { | ||
180 | .name = "rtc", | ||
181 | .id = -1, | ||
182 | .parent = &clk_p, | ||
183 | .enable = s3c2410_clkcon_enable, | ||
184 | .ctrlbit = S3C2410_CLKCON_RTC, | ||
185 | }, { | ||
186 | .name = "watchdog", | ||
187 | .id = -1, | ||
188 | .parent = &clk_p, | ||
189 | .ctrlbit = 0, | ||
190 | }, { | ||
191 | .name = "usb-bus-host", | ||
192 | .id = -1, | ||
193 | .parent = &clk_usb_bus, | ||
194 | }, { | ||
195 | .name = "usb-bus-gadget", | ||
196 | .id = -1, | ||
197 | .parent = &clk_usb_bus, | ||
198 | }, | ||
376 | }; | 199 | }; |
377 | 200 | ||
378 | struct clk s3c24xx_clkout1 = { | 201 | /* s3c2410_baseclk_add() |
379 | .name = "clkout1", | 202 | * |
380 | .id = -1, | 203 | * Add all the clocks used by the s3c2410 or compatible CPUs |
381 | .set_parent = s3c24xx_clkout_setparent, | 204 | * such as the S3C2440 and S3C2442. |
382 | }; | 205 | * |
383 | 206 | * We cannot use a system device as we are needed before any | |
384 | struct clk s3c24xx_uclk = { | 207 | * of the init-calls that initialise the devices are actually |
385 | .name = "uclk", | 208 | * done. |
386 | .id = -1, | 209 | */ |
387 | }; | ||
388 | |||
389 | /* initialise the clock system */ | ||
390 | |||
391 | int s3c24xx_register_clock(struct clk *clk) | ||
392 | { | ||
393 | clk->owner = THIS_MODULE; | ||
394 | |||
395 | if (clk->enable == NULL) | ||
396 | clk->enable = clk_null_enable; | ||
397 | |||
398 | /* add to the list of available clocks */ | ||
399 | |||
400 | mutex_lock(&clocks_mutex); | ||
401 | list_add(&clk->list, &clocks); | ||
402 | mutex_unlock(&clocks_mutex); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* initalise all the clocks */ | ||
408 | 210 | ||
409 | int __init s3c24xx_setup_clocks(unsigned long xtal, | 211 | int __init s3c2410_baseclk_add(void) |
410 | unsigned long fclk, | ||
411 | unsigned long hclk, | ||
412 | unsigned long pclk) | ||
413 | { | 212 | { |
414 | printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); | 213 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); |
214 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | ||
215 | struct clk *clkp; | ||
216 | struct clk *xtal; | ||
217 | int ret; | ||
218 | int ptr; | ||
415 | 219 | ||
416 | /* initialise the main system clocks */ | 220 | clk_upll.enable = s3c2410_upll_enable; |
417 | 221 | ||
418 | clk_xtal.rate = xtal; | 222 | if (s3c24xx_register_clock(&clk_usb_bus) < 0) |
419 | clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); | 223 | printk(KERN_ERR "failed to register usb bus clock\n"); |
420 | 224 | ||
421 | clk_mpll.rate = fclk; | 225 | /* register clocks from clock array */ |
422 | clk_h.rate = hclk; | ||
423 | clk_p.rate = pclk; | ||
424 | clk_f.rate = fclk; | ||
425 | 226 | ||
426 | /* assume uart clocks are correctly setup */ | 227 | clkp = init_clocks; |
228 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
229 | /* ensure that we note the clock state */ | ||
427 | 230 | ||
428 | /* register our clocks */ | 231 | clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; |
429 | 232 | ||
430 | if (s3c24xx_register_clock(&clk_xtal) < 0) | 233 | ret = s3c24xx_register_clock(clkp); |
431 | printk(KERN_ERR "failed to register master xtal\n"); | 234 | if (ret < 0) { |
235 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
236 | clkp->name, ret); | ||
237 | } | ||
238 | } | ||
432 | 239 | ||
433 | if (s3c24xx_register_clock(&clk_mpll) < 0) | 240 | /* We must be careful disabling the clocks we are not intending to |
434 | printk(KERN_ERR "failed to register mpll clock\n"); | 241 | * be using at boot time, as subsytems such as the LCD which do |
242 | * their own DMA requests to the bus can cause the system to lockup | ||
243 | * if they where in the middle of requesting bus access. | ||
244 | * | ||
245 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
246 | * and therefore the bootloader should be careful to not enable | ||
247 | * the LCD clock if it is not needed. | ||
248 | */ | ||
249 | |||
250 | /* install (and disable) the clocks we do not need immediately */ | ||
251 | |||
252 | clkp = init_clocks_disable; | ||
253 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | ||
254 | |||
255 | ret = s3c24xx_register_clock(clkp); | ||
256 | if (ret < 0) { | ||
257 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
258 | clkp->name, ret); | ||
259 | } | ||
435 | 260 | ||
436 | if (s3c24xx_register_clock(&clk_upll) < 0) | 261 | s3c2410_clkcon_enable(clkp, 0); |
437 | printk(KERN_ERR "failed to register upll clock\n"); | 262 | } |
438 | 263 | ||
439 | if (s3c24xx_register_clock(&clk_f) < 0) | 264 | /* show the clock-slow value */ |
440 | printk(KERN_ERR "failed to register cpu fclk\n"); | ||
441 | 265 | ||
442 | if (s3c24xx_register_clock(&clk_h) < 0) | 266 | xtal = clk_get(NULL, "xtal"); |
443 | printk(KERN_ERR "failed to register cpu hclk\n"); | ||
444 | 267 | ||
445 | if (s3c24xx_register_clock(&clk_p) < 0) | 268 | printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", |
446 | printk(KERN_ERR "failed to register cpu pclk\n"); | 269 | print_mhz(clk_get_rate(xtal) / |
270 | ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), | ||
271 | (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", | ||
272 | (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", | ||
273 | (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); | ||
447 | 274 | ||
448 | return 0; | 275 | return 0; |
449 | } | 276 | } |