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