1d1324b6eae5189ceee3fe1d70b00255562981d0
[openwrt.git] / target / linux / mcs814x / files-3.3 / arch / arm / mach-mcs814x / clock.c
1 /*
2  * Moschip MCS814x clock routines
3  *
4  * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
5  *
6  * Licensed under GPLv2
7  */
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/export.h>
11 #include <linux/spinlock.h>
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/clkdev.h>
15 #include <linux/clk.h>
16
17 #include <mach/mcs814x.h>
18
19 #define KHZ     1000
20 #define MHZ     (KHZ * KHZ)
21
22 struct clk_ops {
23         unsigned long (*get_rate)(struct clk *clk);
24         int (*set_rate)(struct clk *clk, unsigned long rate);
25         struct clk *(*get_parent)(struct clk *clk);
26         int (*enable)(struct clk *clk, int enable);
27 };
28
29 struct clk {
30         struct clk *parent;             /* parent clk */
31         unsigned long rate;             /* clock rate in Hz */
32         unsigned long divider;          /* clock divider */
33         u32 usecount;                   /* reference count */
34         struct clk_ops *ops;            /* clock operation */
35         void __iomem *enable_reg;       /* clock enable register */
36         u32 enable_mask;                /* clock enable mask */
37 };
38
39 static unsigned long clk_divide_parent(struct clk *clk)
40 {
41         if (clk->parent && clk->divider)
42                 return clk_get_rate(clk->parent) / clk->divider;
43         else
44                 return 0;
45 }
46
47 static int clk_local_onoff_enable(struct clk *clk, int enable)
48 {
49         u32 tmp;
50
51         /* no enable_reg means the clock is always enabled */
52         if (!clk->enable_reg)
53                 return 0;
54
55         tmp = __raw_readl(clk->enable_reg);
56         if (!enable)
57                 tmp &= ~clk->enable_mask;
58         else
59                 tmp |= clk->enable_mask;
60
61         __raw_writel(tmp, clk->enable_reg);
62
63         return 0;
64 }
65
66 static struct clk_ops default_clk_ops = {
67         .get_rate       = clk_divide_parent,
68         .enable         = clk_local_onoff_enable,
69 };
70
71 static DEFINE_SPINLOCK(clocks_lock);
72
73 static const unsigned long cpu_freq_table[] = {
74         175000,
75         300000,
76         125000,
77         137500,
78         212500,
79         250000,
80         162500,
81         187500,
82         162500,
83         150000,
84         225000,
85         237500,
86         200000,
87         262500,
88         275000,
89         287500
90 };
91
92 static struct clk clk_cpu;
93
94 /* System clock is fixed at 50Mhz */
95 static struct clk clk_sys = {
96         .rate   = 50 * MHZ,
97 };
98
99 static struct clk clk_sdram;
100
101 static struct clk clk_timer0 = {
102         .parent = &clk_sdram,
103         .divider = 2,
104         .ops    = &default_clk_ops,
105 };
106
107 static struct clk clk_timer1_2 = {
108         .parent = &clk_sys,
109 };
110
111 /* Watchdog clock is system clock / 128 */
112 static struct clk clk_wdt = {
113         .parent = &clk_sys,
114         .divider = 128,
115         .ops    = &default_clk_ops,
116 };
117
118 static struct clk clk_emac = {
119         .ops            = &default_clk_ops,
120         .enable_reg     = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
121         .enable_mask    = SYSCTL_EMAC,
122 };
123
124 static struct clk clk_ephy = {
125         .ops            = &default_clk_ops,
126         .enable_reg     = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_PLL_CTL),
127         .enable_mask    = ~(1 << 0),
128 };
129
130 static struct clk clk_cipher = {
131         .ops            = &default_clk_ops,
132         .enable_reg     = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
133         .enable_mask    = SYSCTL_CIPHER,
134 };
135
136 #define CLK(_dev, _con, _clk)   \
137 { .dev_id = (_dev), .con_id = (_con), .clk = (_clk) },
138
139 static struct clk_lookup mcs814x_chip_clks[] = {
140         CLK("cpu", NULL, &clk_cpu)
141         CLK("sys", NULL, &clk_sys)
142         CLK("sdram", NULL, &clk_sdram)
143         /* 32-bits timer0 */
144         CLK("timer0", NULL, &clk_timer0)
145         /* 16-bits timer1 */
146         CLK("timer1", NULL, &clk_timer1_2)
147         /* 64-bits timer2, same as timer 1 */
148         CLK("timer2", NULL, &clk_timer1_2)
149         CLK(NULL, "wdt", &clk_wdt)
150         CLK(NULL, "emac", &clk_emac)
151         CLK(NULL, "ephy", &clk_ephy)
152         CLK(NULL, "cipher", &clk_cipher)
153 };
154
155 static void local_clk_disable(struct clk *clk)
156 {
157         WARN_ON(!clk->usecount);
158
159         if (clk->usecount > 0) {
160                 clk->usecount--;
161
162                 if ((clk->usecount == 0) && (clk->ops->enable))
163                         clk->ops->enable(clk, 0);
164
165                 if (clk->parent)
166                         local_clk_disable(clk->parent);
167         }
168 }
169
170 static int local_clk_enable(struct clk *clk)
171 {
172         int ret = 0;
173
174         if (clk->parent)
175                 ret = local_clk_enable(clk->parent);
176
177         if (ret)
178                 return ret;
179
180         if ((clk->usecount == 0) && (clk->ops->enable))
181                 ret = clk->ops->enable(clk, 1);
182
183         if (!ret)
184                 clk->usecount++;
185         else if (clk->parent && clk->parent->ops->enable)
186                 local_clk_disable(clk->parent);
187
188         return ret;
189 }
190
191 int clk_enable(struct clk *clk)
192 {
193         int ret;
194         unsigned long flags;
195
196         spin_lock_irqsave(&clocks_lock, flags);
197         ret = local_clk_enable(clk);
198         spin_unlock_irqrestore(&clocks_lock, flags);
199
200         return ret;
201 }
202 EXPORT_SYMBOL(clk_enable);
203
204 void clk_disable(struct clk *clk)
205 {
206         unsigned long flags;
207
208         spin_lock_irqsave(&clocks_lock, flags);
209         local_clk_disable(clk);
210         spin_unlock_irqrestore(&clocks_lock, flags);
211 }
212 EXPORT_SYMBOL(clk_disable);
213
214 unsigned long clk_get_rate(struct clk *clk)
215 {
216         if (unlikely(IS_ERR_OR_NULL(clk)))
217                 return 0;
218
219         if (clk->rate)
220                 return clk->rate;
221
222         if (clk->ops && clk->ops->get_rate)
223                 return clk->ops->get_rate(clk);
224
225         return clk_get_rate(clk->parent);
226 }
227 EXPORT_SYMBOL(clk_get_rate);
228
229 struct clk *clk_get_parent(struct clk *clk)
230 {
231         unsigned long flags;
232
233         if (unlikely(IS_ERR_OR_NULL(clk)))
234                 return NULL;
235
236         if (!clk->ops || !clk->ops->get_parent)
237                 return clk->parent;
238
239         spin_lock_irqsave(&clocks_lock, flags);
240         clk->parent = clk->ops->get_parent(clk);
241         spin_unlock_irqrestore(&clocks_lock, flags);
242
243         return clk->parent;
244 }
245 EXPORT_SYMBOL(clk_get_parent);
246
247 void __init mcs814x_clk_init(void)
248 {
249         u32 bs1;
250         u8 cpu_freq;
251
252         clkdev_add_table(mcs814x_chip_clks, ARRAY_SIZE(mcs814x_chip_clks));
253
254         /* read the bootstrap registers to know the exact clocking scheme */
255         bs1 = __raw_readl(_CONFADDR_SYSDBG + SYSDBG_BS1);
256         cpu_freq = (bs1 >> CPU_FREQ_SHIFT) & CPU_FREQ_MASK;
257
258         pr_info("CPU frequency: %lu (kHz)\n", cpu_freq_table[cpu_freq]);
259         clk_cpu.rate = cpu_freq * KHZ;
260
261         /* read SDRAM frequency */
262         if (bs1 & SDRAM_FREQ_BIT)
263                 clk_sdram.rate = 100 * MHZ;
264         else
265                 clk_sdram.rate = 133 * MHZ;
266
267         pr_info("SDRAM frequency: %lu (MHz)\n", clk_sdram.rate / MHZ);
268 }
269