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