Merge git://git.infradead.org/battery-2.6
[pandora-kernel.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 #include <linux/platform_device.h>
13 #include <linux/delay.h>
14
15 #include <asm/arch/pxa-regs.h>
16 #include <asm/hardware.h>
17
18 #include "devices.h"
19 #include "generic.h"
20 #include "clock.h"
21
22 static LIST_HEAD(clocks);
23 static DEFINE_MUTEX(clocks_mutex);
24 static DEFINE_SPINLOCK(clocks_lock);
25
26 struct clk *clk_get(struct device *dev, const char *id)
27 {
28         struct clk *p, *clk = ERR_PTR(-ENOENT);
29
30         mutex_lock(&clocks_mutex);
31         list_for_each_entry(p, &clocks, node) {
32                 if (strcmp(id, p->name) == 0 &&
33                     (p->dev == NULL || p->dev == dev)) {
34                         clk = p;
35                         break;
36                 }
37         }
38         mutex_unlock(&clocks_mutex);
39
40         return clk;
41 }
42 EXPORT_SYMBOL(clk_get);
43
44 void clk_put(struct clk *clk)
45 {
46 }
47 EXPORT_SYMBOL(clk_put);
48
49 int clk_enable(struct clk *clk)
50 {
51         unsigned long flags;
52
53         spin_lock_irqsave(&clocks_lock, flags);
54         if (clk->enabled++ == 0)
55                 clk->ops->enable(clk);
56         spin_unlock_irqrestore(&clocks_lock, flags);
57
58         if (clk->delay)
59                 udelay(clk->delay);
60
61         return 0;
62 }
63 EXPORT_SYMBOL(clk_enable);
64
65 void clk_disable(struct clk *clk)
66 {
67         unsigned long flags;
68
69         WARN_ON(clk->enabled == 0);
70
71         spin_lock_irqsave(&clocks_lock, flags);
72         if (--clk->enabled == 0)
73                 clk->ops->disable(clk);
74         spin_unlock_irqrestore(&clocks_lock, flags);
75 }
76 EXPORT_SYMBOL(clk_disable);
77
78 unsigned long clk_get_rate(struct clk *clk)
79 {
80         unsigned long rate;
81
82         rate = clk->rate;
83         if (clk->ops->getrate)
84                 rate = clk->ops->getrate(clk);
85
86         return rate;
87 }
88 EXPORT_SYMBOL(clk_get_rate);
89
90
91 static void clk_gpio27_enable(struct clk *clk)
92 {
93         pxa_gpio_mode(GPIO11_3_6MHz_MD);
94 }
95
96 static void clk_gpio27_disable(struct clk *clk)
97 {
98 }
99
100 static const struct clkops clk_gpio27_ops = {
101         .enable         = clk_gpio27_enable,
102         .disable        = clk_gpio27_disable,
103 };
104
105
106 void clk_cken_enable(struct clk *clk)
107 {
108         CKEN |= 1 << clk->cken;
109 }
110
111 void clk_cken_disable(struct clk *clk)
112 {
113         CKEN &= ~(1 << clk->cken);
114 }
115
116 const struct clkops clk_cken_ops = {
117         .enable         = clk_cken_enable,
118         .disable        = clk_cken_disable,
119 };
120
121 static struct clk common_clks[] = {
122         {
123                 .name           = "GPIO27_CLK",
124                 .ops            = &clk_gpio27_ops,
125                 .rate           = 3686400,
126         },
127 };
128
129 void clks_register(struct clk *clks, size_t num)
130 {
131         int i;
132
133         mutex_lock(&clocks_mutex);
134         for (i = 0; i < num; i++)
135                 list_add(&clks[i].node, &clocks);
136         mutex_unlock(&clocks_mutex);
137 }
138
139 static int __init clk_init(void)
140 {
141         clks_register(common_clks, ARRAY_SIZE(common_clks));
142         return 0;
143 }
144 arch_initcall(clk_init);