~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/plat-samsung/clock.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* linux/arch/arm/plat-s3c24xx/clock.c
 
2
 *
 
3
 * Copyright 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/spinlock.h>
 
41
#include <linux/io.h>
 
42
#if defined(CONFIG_DEBUG_FS)
 
43
#include <linux/debugfs.h>
 
44
#endif
 
45
 
 
46
#include <mach/hardware.h>
 
47
#include <asm/irq.h>
 
48
 
 
49
#include <plat/cpu-freq.h>
 
50
 
 
51
#include <plat/clock.h>
 
52
#include <plat/cpu.h>
 
53
 
 
54
#include <linux/serial_core.h>
 
55
#include <plat/regs-serial.h> /* for s3c24xx_uart_devs */
 
56
 
 
57
/* clock information */
 
58
 
 
59
static LIST_HEAD(clocks);
 
60
 
 
61
/* We originally used an mutex here, but some contexts (see resume)
 
62
 * are calling functions such as clk_set_parent() with IRQs disabled
 
63
 * causing an BUG to be triggered.
 
64
 */
 
65
DEFINE_SPINLOCK(clocks_lock);
 
66
 
 
67
/* Global watchdog clock used by arch_wtd_reset() callback */
 
68
struct clk *s3c2410_wdtclk;
 
69
static int __init s3c_wdt_reset_init(void)
 
70
{
 
71
        s3c2410_wdtclk = clk_get(NULL, "watchdog");
 
72
        if (IS_ERR(s3c2410_wdtclk))
 
73
                printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
 
74
        return 0;
 
75
}
 
76
arch_initcall(s3c_wdt_reset_init);
 
77
 
 
78
/* enable and disable calls for use with the clk struct */
 
79
 
 
80
static int clk_null_enable(struct clk *clk, int enable)
 
81
{
 
82
        return 0;
 
83
}
 
84
 
 
85
int clk_enable(struct clk *clk)
 
86
{
 
87
        if (IS_ERR(clk) || clk == NULL)
 
88
                return -EINVAL;
 
89
 
 
90
        clk_enable(clk->parent);
 
91
 
 
92
        spin_lock(&clocks_lock);
 
93
 
 
94
        if ((clk->usage++) == 0)
 
95
                (clk->enable)(clk, 1);
 
96
 
 
97
        spin_unlock(&clocks_lock);
 
98
        return 0;
 
99
}
 
100
 
 
101
void clk_disable(struct clk *clk)
 
102
{
 
103
        if (IS_ERR(clk) || clk == NULL)
 
104
                return;
 
105
 
 
106
        spin_lock(&clocks_lock);
 
107
 
 
108
        if ((--clk->usage) == 0)
 
109
                (clk->enable)(clk, 0);
 
110
 
 
111
        spin_unlock(&clocks_lock);
 
112
        clk_disable(clk->parent);
 
113
}
 
114
 
 
115
 
 
116
unsigned long clk_get_rate(struct clk *clk)
 
117
{
 
118
        if (IS_ERR(clk))
 
119
                return 0;
 
120
 
 
121
        if (clk->rate != 0)
 
122
                return clk->rate;
 
123
 
 
124
        if (clk->ops != NULL && clk->ops->get_rate != NULL)
 
125
                return (clk->ops->get_rate)(clk);
 
126
 
 
127
        if (clk->parent != NULL)
 
128
                return clk_get_rate(clk->parent);
 
129
 
 
130
        return clk->rate;
 
131
}
 
132
 
 
133
long clk_round_rate(struct clk *clk, unsigned long rate)
 
134
{
 
135
        if (!IS_ERR(clk) && clk->ops && clk->ops->round_rate)
 
136
                return (clk->ops->round_rate)(clk, rate);
 
137
 
 
138
        return rate;
 
139
}
 
140
 
 
141
int clk_set_rate(struct clk *clk, unsigned long rate)
 
142
{
 
143
        int ret;
 
144
 
 
145
        if (IS_ERR(clk))
 
146
                return -EINVAL;
 
147
 
 
148
        /* We do not default just do a clk->rate = rate as
 
149
         * the clock may have been made this way by choice.
 
150
         */
 
151
 
 
152
        WARN_ON(clk->ops == NULL);
 
153
        WARN_ON(clk->ops && clk->ops->set_rate == NULL);
 
154
 
 
155
        if (clk->ops == NULL || clk->ops->set_rate == NULL)
 
156
                return -EINVAL;
 
157
 
 
158
        spin_lock(&clocks_lock);
 
159
        ret = (clk->ops->set_rate)(clk, rate);
 
160
        spin_unlock(&clocks_lock);
 
161
 
 
162
        return ret;
 
163
}
 
164
 
 
165
struct clk *clk_get_parent(struct clk *clk)
 
166
{
 
167
        return clk->parent;
 
168
}
 
169
 
 
170
int clk_set_parent(struct clk *clk, struct clk *parent)
 
171
{
 
172
        int ret = 0;
 
173
 
 
174
        if (IS_ERR(clk))
 
175
                return -EINVAL;
 
176
 
 
177
        spin_lock(&clocks_lock);
 
178
 
 
179
        if (clk->ops && clk->ops->set_parent)
 
180
                ret = (clk->ops->set_parent)(clk, parent);
 
181
 
 
182
        spin_unlock(&clocks_lock);
 
183
 
 
184
        return ret;
 
185
}
 
186
 
 
187
EXPORT_SYMBOL(clk_enable);
 
188
EXPORT_SYMBOL(clk_disable);
 
189
EXPORT_SYMBOL(clk_get_rate);
 
190
EXPORT_SYMBOL(clk_round_rate);
 
191
EXPORT_SYMBOL(clk_set_rate);
 
192
EXPORT_SYMBOL(clk_get_parent);
 
193
EXPORT_SYMBOL(clk_set_parent);
 
194
 
 
195
/* base clocks */
 
196
 
 
197
int clk_default_setrate(struct clk *clk, unsigned long rate)
 
198
{
 
199
        clk->rate = rate;
 
200
        return 0;
 
201
}
 
202
 
 
203
struct clk_ops clk_ops_def_setrate = {
 
204
        .set_rate       = clk_default_setrate,
 
205
};
 
206
 
 
207
struct clk clk_xtal = {
 
208
        .name           = "xtal",
 
209
        .rate           = 0,
 
210
        .parent         = NULL,
 
211
        .ctrlbit        = 0,
 
212
};
 
213
 
 
214
struct clk clk_ext = {
 
215
        .name           = "ext",
 
216
};
 
217
 
 
218
struct clk clk_epll = {
 
219
        .name           = "epll",
 
220
};
 
221
 
 
222
struct clk clk_mpll = {
 
223
        .name           = "mpll",
 
224
        .ops            = &clk_ops_def_setrate,
 
225
};
 
226
 
 
227
struct clk clk_upll = {
 
228
        .name           = "upll",
 
229
        .parent         = NULL,
 
230
        .ctrlbit        = 0,
 
231
};
 
232
 
 
233
struct clk clk_f = {
 
234
        .name           = "fclk",
 
235
        .rate           = 0,
 
236
        .parent         = &clk_mpll,
 
237
        .ctrlbit        = 0,
 
238
};
 
239
 
 
240
struct clk clk_h = {
 
241
        .name           = "hclk",
 
242
        .rate           = 0,
 
243
        .parent         = NULL,
 
244
        .ctrlbit        = 0,
 
245
        .ops            = &clk_ops_def_setrate,
 
246
};
 
247
 
 
248
struct clk clk_p = {
 
249
        .name           = "pclk",
 
250
        .rate           = 0,
 
251
        .parent         = NULL,
 
252
        .ctrlbit        = 0,
 
253
        .ops            = &clk_ops_def_setrate,
 
254
};
 
255
 
 
256
struct clk clk_usb_bus = {
 
257
        .name           = "usb-bus",
 
258
        .rate           = 0,
 
259
        .parent         = &clk_upll,
 
260
};
 
261
 
 
262
 
 
263
struct clk s3c24xx_uclk = {
 
264
        .name           = "uclk",
 
265
};
 
266
 
 
267
/* initialise the clock system */
 
268
 
 
269
/**
 
270
 * s3c24xx_register_clock() - register a clock
 
271
 * @clk: The clock to register
 
272
 *
 
273
 * Add the specified clock to the list of clocks known by the system.
 
274
 */
 
275
int s3c24xx_register_clock(struct clk *clk)
 
276
{
 
277
        if (clk->enable == NULL)
 
278
                clk->enable = clk_null_enable;
 
279
 
 
280
        /* fill up the clk_lookup structure and register it*/
 
281
        clk->lookup.dev_id = clk->devname;
 
282
        clk->lookup.con_id = clk->name;
 
283
        clk->lookup.clk = clk;
 
284
        clkdev_add(&clk->lookup);
 
285
 
 
286
        return 0;
 
287
}
 
288
 
 
289
/**
 
290
 * s3c24xx_register_clocks() - register an array of clock pointers
 
291
 * @clks: Pointer to an array of struct clk pointers
 
292
 * @nr_clks: The number of clocks in the @clks array.
 
293
 *
 
294
 * Call s3c24xx_register_clock() for all the clock pointers contained
 
295
 * in the @clks list. Returns the number of failures.
 
296
 */
 
297
int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
 
298
{
 
299
        int fails = 0;
 
300
 
 
301
        for (; nr_clks > 0; nr_clks--, clks++) {
 
302
                if (s3c24xx_register_clock(*clks) < 0) {
 
303
                        struct clk *clk = *clks;
 
304
                        printk(KERN_ERR "%s: failed to register %p: %s\n",
 
305
                               __func__, clk, clk->name);
 
306
                        fails++;
 
307
                }
 
308
        }
 
309
 
 
310
        return fails;
 
311
}
 
312
 
 
313
/**
 
314
 * s3c_register_clocks() - register an array of clocks
 
315
 * @clkp: Pointer to the first clock in the array.
 
316
 * @nr_clks: Number of clocks to register.
 
317
 *
 
318
 * Call s3c24xx_register_clock() on the @clkp array given, printing an
 
319
 * error if it fails to register the clock (unlikely).
 
320
 */
 
321
void __init s3c_register_clocks(struct clk *clkp, int nr_clks)
 
322
{
 
323
        int ret;
 
324
 
 
325
        for (; nr_clks > 0; nr_clks--, clkp++) {
 
326
                ret = s3c24xx_register_clock(clkp);
 
327
 
 
328
                if (ret < 0) {
 
329
                        printk(KERN_ERR "Failed to register clock %s (%d)\n",
 
330
                               clkp->name, ret);
 
331
                }
 
332
        }
 
333
}
 
334
 
 
335
/**
 
336
 * s3c_disable_clocks() - disable an array of clocks
 
337
 * @clkp: Pointer to the first clock in the array.
 
338
 * @nr_clks: Number of clocks to register.
 
339
 *
 
340
 * for internal use only at initialisation time. disable the clocks in the
 
341
 * @clkp array.
 
342
 */
 
343
 
 
344
void __init s3c_disable_clocks(struct clk *clkp, int nr_clks)
 
345
{
 
346
        for (; nr_clks > 0; nr_clks--, clkp++)
 
347
                (clkp->enable)(clkp, 0);
 
348
}
 
349
 
 
350
/* initialise all the clocks */
 
351
 
 
352
int __init s3c24xx_register_baseclocks(unsigned long xtal)
 
353
{
 
354
        printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n");
 
355
 
 
356
        clk_xtal.rate = xtal;
 
357
 
 
358
        /* register our clocks */
 
359
 
 
360
        if (s3c24xx_register_clock(&clk_xtal) < 0)
 
361
                printk(KERN_ERR "failed to register master xtal\n");
 
362
 
 
363
        if (s3c24xx_register_clock(&clk_mpll) < 0)
 
364
                printk(KERN_ERR "failed to register mpll clock\n");
 
365
 
 
366
        if (s3c24xx_register_clock(&clk_upll) < 0)
 
367
                printk(KERN_ERR "failed to register upll clock\n");
 
368
 
 
369
        if (s3c24xx_register_clock(&clk_f) < 0)
 
370
                printk(KERN_ERR "failed to register cpu fclk\n");
 
371
 
 
372
        if (s3c24xx_register_clock(&clk_h) < 0)
 
373
                printk(KERN_ERR "failed to register cpu hclk\n");
 
374
 
 
375
        if (s3c24xx_register_clock(&clk_p) < 0)
 
376
                printk(KERN_ERR "failed to register cpu pclk\n");
 
377
 
 
378
        return 0;
 
379
}
 
380
 
 
381
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
 
382
/* debugfs support to trace clock tree hierarchy and attributes */
 
383
 
 
384
static struct dentry *clk_debugfs_root;
 
385
 
 
386
static int clk_debugfs_register_one(struct clk *c)
 
387
{
 
388
        int err;
 
389
        struct dentry *d;
 
390
        struct clk *pa = c->parent;
 
391
        char s[255];
 
392
        char *p = s;
 
393
 
 
394
        p += sprintf(p, "%s", c->devname);
 
395
 
 
396
        d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
 
397
        if (!d)
 
398
                return -ENOMEM;
 
399
 
 
400
        c->dent = d;
 
401
 
 
402
        d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usage);
 
403
        if (!d) {
 
404
                err = -ENOMEM;
 
405
                goto err_out;
 
406
        }
 
407
 
 
408
        d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
 
409
        if (!d) {
 
410
                err = -ENOMEM;
 
411
                goto err_out;
 
412
        }
 
413
        return 0;
 
414
 
 
415
err_out:
 
416
        debugfs_remove_recursive(c->dent);
 
417
        return err;
 
418
}
 
419
 
 
420
static int clk_debugfs_register(struct clk *c)
 
421
{
 
422
        int err;
 
423
        struct clk *pa = c->parent;
 
424
 
 
425
        if (pa && !pa->dent) {
 
426
                err = clk_debugfs_register(pa);
 
427
                if (err)
 
428
                        return err;
 
429
        }
 
430
 
 
431
        if (!c->dent) {
 
432
                err = clk_debugfs_register_one(c);
 
433
                if (err)
 
434
                        return err;
 
435
        }
 
436
        return 0;
 
437
}
 
438
 
 
439
static int __init clk_debugfs_init(void)
 
440
{
 
441
        struct clk *c;
 
442
        struct dentry *d;
 
443
        int err;
 
444
 
 
445
        d = debugfs_create_dir("clock", NULL);
 
446
        if (!d)
 
447
                return -ENOMEM;
 
448
        clk_debugfs_root = d;
 
449
 
 
450
        list_for_each_entry(c, &clocks, list) {
 
451
                err = clk_debugfs_register(c);
 
452
                if (err)
 
453
                        goto err_out;
 
454
        }
 
455
        return 0;
 
456
 
 
457
err_out:
 
458
        debugfs_remove_recursive(clk_debugfs_root);
 
459
        return err;
 
460
}
 
461
late_initcall(clk_debugfs_init);
 
462
 
 
463
#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */