This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / arm / mach-pxa / clock.c
1 /*
2  *  linux/arch/arm/mach-sa1100/clock.c
3  */
4 #include <linux/module.h>
5 #include <linux/kernel.h>
6 #include <linux/list.h>
7 #include <linux/errno.h>
8 #include <linux/err.h>
9 #include <linux/string.h>
10 #include <linux/clk.h>
11 #include <linux/spinlock.h>
12
13 #include <asm/arch/pxa-regs.h>
14 #include <asm/hardware.h>
15 #include <asm/semaphore.h>
16
17 struct clk {
18         struct list_head        node;
19         unsigned long           rate;
20         struct module           *owner;
21         const char              *name;
22         unsigned int            enabled;
23         void                    (*enable)(void);
24         void                    (*disable)(void);
25 };
26
27 static LIST_HEAD(clocks);
28 static DECLARE_MUTEX(clocks_sem);
29 static DEFINE_SPINLOCK(clocks_lock);
30
31 struct clk *clk_get(struct device *dev, const char *id)
32 {
33         struct clk *p, *clk = ERR_PTR(-ENOENT);
34
35         down(&clocks_sem);
36         list_for_each_entry(p, &clocks, node) {
37                 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
38                         clk = p;
39                         break;
40                 }
41         }
42         up(&clocks_sem);
43
44         return clk;
45 }
46 EXPORT_SYMBOL(clk_get);
47
48 void clk_put(struct clk *clk)
49 {
50         module_put(clk->owner);
51 }
52 EXPORT_SYMBOL(clk_put);
53
54 int clk_enable(struct clk *clk)
55 {
56         unsigned long flags;
57
58         spin_lock_irqsave(&clocks_lock, flags);
59         if (clk->enabled++ == 0)
60                 clk->enable();
61         spin_unlock_irqrestore(&clocks_lock, flags);
62         return 0;
63 }
64 EXPORT_SYMBOL(clk_enable);
65
66 void clk_disable(struct clk *clk)
67 {
68         unsigned long flags;
69
70         WARN_ON(clk->enabled == 0);
71
72         spin_lock_irqsave(&clocks_lock, flags);
73         if (--clk->enabled == 0)
74                 clk->disable();
75         spin_unlock_irqrestore(&clocks_lock, flags);
76 }
77 EXPORT_SYMBOL(clk_disable);
78
79 unsigned long clk_get_rate(struct clk *clk)
80 {
81         return clk->rate;
82 }
83 EXPORT_SYMBOL(clk_get_rate);
84
85
86 static void clk_gpio27_enable(void)
87 {
88         pxa_gpio_mode(GPIO11_3_6MHz_MD);
89 }
90
91 static void clk_gpio27_disable(void)
92 {
93 }
94
95 static struct clk clk_gpio27 = {
96         .name           = "GPIO27_CLK",
97         .rate           = 3686400,
98         .enable         = clk_gpio27_enable,
99         .disable        = clk_gpio27_disable,
100 };
101
102 int clk_register(struct clk *clk)
103 {
104         down(&clocks_sem);
105         list_add(&clk->node, &clocks);
106         up(&clocks_sem);
107         return 0;
108 }
109 EXPORT_SYMBOL(clk_register);
110
111 void clk_unregister(struct clk *clk)
112 {
113         down(&clocks_sem);
114         list_del(&clk->node);
115         up(&clocks_sem);
116 }
117 EXPORT_SYMBOL(clk_unregister);
118
119 static int __init clk_init(void)
120 {
121         clk_register(&clk_gpio27);
122         return 0;
123 }
124 arch_initcall(clk_init);