[ARM] Allow r2 to be passed through the decompressor to the kernel
[deliverable/linux.git] / arch / arm / mach-s3c2410 / clock.c
CommitLineData
1da177e4
LT
1/* linux/arch/arm/mach-s3c2410/clock.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 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 *
14 * 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
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27*/
28
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/list.h>
33#include <linux/errno.h>
34#include <linux/err.h>
d052d1be 35#include <linux/platform_device.h>
1da177e4 36#include <linux/sysdev.h>
1da177e4
LT
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
f8ce2547 39#include <linux/clk.h>
1da177e4
LT
40
41#include <asm/hardware.h>
42#include <asm/atomic.h>
43#include <asm/irq.h>
44#include <asm/io.h>
45
1da177e4
LT
46#include <asm/arch/regs-clock.h>
47
48#include "clock.h"
49#include "cpu.h"
50
51/* clock information */
52
53static LIST_HEAD(clocks);
54static DECLARE_MUTEX(clocks_sem);
55
56/* old functions */
57
58void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
59{
60 unsigned long clkcon;
61 unsigned long flags;
62
63 local_irq_save(flags);
64
65 clkcon = __raw_readl(S3C2410_CLKCON);
66 clkcon &= ~clocks;
67
68 if (enable)
69 clkcon |= clocks;
70
71 /* ensure none of the special function bits set */
72 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
73
74 __raw_writel(clkcon, S3C2410_CLKCON);
75
76 local_irq_restore(flags);
77}
78
79/* enable and disable calls for use with the clk struct */
80
81static int clk_null_enable(struct clk *clk, int enable)
82{
83 return 0;
84}
85
86int s3c24xx_clkcon_enable(struct clk *clk, int enable)
87{
88 s3c24xx_clk_enable(clk->ctrlbit, enable);
89 return 0;
90}
91
92/* Clock API calls */
93
94struct clk *clk_get(struct device *dev, const char *id)
95{
96 struct clk *p;
97 struct clk *clk = ERR_PTR(-ENOENT);
98 int idno;
99
c086f282
BD
100 if (dev == NULL || dev->bus != &platform_bus_type)
101 idno = -1;
102 else
103 idno = to_platform_device(dev)->id;
1da177e4
LT
104
105 down(&clocks_sem);
106
107 list_for_each_entry(p, &clocks, list) {
108 if (p->id == idno &&
109 strcmp(id, p->name) == 0 &&
110 try_module_get(p->owner)) {
111 clk = p;
112 break;
113 }
114 }
115
116 /* check for the case where a device was supplied, but the
117 * clock that was being searched for is not device specific */
118
119 if (IS_ERR(clk)) {
120 list_for_each_entry(p, &clocks, list) {
121 if (p->id == -1 && strcmp(id, p->name) == 0 &&
122 try_module_get(p->owner)) {
123 clk = p;
124 break;
125 }
126 }
127 }
128
129 up(&clocks_sem);
130 return clk;
131}
132
133void clk_put(struct clk *clk)
134{
135 module_put(clk->owner);
136}
137
138int clk_enable(struct clk *clk)
139{
140 if (IS_ERR(clk))
141 return -EINVAL;
142
143 return (clk->enable)(clk, 1);
144}
145
146void clk_disable(struct clk *clk)
147{
148 if (!IS_ERR(clk))
149 (clk->enable)(clk, 0);
150}
151
152
1da177e4
LT
153unsigned long clk_get_rate(struct clk *clk)
154{
155 if (IS_ERR(clk))
156 return 0;
157
158 if (clk->rate != 0)
159 return clk->rate;
160
161 while (clk->parent != NULL && clk->rate == 0)
162 clk = clk->parent;
163
164 return clk->rate;
165}
166
167long clk_round_rate(struct clk *clk, unsigned long rate)
168{
169 return rate;
170}
171
172int clk_set_rate(struct clk *clk, unsigned long rate)
173{
174 return -EINVAL;
175}
176
177struct clk *clk_get_parent(struct clk *clk)
178{
179 return clk->parent;
180}
181
182EXPORT_SYMBOL(clk_get);
183EXPORT_SYMBOL(clk_put);
184EXPORT_SYMBOL(clk_enable);
185EXPORT_SYMBOL(clk_disable);
1da177e4
LT
186EXPORT_SYMBOL(clk_get_rate);
187EXPORT_SYMBOL(clk_round_rate);
188EXPORT_SYMBOL(clk_set_rate);
189EXPORT_SYMBOL(clk_get_parent);
190
191/* base clocks */
192
193static struct clk clk_xtal = {
194 .name = "xtal",
195 .id = -1,
196 .rate = 0,
197 .parent = NULL,
198 .ctrlbit = 0,
199};
200
201static struct clk clk_f = {
202 .name = "fclk",
203 .id = -1,
204 .rate = 0,
205 .parent = NULL,
206 .ctrlbit = 0,
207};
208
209static struct clk clk_h = {
210 .name = "hclk",
211 .id = -1,
212 .rate = 0,
213 .parent = NULL,
214 .ctrlbit = 0,
215};
216
217static struct clk clk_p = {
218 .name = "pclk",
219 .id = -1,
220 .rate = 0,
221 .parent = NULL,
222 .ctrlbit = 0,
223};
224
225/* clocks that could be registered by external code */
226
227struct clk s3c24xx_dclk0 = {
228 .name = "dclk0",
229 .id = -1,
230};
231
232struct clk s3c24xx_dclk1 = {
233 .name = "dclk1",
234 .id = -1,
235};
236
237struct clk s3c24xx_clkout0 = {
238 .name = "clkout0",
239 .id = -1,
240};
241
242struct clk s3c24xx_clkout1 = {
243 .name = "clkout1",
244 .id = -1,
245};
246
247struct clk s3c24xx_uclk = {
248 .name = "uclk",
249 .id = -1,
250};
251
252
253/* clock definitions */
254
255static struct clk init_clocks[] = {
fe38ea56
BD
256 {
257 .name = "nand",
258 .id = -1,
259 .parent = &clk_h,
260 .enable = s3c24xx_clkcon_enable,
261 .ctrlbit = S3C2410_CLKCON_NAND,
262 }, {
263 .name = "lcd",
264 .id = -1,
265 .parent = &clk_h,
266 .enable = s3c24xx_clkcon_enable,
267 .ctrlbit = S3C2410_CLKCON_LCDC,
268 }, {
269 .name = "usb-host",
270 .id = -1,
271 .parent = &clk_h,
272 .enable = s3c24xx_clkcon_enable,
273 .ctrlbit = S3C2410_CLKCON_USBH,
274 }, {
275 .name = "usb-device",
276 .id = -1,
277 .parent = &clk_h,
278 .enable = s3c24xx_clkcon_enable,
279 .ctrlbit = S3C2410_CLKCON_USBD,
280 }, {
281 .name = "timers",
282 .id = -1,
283 .parent = &clk_p,
284 .enable = s3c24xx_clkcon_enable,
285 .ctrlbit = S3C2410_CLKCON_PWMT,
286 }, {
287 .name = "sdi",
288 .id = -1,
289 .parent = &clk_p,
290 .enable = s3c24xx_clkcon_enable,
291 .ctrlbit = S3C2410_CLKCON_SDI,
292 }, {
293 .name = "uart",
294 .id = 0,
295 .parent = &clk_p,
296 .enable = s3c24xx_clkcon_enable,
297 .ctrlbit = S3C2410_CLKCON_UART0,
298 }, {
299 .name = "uart",
300 .id = 1,
301 .parent = &clk_p,
302 .enable = s3c24xx_clkcon_enable,
303 .ctrlbit = S3C2410_CLKCON_UART1,
304 }, {
305 .name = "uart",
306 .id = 2,
307 .parent = &clk_p,
308 .enable = s3c24xx_clkcon_enable,
309 .ctrlbit = S3C2410_CLKCON_UART2,
310 }, {
311 .name = "gpio",
312 .id = -1,
313 .parent = &clk_p,
314 .enable = s3c24xx_clkcon_enable,
315 .ctrlbit = S3C2410_CLKCON_GPIO,
316 }, {
317 .name = "rtc",
318 .id = -1,
319 .parent = &clk_p,
320 .enable = s3c24xx_clkcon_enable,
321 .ctrlbit = S3C2410_CLKCON_RTC,
322 }, {
323 .name = "adc",
324 .id = -1,
325 .parent = &clk_p,
326 .enable = s3c24xx_clkcon_enable,
327 .ctrlbit = S3C2410_CLKCON_ADC,
328 }, {
329 .name = "i2c",
330 .id = -1,
331 .parent = &clk_p,
332 .enable = s3c24xx_clkcon_enable,
333 .ctrlbit = S3C2410_CLKCON_IIC,
334 }, {
335 .name = "iis",
336 .id = -1,
337 .parent = &clk_p,
338 .enable = s3c24xx_clkcon_enable,
339 .ctrlbit = S3C2410_CLKCON_IIS,
340 }, {
341 .name = "spi",
342 .id = -1,
343 .parent = &clk_p,
344 .enable = s3c24xx_clkcon_enable,
345 .ctrlbit = S3C2410_CLKCON_SPI,
346 }, {
347 .name = "watchdog",
348 .id = -1,
349 .parent = &clk_p,
350 .ctrlbit = 0,
1da177e4
LT
351 }
352};
353
354/* initialise the clock system */
355
356int s3c24xx_register_clock(struct clk *clk)
357{
358 clk->owner = THIS_MODULE;
1da177e4
LT
359
360 if (clk->enable == NULL)
361 clk->enable = clk_null_enable;
362
363 /* add to the list of available clocks */
364
365 down(&clocks_sem);
366 list_add(&clk->list, &clocks);
367 up(&clocks_sem);
368
369 return 0;
370}
371
372/* initalise all the clocks */
373
374int __init s3c24xx_setup_clocks(unsigned long xtal,
375 unsigned long fclk,
376 unsigned long hclk,
377 unsigned long pclk)
378{
d6b0bf21 379 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
1da177e4
LT
380 struct clk *clkp = init_clocks;
381 int ptr;
382 int ret;
383
384 printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n");
385
386 /* initialise the main system clocks */
387
388 clk_xtal.rate = xtal;
389
390 clk_h.rate = hclk;
391 clk_p.rate = pclk;
392 clk_f.rate = fclk;
393
fe38ea56
BD
394 /* We must be careful disabling the clocks we are not intending to
395 * be using at boot time, as subsytems such as the LCD which do
396 * their own DMA requests to the bus can cause the system to lockup
397 * if they where in the middle of requesting bus access.
1da177e4 398 *
fe38ea56
BD
399 * Disabling the LCD clock if the LCD is active is very dangerous,
400 * and therefore the bootloader should be careful to not enable
401 * the LCD clock if it is not needed.
402 */
1da177e4
LT
403
404 s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0);
405 s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0);
406 s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0);
407 s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0);
408 s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0);
409 s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0);
410
411 /* assume uart clocks are correctly setup */
412
413 /* register our clocks */
414
415 if (s3c24xx_register_clock(&clk_xtal) < 0)
416 printk(KERN_ERR "failed to register master xtal\n");
417
418 if (s3c24xx_register_clock(&clk_f) < 0)
419 printk(KERN_ERR "failed to register cpu fclk\n");
420
421 if (s3c24xx_register_clock(&clk_h) < 0)
422 printk(KERN_ERR "failed to register cpu hclk\n");
423
424 if (s3c24xx_register_clock(&clk_p) < 0)
425 printk(KERN_ERR "failed to register cpu pclk\n");
426
427 /* register clocks from clock array */
428
429 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
430 ret = s3c24xx_register_clock(clkp);
431 if (ret < 0) {
432 printk(KERN_ERR "Failed to register clock %s (%d)\n",
433 clkp->name, ret);
434 }
435 }
436
d6b0bf21
BD
437 /* show the clock-slow value */
438
439 printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
440 print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
441 (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
442 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
443 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
444
1da177e4
LT
445 return 0;
446}
This page took 0.117166 seconds and 5 git commands to generate.