]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/plat-s3c24xx/clock.c
[ARM] S3C24XX: Split pll code out of regs-clock.h
[karo-tx-linux.git] / arch / arm / plat-s3c24xx / clock.c
1 /* linux/arch/arm/plat-s3c24xx/clock.c
2  *
3  * Copyright (c) 2004-2005 Simtec Electronics
4  *      Ben Dooks <ben@simtec.co.uk>
5  *
6  * S3C24XX Core 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 #include <linux/io.h>
43
44 #include <mach/hardware.h>
45 #include <asm/irq.h>
46
47 #include <mach/regs-clock.h>
48 #include <mach/regs-gpio.h>
49
50 #include <plat/clock.h>
51 #include <plat/cpu.h>
52 #include <plat/pll.h>
53
54 /* clock information */
55
56 static LIST_HEAD(clocks);
57
58 DEFINE_MUTEX(clocks_mutex);
59
60 /* enable and disable calls for use with the clk struct */
61
62 static int clk_null_enable(struct clk *clk, int enable)
63 {
64         return 0;
65 }
66
67 /* Clock API calls */
68
69 struct clk *clk_get(struct device *dev, const char *id)
70 {
71         struct clk *p;
72         struct clk *clk = ERR_PTR(-ENOENT);
73         int idno;
74
75         if (dev == NULL || dev->bus != &platform_bus_type)
76                 idno = -1;
77         else
78                 idno = to_platform_device(dev)->id;
79
80         mutex_lock(&clocks_mutex);
81
82         list_for_each_entry(p, &clocks, list) {
83                 if (p->id == idno &&
84                     strcmp(id, p->name) == 0 &&
85                     try_module_get(p->owner)) {
86                         clk = p;
87                         break;
88                 }
89         }
90
91         /* check for the case where a device was supplied, but the
92          * clock that was being searched for is not device specific */
93
94         if (IS_ERR(clk)) {
95                 list_for_each_entry(p, &clocks, list) {
96                         if (p->id == -1 && strcmp(id, p->name) == 0 &&
97                             try_module_get(p->owner)) {
98                                 clk = p;
99                                 break;
100                         }
101                 }
102         }
103
104         mutex_unlock(&clocks_mutex);
105         return clk;
106 }
107
108 void clk_put(struct clk *clk)
109 {
110         module_put(clk->owner);
111 }
112
113 int clk_enable(struct clk *clk)
114 {
115         if (IS_ERR(clk) || clk == NULL)
116                 return -EINVAL;
117
118         clk_enable(clk->parent);
119
120         mutex_lock(&clocks_mutex);
121
122         if ((clk->usage++) == 0)
123                 (clk->enable)(clk, 1);
124
125         mutex_unlock(&clocks_mutex);
126         return 0;
127 }
128
129 void clk_disable(struct clk *clk)
130 {
131         if (IS_ERR(clk) || clk == NULL)
132                 return;
133
134         mutex_lock(&clocks_mutex);
135
136         if ((--clk->usage) == 0)
137                 (clk->enable)(clk, 0);
138
139         mutex_unlock(&clocks_mutex);
140         clk_disable(clk->parent);
141 }
142
143
144 unsigned long clk_get_rate(struct clk *clk)
145 {
146         if (IS_ERR(clk))
147                 return 0;
148
149         if (clk->rate != 0)
150                 return clk->rate;
151
152         if (clk->get_rate != NULL)
153                 return (clk->get_rate)(clk);
154
155         if (clk->parent != NULL)
156                 return clk_get_rate(clk->parent);
157
158         return clk->rate;
159 }
160
161 long clk_round_rate(struct clk *clk, unsigned long rate)
162 {
163         if (!IS_ERR(clk) && clk->round_rate)
164                 return (clk->round_rate)(clk, rate);
165
166         return rate;
167 }
168
169 int clk_set_rate(struct clk *clk, unsigned long rate)
170 {
171         int ret;
172
173         if (IS_ERR(clk))
174                 return -EINVAL;
175
176         /* We do not default just do a clk->rate = rate as
177          * the clock may have been made this way by choice.
178          */
179
180         WARN_ON(clk->set_rate == NULL);
181
182         if (clk->set_rate == NULL)
183                 return -EINVAL;
184
185         mutex_lock(&clocks_mutex);
186         ret = (clk->set_rate)(clk, rate);
187         mutex_unlock(&clocks_mutex);
188
189         return ret;
190 }
191
192 struct clk *clk_get_parent(struct clk *clk)
193 {
194         return clk->parent;
195 }
196
197 int clk_set_parent(struct clk *clk, struct clk *parent)
198 {
199         int ret = 0;
200
201         if (IS_ERR(clk))
202                 return -EINVAL;
203
204         mutex_lock(&clocks_mutex);
205
206         if (clk->set_parent)
207                 ret = (clk->set_parent)(clk, parent);
208
209         mutex_unlock(&clocks_mutex);
210
211         return ret;
212 }
213
214 EXPORT_SYMBOL(clk_get);
215 EXPORT_SYMBOL(clk_put);
216 EXPORT_SYMBOL(clk_enable);
217 EXPORT_SYMBOL(clk_disable);
218 EXPORT_SYMBOL(clk_get_rate);
219 EXPORT_SYMBOL(clk_round_rate);
220 EXPORT_SYMBOL(clk_set_rate);
221 EXPORT_SYMBOL(clk_get_parent);
222 EXPORT_SYMBOL(clk_set_parent);
223
224 /* base clocks */
225
226 static int clk_default_setrate(struct clk *clk, unsigned long rate)
227 {
228         clk->rate = rate;
229         return 0;
230 }
231
232 struct clk clk_xtal = {
233         .name           = "xtal",
234         .id             = -1,
235         .rate           = 0,
236         .parent         = NULL,
237         .ctrlbit        = 0,
238 };
239
240 struct clk clk_mpll = {
241         .name           = "mpll",
242         .id             = -1,
243         .set_rate       = clk_default_setrate,
244 };
245
246 struct clk clk_upll = {
247         .name           = "upll",
248         .id             = -1,
249         .parent         = NULL,
250         .ctrlbit        = 0,
251 };
252
253 struct clk clk_f = {
254         .name           = "fclk",
255         .id             = -1,
256         .rate           = 0,
257         .parent         = &clk_mpll,
258         .ctrlbit        = 0,
259         .set_rate       = clk_default_setrate,
260 };
261
262 struct clk clk_h = {
263         .name           = "hclk",
264         .id             = -1,
265         .rate           = 0,
266         .parent         = NULL,
267         .ctrlbit        = 0,
268         .set_rate       = clk_default_setrate,
269 };
270
271 struct clk clk_p = {
272         .name           = "pclk",
273         .id             = -1,
274         .rate           = 0,
275         .parent         = NULL,
276         .ctrlbit        = 0,
277         .set_rate       = clk_default_setrate,
278 };
279
280 struct clk clk_usb_bus = {
281         .name           = "usb-bus",
282         .id             = -1,
283         .rate           = 0,
284         .parent         = &clk_upll,
285 };
286
287
288
289 struct clk s3c24xx_uclk = {
290         .name           = "uclk",
291         .id             = -1,
292 };
293
294 /* initialise the clock system */
295
296 int s3c24xx_register_clock(struct clk *clk)
297 {
298         clk->owner = THIS_MODULE;
299
300         if (clk->enable == NULL)
301                 clk->enable = clk_null_enable;
302
303         /* add to the list of available clocks */
304
305         mutex_lock(&clocks_mutex);
306         list_add(&clk->list, &clocks);
307         mutex_unlock(&clocks_mutex);
308
309         return 0;
310 }
311
312 int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
313 {
314         int fails = 0;
315
316         for (; nr_clks > 0; nr_clks--, clks++) {
317                 if (s3c24xx_register_clock(*clks) < 0)
318                         fails++;
319         }
320
321         return fails;
322 }
323
324 /* initalise all the clocks */
325
326 int __init s3c24xx_setup_clocks(unsigned long xtal,
327                                 unsigned long fclk,
328                                 unsigned long hclk,
329                                 unsigned long pclk)
330 {
331         printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
332
333         /* initialise the main system clocks */
334
335         clk_xtal.rate = xtal;
336         clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
337
338         clk_mpll.rate = fclk;
339         clk_h.rate = hclk;
340         clk_p.rate = pclk;
341         clk_f.rate = fclk;
342
343         /* assume uart clocks are correctly setup */
344
345         /* register our clocks */
346
347         if (s3c24xx_register_clock(&clk_xtal) < 0)
348                 printk(KERN_ERR "failed to register master xtal\n");
349
350         if (s3c24xx_register_clock(&clk_mpll) < 0)
351                 printk(KERN_ERR "failed to register mpll clock\n");
352
353         if (s3c24xx_register_clock(&clk_upll) < 0)
354                 printk(KERN_ERR "failed to register upll clock\n");
355
356         if (s3c24xx_register_clock(&clk_f) < 0)
357                 printk(KERN_ERR "failed to register cpu fclk\n");
358
359         if (s3c24xx_register_clock(&clk_h) < 0)
360                 printk(KERN_ERR "failed to register cpu hclk\n");
361
362         if (s3c24xx_register_clock(&clk_p) < 0)
363                 printk(KERN_ERR "failed to register cpu pclk\n");
364
365         return 0;
366 }