Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / arch / blackfin / mach-bf609 / clock.c
blob16e0b09e2197e40759d654b50d7334de8032bd13
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/list.h>
5 #include <linux/errno.h>
6 #include <linux/err.h>
7 #include <linux/string.h>
8 #include <linux/clk.h>
9 #include <linux/mutex.h>
10 #include <linux/spinlock.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
13 #include <linux/init.h>
14 #include <linux/timer.h>
15 #include <linux/io.h>
16 #include <linux/seq_file.h>
17 #include <linux/clkdev.h>
19 #include <asm/clocks.h>
21 #define CGU0_CTL_DF (1 << 0)
23 #define CGU0_CTL_MSEL_SHIFT 8
24 #define CGU0_CTL_MSEL_MASK (0x7f << 8)
26 #define CGU0_STAT_PLLEN (1 << 0)
27 #define CGU0_STAT_PLLBP (1 << 1)
28 #define CGU0_STAT_PLLLK (1 << 2)
29 #define CGU0_STAT_CLKSALGN (1 << 3)
30 #define CGU0_STAT_CCBF0 (1 << 4)
31 #define CGU0_STAT_CCBF1 (1 << 5)
32 #define CGU0_STAT_SCBF0 (1 << 6)
33 #define CGU0_STAT_SCBF1 (1 << 7)
34 #define CGU0_STAT_DCBF (1 << 8)
35 #define CGU0_STAT_OCBF (1 << 9)
36 #define CGU0_STAT_ADDRERR (1 << 16)
37 #define CGU0_STAT_LWERR (1 << 17)
38 #define CGU0_STAT_DIVERR (1 << 18)
39 #define CGU0_STAT_WDFMSERR (1 << 19)
40 #define CGU0_STAT_WDIVERR (1 << 20)
41 #define CGU0_STAT_PLOCKERR (1 << 21)
43 #define CGU0_DIV_CSEL_SHIFT 0
44 #define CGU0_DIV_CSEL_MASK 0x0000001F
45 #define CGU0_DIV_S0SEL_SHIFT 5
46 #define CGU0_DIV_S0SEL_MASK (0x3 << CGU0_DIV_S0SEL_SHIFT)
47 #define CGU0_DIV_SYSSEL_SHIFT 8
48 #define CGU0_DIV_SYSSEL_MASK (0x1f << CGU0_DIV_SYSSEL_SHIFT)
49 #define CGU0_DIV_S1SEL_SHIFT 13
50 #define CGU0_DIV_S1SEL_MASK (0x3 << CGU0_DIV_S1SEL_SHIFT)
51 #define CGU0_DIV_DSEL_SHIFT 16
52 #define CGU0_DIV_DSEL_MASK (0x1f << CGU0_DIV_DSEL_SHIFT)
53 #define CGU0_DIV_OSEL_SHIFT 22
54 #define CGU0_DIV_OSEL_MASK (0x7f << CGU0_DIV_OSEL_SHIFT)
56 #define CLK(_clk, _devname, _conname) \
57 { \
58 .clk = &_clk, \
59 .dev_id = _devname, \
60 .con_id = _conname, \
63 #define NEEDS_INITIALIZATION 0x11
65 static LIST_HEAD(clk_list);
67 static void clk_reg_write_mask(u32 reg, uint32_t val, uint32_t mask)
69 u32 val2;
71 val2 = bfin_read32(reg);
72 val2 &= ~mask;
73 val2 |= val;
74 bfin_write32(reg, val2);
77 int wait_for_pll_align(void)
79 int i = 10000;
80 while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN));
82 if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) {
83 printk(KERN_CRIT "fail to align clk\n");
84 return -1;
87 return 0;
90 int clk_enable(struct clk *clk)
92 int ret = -EIO;
93 if (clk->ops && clk->ops->enable)
94 ret = clk->ops->enable(clk);
95 return ret;
97 EXPORT_SYMBOL(clk_enable);
99 void clk_disable(struct clk *clk)
101 if (!clk)
102 return;
104 if (clk->ops && clk->ops->disable)
105 clk->ops->disable(clk);
107 EXPORT_SYMBOL(clk_disable);
110 unsigned long clk_get_rate(struct clk *clk)
112 unsigned long ret = 0;
113 if (clk->ops && clk->ops->get_rate)
114 ret = clk->ops->get_rate(clk);
115 return ret;
117 EXPORT_SYMBOL(clk_get_rate);
119 long clk_round_rate(struct clk *clk, unsigned long rate)
121 long ret = 0;
122 if (clk->ops && clk->ops->round_rate)
123 ret = clk->ops->round_rate(clk, rate);
124 return ret;
126 EXPORT_SYMBOL(clk_round_rate);
128 int clk_set_rate(struct clk *clk, unsigned long rate)
130 int ret = -EIO;
131 if (clk->ops && clk->ops->set_rate)
132 ret = clk->ops->set_rate(clk, rate);
133 return ret;
135 EXPORT_SYMBOL(clk_set_rate);
137 unsigned long vco_get_rate(struct clk *clk)
139 return clk->rate;
142 unsigned long pll_get_rate(struct clk *clk)
144 u32 df;
145 u32 msel;
146 u32 ctl = bfin_read32(CGU0_CTL);
147 u32 stat = bfin_read32(CGU0_STAT);
148 if (stat & CGU0_STAT_PLLBP)
149 return 0;
150 msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
151 df = (ctl & CGU0_CTL_DF);
152 clk->parent->rate = clk_get_rate(clk->parent);
153 return clk->parent->rate / (df + 1) * msel * 2;
156 unsigned long pll_round_rate(struct clk *clk, unsigned long rate)
158 u32 div;
159 div = rate / clk->parent->rate;
160 return clk->parent->rate * div;
163 int pll_set_rate(struct clk *clk, unsigned long rate)
165 u32 msel;
166 u32 stat = bfin_read32(CGU0_STAT);
167 if (!(stat & CGU0_STAT_PLLEN))
168 return -EBUSY;
169 if (!(stat & CGU0_STAT_PLLLK))
170 return -EBUSY;
171 if (wait_for_pll_align())
172 return -EBUSY;
173 msel = rate / clk->parent->rate / 2;
174 clk_reg_write_mask(CGU0_CTL, msel << CGU0_CTL_MSEL_SHIFT,
175 CGU0_CTL_MSEL_MASK);
176 clk->rate = rate;
177 return 0;
180 unsigned long cclk_get_rate(struct clk *clk)
182 if (clk->parent)
183 return clk->parent->rate;
184 else
185 return 0;
188 unsigned long sys_clk_get_rate(struct clk *clk)
190 unsigned long drate;
191 u32 msel;
192 u32 df;
193 u32 ctl = bfin_read32(CGU0_CTL);
194 u32 div = bfin_read32(CGU0_DIV);
195 div = (div & clk->mask) >> clk->shift;
196 msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
197 df = (ctl & CGU0_CTL_DF);
199 if (!strcmp(clk->parent->name, "SYS_CLKIN")) {
200 drate = clk->parent->rate / (df + 1);
201 drate *= msel;
202 drate /= div;
203 return drate;
204 } else {
205 clk->parent->rate = clk_get_rate(clk->parent);
206 return clk->parent->rate / div;
210 unsigned long dummy_get_rate(struct clk *clk)
212 clk->parent->rate = clk_get_rate(clk->parent);
213 return clk->parent->rate;
216 unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
218 unsigned long max_rate;
219 unsigned long drate;
220 int i;
221 u32 msel;
222 u32 df;
223 u32 ctl = bfin_read32(CGU0_CTL);
225 msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT;
226 df = (ctl & CGU0_CTL_DF);
227 max_rate = clk->parent->rate / (df + 1) * msel;
229 if (rate > max_rate)
230 return 0;
232 for (i = 1; i < clk->mask; i++) {
233 drate = max_rate / i;
234 if (rate >= drate)
235 return drate;
237 return 0;
240 int sys_clk_set_rate(struct clk *clk, unsigned long rate)
242 u32 div = bfin_read32(CGU0_DIV);
243 div = (div & clk->mask) >> clk->shift;
245 rate = clk_round_rate(clk, rate);
247 if (!rate)
248 return -EINVAL;
250 div = (clk_get_rate(clk) * div) / rate;
252 if (wait_for_pll_align())
253 return -EBUSY;
254 clk_reg_write_mask(CGU0_DIV, div << clk->shift,
255 clk->mask);
256 clk->rate = rate;
257 return 0;
260 static struct clk_ops vco_ops = {
261 .get_rate = vco_get_rate,
264 static struct clk_ops pll_ops = {
265 .get_rate = pll_get_rate,
266 .set_rate = pll_set_rate,
269 static struct clk_ops cclk_ops = {
270 .get_rate = cclk_get_rate,
273 static struct clk_ops sys_clk_ops = {
274 .get_rate = sys_clk_get_rate,
275 .set_rate = sys_clk_set_rate,
276 .round_rate = sys_clk_round_rate,
279 static struct clk_ops dummy_clk_ops = {
280 .get_rate = dummy_get_rate,
283 static struct clk sys_clkin = {
284 .name = "SYS_CLKIN",
285 .rate = CONFIG_CLKIN_HZ,
286 .ops = &vco_ops,
289 static struct clk pll_clk = {
290 .name = "PLLCLK",
291 .rate = 500000000,
292 .parent = &sys_clkin,
293 .ops = &pll_ops,
294 .flags = NEEDS_INITIALIZATION,
297 static struct clk cclk = {
298 .name = "CCLK",
299 .rate = 500000000,
300 .mask = CGU0_DIV_CSEL_MASK,
301 .shift = CGU0_DIV_CSEL_SHIFT,
302 .parent = &sys_clkin,
303 .ops = &sys_clk_ops,
304 .flags = NEEDS_INITIALIZATION,
307 static struct clk cclk0 = {
308 .name = "CCLK0",
309 .parent = &cclk,
310 .ops = &cclk_ops,
313 static struct clk cclk1 = {
314 .name = "CCLK1",
315 .parent = &cclk,
316 .ops = &cclk_ops,
319 static struct clk sysclk = {
320 .name = "SYSCLK",
321 .rate = 500000000,
322 .mask = CGU0_DIV_SYSSEL_MASK,
323 .shift = CGU0_DIV_SYSSEL_SHIFT,
324 .parent = &sys_clkin,
325 .ops = &sys_clk_ops,
326 .flags = NEEDS_INITIALIZATION,
329 static struct clk sclk0 = {
330 .name = "SCLK0",
331 .rate = 500000000,
332 .mask = CGU0_DIV_S0SEL_MASK,
333 .shift = CGU0_DIV_S0SEL_SHIFT,
334 .parent = &sysclk,
335 .ops = &sys_clk_ops,
338 static struct clk sclk1 = {
339 .name = "SCLK1",
340 .rate = 500000000,
341 .mask = CGU0_DIV_S1SEL_MASK,
342 .shift = CGU0_DIV_S1SEL_SHIFT,
343 .parent = &sysclk,
344 .ops = &sys_clk_ops,
347 static struct clk dclk = {
348 .name = "DCLK",
349 .rate = 500000000,
350 .mask = CGU0_DIV_DSEL_MASK,
351 .shift = CGU0_DIV_DSEL_SHIFT,
352 .parent = &sys_clkin,
353 .ops = &sys_clk_ops,
356 static struct clk oclk = {
357 .name = "OCLK",
358 .rate = 500000000,
359 .mask = CGU0_DIV_OSEL_MASK,
360 .shift = CGU0_DIV_OSEL_SHIFT,
361 .parent = &pll_clk,
364 static struct clk ethclk = {
365 .name = "stmmaceth",
366 .parent = &sclk0,
367 .ops = &dummy_clk_ops,
370 static struct clk ethpclk = {
371 .name = "pclk",
372 .parent = &sclk0,
373 .ops = &dummy_clk_ops,
376 static struct clk spiclk = {
377 .name = "spi",
378 .parent = &sclk1,
379 .ops = &dummy_clk_ops,
382 static struct clk_lookup bf609_clks[] = {
383 CLK(sys_clkin, NULL, "SYS_CLKIN"),
384 CLK(pll_clk, NULL, "PLLCLK"),
385 CLK(cclk, NULL, "CCLK"),
386 CLK(cclk0, NULL, "CCLK0"),
387 CLK(cclk1, NULL, "CCLK1"),
388 CLK(sysclk, NULL, "SYSCLK"),
389 CLK(sclk0, NULL, "SCLK0"),
390 CLK(sclk1, NULL, "SCLK1"),
391 CLK(dclk, NULL, "DCLK"),
392 CLK(oclk, NULL, "OCLK"),
393 CLK(ethclk, NULL, "stmmaceth"),
394 CLK(ethpclk, NULL, "pclk"),
395 CLK(spiclk, NULL, "spi"),
398 int __init clk_init(void)
400 int i;
401 struct clk *clkp;
402 for (i = 0; i < ARRAY_SIZE(bf609_clks); i++) {
403 clkp = bf609_clks[i].clk;
404 if (clkp->flags & NEEDS_INITIALIZATION)
405 clk_get_rate(clkp);
407 clkdev_add_table(bf609_clks, ARRAY_SIZE(bf609_clks));
408 return 0;