]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/blackfin/mach-bf609/clock.c
Merge tag 'nfs-for-4.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[karo-tx-linux.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 int wait_for_pll_align(void)
77 {
78         int i = 10000;
79         while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN));
80
81         if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) {
82                 printk(KERN_CRIT "fail to align clk\n");
83                 return -1;
84         }
85
86         return 0;
87 }
88
89 int clk_enable(struct clk *clk)
90 {
91         int ret = -EIO;
92         if (clk->ops && clk->ops->enable)
93                 ret = clk->ops->enable(clk);
94         return ret;
95 }
96 EXPORT_SYMBOL(clk_enable);
97
98 void clk_disable(struct clk *clk)
99 {
100         if (!clk)
101                 return;
102
103         if (clk->ops && clk->ops->disable)
104                 clk->ops->disable(clk);
105 }
106 EXPORT_SYMBOL(clk_disable);
107
108
109 unsigned long clk_get_rate(struct clk *clk)
110 {
111         unsigned long ret = 0;
112         if (clk->ops && clk->ops->get_rate)
113                 ret = clk->ops->get_rate(clk);
114         return ret;
115 }
116 EXPORT_SYMBOL(clk_get_rate);
117
118 long clk_round_rate(struct clk *clk, unsigned long rate)
119 {
120         long ret = 0;
121         if (clk->ops && clk->ops->round_rate)
122                 ret = clk->ops->round_rate(clk, rate);
123         return ret;
124 }
125 EXPORT_SYMBOL(clk_round_rate);
126
127 int clk_set_rate(struct clk *clk, unsigned long rate)
128 {
129         int ret = -EIO;
130         if (clk->ops && clk->ops->set_rate)
131                 ret = clk->ops->set_rate(clk, rate);
132         return ret;
133 }
134 EXPORT_SYMBOL(clk_set_rate);
135
136 unsigned long vco_get_rate(struct clk *clk)
137 {
138         return clk->rate;
139 }
140
141 unsigned long pll_get_rate(struct clk *clk)
142 {
143         u32 df;
144         u32 msel;
145         u32 ctl = bfin_read32(CGU0_CTL);
146         u32 stat = bfin_read32(CGU0_STAT);
147         if (stat & CGU0_STAT_PLLBP)
148                 return 0;
149         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
150         df = (ctl &  CGU0_CTL_DF);
151         clk->parent->rate = clk_get_rate(clk->parent);
152         return clk->parent->rate / (df + 1) * msel * 2;
153 }
154
155 unsigned long pll_round_rate(struct clk *clk, unsigned long rate)
156 {
157         u32 div;
158         div = rate / clk->parent->rate;
159         return clk->parent->rate * div;
160 }
161
162 int pll_set_rate(struct clk *clk, unsigned long rate)
163 {
164         u32 msel;
165         u32 stat = bfin_read32(CGU0_STAT);
166         if (!(stat & CGU0_STAT_PLLEN))
167                 return -EBUSY;
168         if (!(stat & CGU0_STAT_PLLLK))
169                 return -EBUSY;
170         if (wait_for_pll_align())
171                 return -EBUSY;
172         msel = rate / clk->parent->rate / 2;
173         clk_reg_write_mask(CGU0_CTL, msel << CGU0_CTL_MSEL_SHIFT,
174                 CGU0_CTL_MSEL_MASK);
175         clk->rate = rate;
176         return 0;
177 }
178
179 unsigned long cclk_get_rate(struct clk *clk)
180 {
181         if (clk->parent)
182                 return clk->parent->rate;
183         else
184                 return 0;
185 }
186
187 unsigned long sys_clk_get_rate(struct clk *clk)
188 {
189         unsigned long drate;
190         u32 msel;
191         u32 df;
192         u32 ctl = bfin_read32(CGU0_CTL);
193         u32 div = bfin_read32(CGU0_DIV);
194         div = (div & clk->mask) >> clk->shift;
195         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
196         df = (ctl &  CGU0_CTL_DF);
197
198         if (!strcmp(clk->parent->name, "SYS_CLKIN")) {
199                 drate = clk->parent->rate / (df + 1);
200                 drate *=  msel;
201                 drate /= div;
202                 return drate;
203         } else {
204                 clk->parent->rate = clk_get_rate(clk->parent);
205                 return clk->parent->rate / div;
206         }
207 }
208
209 unsigned long dummy_get_rate(struct clk *clk)
210 {
211         clk->parent->rate = clk_get_rate(clk->parent);
212         return clk->parent->rate;
213 }
214
215 unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
216 {
217         unsigned long max_rate;
218         unsigned long drate;
219         int i;
220         u32 msel;
221         u32 df;
222         u32 ctl = bfin_read32(CGU0_CTL);
223
224         msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
225         df = (ctl &  CGU0_CTL_DF);
226         max_rate = clk->parent->rate / (df + 1) * msel;
227
228         if (rate > max_rate)
229                 return 0;
230
231         for (i = 1; i < clk->mask; i++) {
232                 drate = max_rate / i;
233                 if (rate >= drate)
234                         return drate;
235         }
236         return 0;
237 }
238
239 int sys_clk_set_rate(struct clk *clk, unsigned long rate)
240 {
241         u32 div = bfin_read32(CGU0_DIV);
242         div = (div & clk->mask) >> clk->shift;
243
244         rate = clk_round_rate(clk, rate);
245
246         if (!rate)
247                 return -EINVAL;
248
249         div = (clk_get_rate(clk) * div) / rate;
250
251         if (wait_for_pll_align())
252                 return -EBUSY;
253         clk_reg_write_mask(CGU0_DIV, div << clk->shift,
254                         clk->mask);
255         clk->rate = rate;
256         return 0;
257 }
258
259 static struct clk_ops vco_ops = {
260         .get_rate = vco_get_rate,
261 };
262
263 static struct clk_ops pll_ops = {
264         .get_rate = pll_get_rate,
265         .set_rate = pll_set_rate,
266 };
267
268 static struct clk_ops cclk_ops = {
269         .get_rate = cclk_get_rate,
270 };
271
272 static struct clk_ops sys_clk_ops = {
273         .get_rate = sys_clk_get_rate,
274         .set_rate = sys_clk_set_rate,
275         .round_rate = sys_clk_round_rate,
276 };
277
278 static struct clk_ops dummy_clk_ops = {
279         .get_rate = dummy_get_rate,
280 };
281
282 static struct clk sys_clkin = {
283         .name       = "SYS_CLKIN",
284         .rate       = CONFIG_CLKIN_HZ,
285         .ops        = &vco_ops,
286 };
287
288 static struct clk pll_clk = {
289         .name       = "PLLCLK",
290         .rate       = 500000000,
291         .parent     = &sys_clkin,
292         .ops = &pll_ops,
293         .flags = NEEDS_INITIALIZATION,
294 };
295
296 static struct clk cclk = {
297         .name       = "CCLK",
298         .rate       = 500000000,
299         .mask       = CGU0_DIV_CSEL_MASK,
300         .shift      = CGU0_DIV_CSEL_SHIFT,
301         .parent     = &sys_clkin,
302         .ops        = &sys_clk_ops,
303         .flags = NEEDS_INITIALIZATION,
304 };
305
306 static struct clk cclk0 = {
307         .name       = "CCLK0",
308         .parent     = &cclk,
309         .ops        = &cclk_ops,
310 };
311
312 static struct clk cclk1 = {
313         .name       = "CCLK1",
314         .parent     = &cclk,
315         .ops        = &cclk_ops,
316 };
317
318 static struct clk sysclk = {
319         .name       = "SYSCLK",
320         .rate       = 500000000,
321         .mask       = CGU0_DIV_SYSSEL_MASK,
322         .shift      = CGU0_DIV_SYSSEL_SHIFT,
323         .parent     = &sys_clkin,
324         .ops        = &sys_clk_ops,
325         .flags = NEEDS_INITIALIZATION,
326 };
327
328 static struct clk sclk0 = {
329         .name       = "SCLK0",
330         .rate       = 500000000,
331         .mask       = CGU0_DIV_S0SEL_MASK,
332         .shift      = CGU0_DIV_S0SEL_SHIFT,
333         .parent     = &sysclk,
334         .ops        = &sys_clk_ops,
335 };
336
337 static struct clk sclk1 = {
338         .name       = "SCLK1",
339         .rate       = 500000000,
340         .mask       = CGU0_DIV_S1SEL_MASK,
341         .shift      = CGU0_DIV_S1SEL_SHIFT,
342         .parent     = &sysclk,
343         .ops        = &sys_clk_ops,
344 };
345
346 static struct clk dclk = {
347         .name       = "DCLK",
348         .rate       = 500000000,
349         .mask       = CGU0_DIV_DSEL_MASK,
350         .shift       = CGU0_DIV_DSEL_SHIFT,
351         .parent     = &sys_clkin,
352         .ops        = &sys_clk_ops,
353 };
354
355 static struct clk oclk = {
356         .name       = "OCLK",
357         .rate       = 500000000,
358         .mask       = CGU0_DIV_OSEL_MASK,
359         .shift      = CGU0_DIV_OSEL_SHIFT,
360         .parent     = &pll_clk,
361 };
362
363 static struct clk ethclk = {
364         .name       = "stmmaceth",
365         .parent     = &sclk0,
366         .ops        = &dummy_clk_ops,
367 };
368
369 static struct clk ethpclk = {
370         .name       = "pclk",
371         .parent     = &sclk0,
372         .ops        = &dummy_clk_ops,
373 };
374
375 static struct clk spiclk = {
376         .name       = "spi",
377         .parent     = &sclk1,
378         .ops        = &dummy_clk_ops,
379 };
380
381 static struct clk_lookup bf609_clks[] = {
382         CLK(sys_clkin, NULL, "SYS_CLKIN"),
383         CLK(pll_clk, NULL, "PLLCLK"),
384         CLK(cclk, NULL, "CCLK"),
385         CLK(cclk0, NULL, "CCLK0"),
386         CLK(cclk1, NULL, "CCLK1"),
387         CLK(sysclk, NULL, "SYSCLK"),
388         CLK(sclk0, NULL, "SCLK0"),
389         CLK(sclk1, NULL, "SCLK1"),
390         CLK(dclk, NULL, "DCLK"),
391         CLK(oclk, NULL, "OCLK"),
392         CLK(ethclk, NULL, "stmmaceth"),
393         CLK(ethpclk, NULL, "pclk"),
394         CLK(spiclk, NULL, "spi"),
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 }