1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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/device.h>
36
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39
40#include <asm/hardware.h>
41#include <asm/atomic.h>
42#include <asm/irq.h>
43#include <asm/io.h>
44
45#include <asm/hardware/clock.h>
46#include <asm/arch/regs-clock.h>
47
48#include "clock.h"
49
50
51
52unsigned long s3c24xx_xtal = 12*1000*1000;
53unsigned long s3c24xx_fclk;
54unsigned long s3c24xx_hclk;
55unsigned long s3c24xx_pclk;
56
57static LIST_HEAD(clocks);
58static DECLARE_MUTEX(clocks_sem);
59
60
61
62
63void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
64{
65 unsigned long clkcon;
66 unsigned long flags;
67
68 local_irq_save(flags);
69
70 clkcon = __raw_readl(S3C2410_CLKCON);
71 clkcon &= ~clocks;
72
73 if (enable)
74 clkcon |= clocks;
75
76
77 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
78
79 __raw_writel(clkcon, S3C2410_CLKCON);
80
81 local_irq_restore(flags);
82}
83
84
85
86static int clk_null_enable(struct clk *clk, int enable)
87{
88 return 0;
89}
90
91int s3c24xx_clkcon_enable(struct clk *clk, int enable)
92{
93 s3c24xx_clk_enable(clk->ctrlbit, enable);
94 return 0;
95}
96
97
98
99struct clk *clk_get(struct device *dev, const char *id)
100{
101 struct clk *p;
102 struct clk *clk = ERR_PTR(-ENOENT);
103 int idno;
104
105 idno = (dev == NULL) ? -1 : to_platform_device(dev)->id;
106
107 down(&clocks_sem);
108
109 list_for_each_entry(p, &clocks, list) {
110 if (p->id == idno &&
111 strcmp(id, p->name) == 0 &&
112 try_module_get(p->owner)) {
113 clk = p;
114 break;
115 }
116 }
117
118
119
120
121 if (IS_ERR(clk)) {
122 list_for_each_entry(p, &clocks, list) {
123 if (p->id == -1 && strcmp(id, p->name) == 0 &&
124 try_module_get(p->owner)) {
125 clk = p;
126 break;
127 }
128 }
129 }
130
131 up(&clocks_sem);
132 return clk;
133}
134
135void clk_put(struct clk *clk)
136{
137 module_put(clk->owner);
138}
139
140int clk_enable(struct clk *clk)
141{
142 if (IS_ERR(clk))
143 return -EINVAL;
144
145 return (clk->enable)(clk, 1);
146}
147
148void clk_disable(struct clk *clk)
149{
150 if (!IS_ERR(clk))
151 (clk->enable)(clk, 0);
152}
153
154
155int clk_use(struct clk *clk)
156{
157 atomic_inc(&clk->used);
158 return 0;
159}
160
161
162void clk_unuse(struct clk *clk)
163{
164 atomic_dec(&clk->used);
165}
166
167unsigned 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
181long clk_round_rate(struct clk *clk, unsigned long rate)
182{
183 return rate;
184}
185
186int clk_set_rate(struct clk *clk, unsigned long rate)
187{
188 return -EINVAL;
189}
190
191struct clk *clk_get_parent(struct clk *clk)
192{
193 return clk->parent;
194}
195
196EXPORT_SYMBOL(clk_get);
197EXPORT_SYMBOL(clk_put);
198EXPORT_SYMBOL(clk_enable);
199EXPORT_SYMBOL(clk_disable);
200EXPORT_SYMBOL(clk_use);
201EXPORT_SYMBOL(clk_unuse);
202EXPORT_SYMBOL(clk_get_rate);
203EXPORT_SYMBOL(clk_round_rate);
204EXPORT_SYMBOL(clk_set_rate);
205EXPORT_SYMBOL(clk_get_parent);
206
207
208
209static struct clk clk_f = {
210 .name = "fclk",
211 .id = -1,
212 .rate = 0,
213 .parent = NULL,
214 .ctrlbit = 0,
215};
216
217static struct clk clk_h = {
218 .name = "hclk",
219 .id = -1,
220 .rate = 0,
221 .parent = NULL,
222 .ctrlbit = 0,
223};
224
225static struct clk clk_p = {
226 .name = "pclk",
227 .id = -1,
228 .rate = 0,
229 .parent = NULL,
230 .ctrlbit = 0,
231};
232
233
234
235struct clk s3c24xx_dclk0 = {
236 .name = "dclk0",
237 .id = -1,
238};
239
240struct clk s3c24xx_dclk1 = {
241 .name = "dclk1",
242 .id = -1,
243};
244
245struct clk s3c24xx_clkout0 = {
246 .name = "clkout0",
247 .id = -1,
248};
249
250struct clk s3c24xx_clkout1 = {
251 .name = "clkout1",
252 .id = -1,
253};
254
255struct clk s3c24xx_uclk = {
256 .name = "uclk",
257 .id = -1,
258};
259
260
261
262
263static struct clk init_clocks[] = {
264 { .name = "nand",
265 .id = -1,
266 .parent = &clk_h,
267 .enable = s3c24xx_clkcon_enable,
268 .ctrlbit = S3C2410_CLKCON_NAND
269 },
270 { .name = "lcd",
271 .id = -1,
272 .parent = &clk_h,
273 .enable = s3c24xx_clkcon_enable,
274 .ctrlbit = S3C2410_CLKCON_LCDC
275 },
276 { .name = "usb-host",
277 .id = -1,
278 .parent = &clk_h,
279 .enable = s3c24xx_clkcon_enable,
280 .ctrlbit = S3C2410_CLKCON_USBH
281 },
282 { .name = "usb-device",
283 .id = -1,
284 .parent = &clk_h,
285 .enable = s3c24xx_clkcon_enable,
286 .ctrlbit = S3C2410_CLKCON_USBD
287 },
288 { .name = "timers",
289 .parent = &clk_p,
290 .enable = s3c24xx_clkcon_enable,
291 .ctrlbit = S3C2410_CLKCON_PWMT
292 },
293 { .name = "sdi",
294 .id = -1,
295 .parent = &clk_p,
296 .enable = s3c24xx_clkcon_enable,
297 .ctrlbit = S3C2410_CLKCON_SDI
298 },
299 { .name = "uart",
300 .id = 0,
301 .parent = &clk_p,
302 .enable = s3c24xx_clkcon_enable,
303 .ctrlbit = S3C2410_CLKCON_UART0
304 },
305 { .name = "uart",
306 .id = 1,
307 .parent = &clk_p,
308 .enable = s3c24xx_clkcon_enable,
309 .ctrlbit = S3C2410_CLKCON_UART1
310 },
311 { .name = "uart",
312 .id = 2,
313 .parent = &clk_p,
314 .enable = s3c24xx_clkcon_enable,
315 .ctrlbit = S3C2410_CLKCON_UART2
316 },
317 { .name = "gpio",
318 .id = -1,
319 .parent = &clk_p,
320 .enable = s3c24xx_clkcon_enable,
321 .ctrlbit = S3C2410_CLKCON_GPIO
322 },
323 { .name = "rtc",
324 .id = -1,
325 .parent = &clk_p,
326 .enable = s3c24xx_clkcon_enable,
327 .ctrlbit = S3C2410_CLKCON_RTC
328 },
329 { .name = "adc",
330 .id = -1,
331 .parent = &clk_p,
332 .enable = s3c24xx_clkcon_enable,
333 .ctrlbit = S3C2410_CLKCON_ADC
334 },
335 { .name = "i2c",
336 .id = -1,
337 .parent = &clk_p,
338 .enable = s3c24xx_clkcon_enable,
339 .ctrlbit = S3C2410_CLKCON_IIC
340 },
341 { .name = "iis",
342 .id = -1,
343 .parent = &clk_p,
344 .enable = s3c24xx_clkcon_enable,
345 .ctrlbit = S3C2410_CLKCON_IIS
346 },
347 { .name = "spi",
348 .id = -1,
349 .parent = &clk_p,
350 .enable = s3c24xx_clkcon_enable,
351 .ctrlbit = S3C2410_CLKCON_SPI
352 },
353 { .name = "watchdog",
354 .id = -1,
355 .parent = &clk_p,
356 .ctrlbit = 0
357 }
358};
359
360
361
362int s3c24xx_register_clock(struct clk *clk)
363{
364 clk->owner = THIS_MODULE;
365 atomic_set(&clk->used, 0);
366
367 if (clk->enable == NULL)
368 clk->enable = clk_null_enable;
369
370
371
372 down(&clocks_sem);
373 list_add(&clk->list, &clocks);
374 up(&clocks_sem);
375
376 return 0;
377}
378
379
380
381int __init s3c24xx_setup_clocks(void)
382{
383 struct clk *clkp = init_clocks;
384 int ptr;
385 int ret;
386
387 printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n");
388
389
390
391 clk_h.rate = s3c24xx_hclk;
392 clk_p.rate = s3c24xx_pclk;
393 clk_f.rate = s3c24xx_fclk;
394
395
396
397
398
399
400
401
402
403
404
405
406 s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0);
407 s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0);
408 s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0);
409 s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0);
410 s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0);
411 s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0);
412
413
414
415
416
417 if (s3c24xx_register_clock(&clk_f) < 0)
418 printk(KERN_ERR "failed to register cpu fclk\n");
419
420 if (s3c24xx_register_clock(&clk_h) < 0)
421 printk(KERN_ERR "failed to register cpu hclk\n");
422
423 if (s3c24xx_register_clock(&clk_p) < 0)
424 printk(KERN_ERR "failed to register cpu pclk\n");
425
426 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
427 ret = s3c24xx_register_clock(clkp);
428 if (ret < 0) {
429 printk(KERN_ERR "Failed to register clock %s (%d)\n",
430 clkp->name, ret);
431 }
432 }
433
434 return 0;
435}
436
437
438