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