Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / blackfin / mach-bf609 / clock.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/list.h>
4 #include <linux/errno.h>
5 #include <linux/err.h>
6 #include <linux/string.h>
7 #include <linux/clk.h>
8 #include <linux/mutex.h>
9 #include <linux/spinlock.h>
10 #include <linux/debugfs.h>
11 #include <linux/device.h>
12 #include <linux/init.h>
13 #include <linux/timer.h>
14 #include <linux/io.h>
15 #include <linux/seq_file.h>
16 #include <linux/clkdev.h>
17
18 #include <asm/clocks.h>
19
20 #define CGU0_CTL_DF (1 << 0)
21
22 #define CGU0_CTL_MSEL_SHIFT 8
23 #define CGU0_CTL_MSEL_MASK (0x7f << 8)
24
25 #define CGU0_STAT_PLLEN (1 << 0)
26 #define CGU0_STAT_PLLBP (1 << 1)
27 #define CGU0_STAT_PLLLK (1 << 2)
28 #define CGU0_STAT_CLKSALGN (1 << 3)
29 #define CGU0_STAT_CCBF0 (1 << 4)
30 #define CGU0_STAT_CCBF1 (1 << 5)
31 #define CGU0_STAT_SCBF0 (1 << 6)
32 #define CGU0_STAT_SCBF1 (1 << 7)
33 #define CGU0_STAT_DCBF (1 << 8)
34 #define CGU0_STAT_OCBF (1 << 9)
35 #define CGU0_STAT_ADDRERR (1 << 16)
36 #define CGU0_STAT_LWERR (1 << 17)
37 #define CGU0_STAT_DIVERR (1 << 18)
38 #define CGU0_STAT_WDFMSERR (1 << 19)
39 #define CGU0_STAT_WDIVERR (1 << 20)
40 #define CGU0_STAT_PLOCKERR (1 << 21)
41
42 #define CGU0_DIV_CSEL_SHIFT 0
43 #define CGU0_DIV_CSEL_MASK 0x0000001F
44 #define CGU0_DIV_S0SEL_SHIFT 5
45 #define CGU0_DIV_S0SEL_MASK (0x3 << CGU0_DIV_S0SEL_SHIFT)
46 #define CGU0_DIV_SYSSEL_SHIFT 8
47 #define CGU0_DIV_SYSSEL_MASK (0x1f << CGU0_DIV_SYSSEL_SHIFT)
48 #define CGU0_DIV_S1SEL_SHIFT 13
49 #define CGU0_DIV_S1SEL_MASK (0x3 << CGU0_DIV_S1SEL_SHIFT)
50 #define CGU0_DIV_DSEL_SHIFT 16
51 #define CGU0_DIV_DSEL_MASK (0x1f << CGU0_DIV_DSEL_SHIFT)
52 #define CGU0_DIV_OSEL_SHIFT 22
53 #define CGU0_DIV_OSEL_MASK (0x7f << CGU0_DIV_OSEL_SHIFT)
54
55 #define CLK(_clk, _devname, _conname)                   \
56         {                                               \
57                 .clk    = &_clk,                  \
58                 .dev_id = _devname,                     \
59                 .con_id = _conname,                     \
60         }
61
62 #define NEEDS_INITIALIZATION 0x11
63
64 static LIST_HEAD(clk_list);
65
66 static void clk_reg_write_mask(u32 reg, uint32_t val, uint32_t mask)
67 {
68         u32 val2;
69
70         val2 = bfin_read32(reg);
71         val2 &= ~mask;
72         val2 |= val;
73         bfin_write32(reg, val2);
74 }
75
76 static void clk_reg_set_bits(u32 reg, uint32_t mask)
77 {
78         u32 val;
79
80         val = bfin_read32(reg);
81         val |= mask;
82         bfin_write32(reg, val);
83 }
84
85 static void clk_reg_clear_bits(u32 reg, uint32_t mask)
86 {
87         u32 val;
88
89         val = bfin_read32(reg);
90         val &= ~mask;
91         bfin_write32(reg, val);
92 }
93
94 int wait_for_pll_align(void)
95 {
96         int i = 10000;
97         while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN));
98
99         if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) {
100                 printk(KERN_CRIT "fail to align clk\n");
101                 return -1;
102         }
103
104         return 0;
105 }
106
107 int clk_enable(struct clk *clk)
108 {
109         int ret = -EIO;
110         if (clk->ops && clk->ops->enable)
111                 ret = clk->ops->enable(clk);
112         return ret;
113 }
114 EXPORT_SYMBOL(clk_enable);
115
116 void clk_disable(struct clk *clk)
117 {
118         if (clk->ops && clk->ops->disable)
119                 clk->ops->disable(clk);
120 }
121 EXPORT_SYMBOL(clk_disable);
122
123 unsigned long clk_get_rate(struct clk *clk)
124 {
125         unsigned long ret = 0;
126         if (clk->ops && clk->ops->get_rate)
127                 ret = clk->ops->get_rate(clk);
128         return ret;
129 }
130 EXPORT_SYMBOL(clk_get_rate);
131
132 long clk_round_rate(struct clk *clk, unsigned long rate)
133 {
134         long ret = -EIO;
135         if (clk->ops && clk->ops->round_rate)
136                 ret = clk->ops->round_rate(clk, rate);
137         return ret;
138 }
139 EXPORT_SYMBOL(clk_round_rate);
140
141 int clk_set_rate(struct clk *clk, unsigned long rate)
142 {
143         int ret = -EIO;
144         if (clk->ops && clk->ops->set_rate)
145                 ret = clk->ops->set_rate(clk, rate);
146         return ret;
147 }
148 EXPORT_SYMBOL(clk_set_rate);
149
150 unsigned long vco_get_rate(struct clk *clk)
151 {
152         return clk->rate;
153 }
154
155 unsigned long pll_get_rate(struct clk *clk)
156 {
157         u32 df;
158         u32 msel;
159         u32 ctl = bfin_read32(CGU0_CTL);
160         u32 stat = bfin_read32(CGU0_STAT);
161         if (stat & CGU0_STAT_PLLBP)
162                 return 0;
163         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
164         df = (ctl &  CGU0_CTL_DF);
165         clk->parent->rate = clk_get_rate(clk->parent);
166         return clk->parent->rate / (df + 1) * msel * 2;
167 }
168
169 unsigned long pll_round_rate(struct clk *clk, unsigned long rate)
170 {
171         u32 div;
172         div = rate / clk->parent->rate;
173         return clk->parent->rate * div;
174 }
175
176 int pll_set_rate(struct clk *clk, unsigned long rate)
177 {
178         u32 msel;
179         u32 stat = bfin_read32(CGU0_STAT);
180         if (!(stat & CGU0_STAT_PLLEN))
181                 return -EBUSY;
182         if (!(stat & CGU0_STAT_PLLLK))
183                 return -EBUSY;
184         if (wait_for_pll_align())
185                 return -EBUSY;
186         msel = rate / clk->parent->rate / 2;
187         clk_reg_write_mask(CGU0_CTL, msel << CGU0_CTL_MSEL_SHIFT,
188                 CGU0_CTL_MSEL_MASK);
189         clk->rate = rate;
190         return 0;
191 }
192
193 unsigned long cclk_get_rate(struct clk *clk)
194 {
195         if (clk->parent)
196                 return clk->parent->rate;
197         else
198                 return 0;
199 }
200
201 unsigned long sys_clk_get_rate(struct clk *clk)
202 {
203         unsigned long drate;
204         u32 msel;
205         u32 df;
206         u32 ctl = bfin_read32(CGU0_CTL);
207         u32 div = bfin_read32(CGU0_DIV);
208         div = (div & clk->mask) >> clk->shift;
209         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
210         df = (ctl &  CGU0_CTL_DF);
211
212         if (!strcmp(clk->parent->name, "SYS_CLKIN")) {
213                 drate = clk->parent->rate / (df + 1);
214                 drate *=  msel;
215                 drate /= div;
216                 return drate;
217         } else {
218                 clk->parent->rate = clk_get_rate(clk->parent);
219                 return clk->parent->rate / div;
220         }
221 }
222
223 unsigned long dummy_get_rate(struct clk *clk)
224 {
225         clk->parent->rate = clk_get_rate(clk->parent);
226         return clk->parent->rate;
227 }
228
229 unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
230 {
231         unsigned long max_rate;
232         unsigned long drate;
233         int i;
234         u32 msel;
235         u32 df;
236         u32 ctl = bfin_read32(CGU0_CTL);
237
238         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
239         df = (ctl &  CGU0_CTL_DF);
240         max_rate = clk->parent->rate / (df + 1) * msel;
241
242         if (rate > max_rate)
243                 return 0;
244
245         for (i = 1; i < clk->mask; i++) {
246                 drate = max_rate / i;
247                 if (rate >= drate)
248                         return drate;
249         }
250         return 0;
251 }
252
253 int sys_clk_set_rate(struct clk *clk, unsigned long rate)
254 {
255         u32 div = bfin_read32(CGU0_DIV);
256         div = (div & clk->mask) >> clk->shift;
257
258         rate = clk_round_rate(clk, rate);
259
260         if (!rate)
261                 return -EINVAL;
262
263         div = (clk_get_rate(clk) * div) / rate;
264
265         if (wait_for_pll_align())
266                 return -EBUSY;
267         clk_reg_write_mask(CGU0_DIV, div << clk->shift,
268                         clk->mask);
269         clk->rate = rate;
270         return 0;
271 }
272
273 static struct clk_ops vco_ops = {
274         .get_rate = vco_get_rate,
275 };
276
277 static struct clk_ops pll_ops = {
278         .get_rate = pll_get_rate,
279         .set_rate = pll_set_rate,
280 };
281
282 static struct clk_ops cclk_ops = {
283         .get_rate = cclk_get_rate,
284 };
285
286 static struct clk_ops sys_clk_ops = {
287         .get_rate = sys_clk_get_rate,
288         .set_rate = sys_clk_set_rate,
289         .round_rate = sys_clk_round_rate,
290 };
291
292 static struct clk_ops dummy_clk_ops = {
293         .get_rate = dummy_get_rate,
294 };
295
296 static struct clk sys_clkin = {
297         .name       = "SYS_CLKIN",
298         .rate       = CONFIG_CLKIN_HZ,
299         .ops        = &vco_ops,
300 };
301
302 static struct clk pll_clk = {
303         .name       = "PLLCLK",
304         .rate       = 500000000,
305         .parent     = &sys_clkin,
306         .ops = &pll_ops,
307         .flags = NEEDS_INITIALIZATION,
308 };
309
310 static struct clk cclk = {
311         .name       = "CCLK",
312         .rate       = 500000000,
313         .mask       = CGU0_DIV_CSEL_MASK,
314         .shift      = CGU0_DIV_CSEL_SHIFT,
315         .parent     = &sys_clkin,
316         .ops        = &sys_clk_ops,
317         .flags = NEEDS_INITIALIZATION,
318 };
319
320 static struct clk cclk0 = {
321         .name       = "CCLK0",
322         .parent     = &cclk,
323         .ops        = &cclk_ops,
324 };
325
326 static struct clk cclk1 = {
327         .name       = "CCLK1",
328         .parent     = &cclk,
329         .ops        = &cclk_ops,
330 };
331
332 static struct clk sysclk = {
333         .name       = "SYSCLK",
334         .rate       = 500000000,
335         .mask       = CGU0_DIV_SYSSEL_MASK,
336         .shift      = CGU0_DIV_SYSSEL_SHIFT,
337         .parent     = &sys_clkin,
338         .ops        = &sys_clk_ops,
339         .flags = NEEDS_INITIALIZATION,
340 };
341
342 static struct clk sclk0 = {
343         .name       = "SCLK0",
344         .rate       = 500000000,
345         .mask       = CGU0_DIV_S0SEL_MASK,
346         .shift      = CGU0_DIV_S0SEL_SHIFT,
347         .parent     = &sysclk,
348         .ops        = &sys_clk_ops,
349 };
350
351 static struct clk sclk1 = {
352         .name       = "SCLK1",
353         .rate       = 500000000,
354         .mask       = CGU0_DIV_S1SEL_MASK,
355         .shift      = CGU0_DIV_S1SEL_SHIFT,
356         .parent     = &sysclk,
357         .ops        = &sys_clk_ops,
358 };
359
360 static struct clk dclk = {
361         .name       = "DCLK",
362         .rate       = 500000000,
363         .mask       = CGU0_DIV_DSEL_MASK,
364         .shift       = CGU0_DIV_DSEL_SHIFT,
365         .parent     = &sys_clkin,
366         .ops        = &sys_clk_ops,
367 };
368
369 static struct clk oclk = {
370         .name       = "OCLK",
371         .rate       = 500000000,
372         .mask       = CGU0_DIV_OSEL_MASK,
373         .shift      = CGU0_DIV_OSEL_SHIFT,
374         .parent     = &pll_clk,
375 };
376
377 static struct clk ethclk = {
378         .name       = "stmmaceth",
379         .parent     = &sclk0,
380         .ops        = &dummy_clk_ops,
381 };
382
383 static struct clk_lookup bf609_clks[] = {
384         CLK(sys_clkin, NULL, "SYS_CLKIN"),
385         CLK(pll_clk, NULL, "PLLCLK"),
386         CLK(cclk, NULL, "CCLK"),
387         CLK(cclk0, NULL, "CCLK0"),
388         CLK(cclk1, NULL, "CCLK1"),
389         CLK(sysclk, NULL, "SYSCLK"),
390         CLK(sclk0, NULL, "SCLK0"),
391         CLK(sclk1, NULL, "SCLK1"),
392         CLK(dclk, NULL, "DCLK"),
393         CLK(oclk, NULL, "OCLK"),
394         CLK(ethclk, NULL, "stmmaceth"),
395 };
396
397 int __init clk_init(void)
398 {
399         int i;
400         struct clk *clkp;
401         for (i = 0; i < ARRAY_SIZE(bf609_clks); i++) {
402                 clkp = bf609_clks[i].clk;
403                 if (clkp->flags & NEEDS_INITIALIZATION)
404                         clk_get_rate(clkp);
405         }
406         clkdev_add_table(bf609_clks, ARRAY_SIZE(bf609_clks));
407         return 0;
408 }