]> git.ipfire.org Git - people/arne_f/kernel.git/blame - arch/blackfin/mach-bf609/clock.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[people/arne_f/kernel.git] / arch / blackfin / mach-bf609 / clock.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
96900315
SM
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>
18
19#include <asm/clocks.h>
20
21#define CGU0_CTL_DF (1 << 0)
22
23#define CGU0_CTL_MSEL_SHIFT 8
24#define CGU0_CTL_MSEL_MASK (0x7f << 8)
25
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)
42
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)
55
56#define CLK(_clk, _devname, _conname) \
57 { \
58 .clk = &_clk, \
59 .dev_id = _devname, \
60 .con_id = _conname, \
61 }
62
63#define NEEDS_INITIALIZATION 0x11
64
65static LIST_HEAD(clk_list);
66
67static void clk_reg_write_mask(u32 reg, uint32_t val, uint32_t mask)
68{
69 u32 val2;
70
71 val2 = bfin_read32(reg);
72 val2 &= ~mask;
73 val2 |= val;
74 bfin_write32(reg, val2);
75}
76
96900315
SM
77int wait_for_pll_align(void)
78{
79 int i = 10000;
80 while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN));
81
82 if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) {
97929003 83 printk(KERN_CRIT "fail to align clk\n");
96900315
SM
84 return -1;
85 }
97929003 86
96900315
SM
87 return 0;
88}
89
90int clk_enable(struct clk *clk)
91{
92 int ret = -EIO;
93 if (clk->ops && clk->ops->enable)
94 ret = clk->ops->enable(clk);
95 return ret;
96}
97EXPORT_SYMBOL(clk_enable);
98
99void clk_disable(struct clk *clk)
100{
accce8e7
MY
101 if (!clk)
102 return;
103
96900315
SM
104 if (clk->ops && clk->ops->disable)
105 clk->ops->disable(clk);
106}
107EXPORT_SYMBOL(clk_disable);
108
b48b3a39 109
96900315
SM
110unsigned long clk_get_rate(struct clk *clk)
111{
112 unsigned long ret = 0;
113 if (clk->ops && clk->ops->get_rate)
114 ret = clk->ops->get_rate(clk);
115 return ret;
116}
117EXPORT_SYMBOL(clk_get_rate);
118
119long clk_round_rate(struct clk *clk, unsigned long rate)
120{
b48b3a39 121 long ret = 0;
96900315
SM
122 if (clk->ops && clk->ops->round_rate)
123 ret = clk->ops->round_rate(clk, rate);
124 return ret;
125}
126EXPORT_SYMBOL(clk_round_rate);
127
128int clk_set_rate(struct clk *clk, unsigned long rate)
129{
130 int ret = -EIO;
131 if (clk->ops && clk->ops->set_rate)
132 ret = clk->ops->set_rate(clk, rate);
133 return ret;
134}
135EXPORT_SYMBOL(clk_set_rate);
136
137unsigned long vco_get_rate(struct clk *clk)
138{
139 return clk->rate;
140}
141
142unsigned long pll_get_rate(struct clk *clk)
143{
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;
154}
155
156unsigned long pll_round_rate(struct clk *clk, unsigned long rate)
157{
158 u32 div;
159 div = rate / clk->parent->rate;
160 return clk->parent->rate * div;
161}
162
163int pll_set_rate(struct clk *clk, unsigned long rate)
164{
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;
178}
179
180unsigned long cclk_get_rate(struct clk *clk)
181{
182 if (clk->parent)
183 return clk->parent->rate;
184 else
185 return 0;
186}
187
188unsigned long sys_clk_get_rate(struct clk *clk)
189{
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);
198
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;
207 }
208}
209
3036dccf
SM
210unsigned long dummy_get_rate(struct clk *clk)
211{
212 clk->parent->rate = clk_get_rate(clk->parent);
213 return clk->parent->rate;
214}
215
96900315
SM
216unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
217{
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);
224
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;
228
229 if (rate > max_rate)
230 return 0;
231
232 for (i = 1; i < clk->mask; i++) {
233 drate = max_rate / i;
234 if (rate >= drate)
235 return drate;
236 }
237 return 0;
238}
239
240int sys_clk_set_rate(struct clk *clk, unsigned long rate)
241{
242 u32 div = bfin_read32(CGU0_DIV);
243 div = (div & clk->mask) >> clk->shift;
244
245 rate = clk_round_rate(clk, rate);
246
247 if (!rate)
248 return -EINVAL;
249
250 div = (clk_get_rate(clk) * div) / rate;
251
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;
258}
259
260static struct clk_ops vco_ops = {
261 .get_rate = vco_get_rate,
262};
263
264static struct clk_ops pll_ops = {
265 .get_rate = pll_get_rate,
266 .set_rate = pll_set_rate,
267};
268
269static struct clk_ops cclk_ops = {
270 .get_rate = cclk_get_rate,
271};
272
273static 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,
277};
278
3036dccf
SM
279static struct clk_ops dummy_clk_ops = {
280 .get_rate = dummy_get_rate,
281};
282
96900315
SM
283static struct clk sys_clkin = {
284 .name = "SYS_CLKIN",
285 .rate = CONFIG_CLKIN_HZ,
286 .ops = &vco_ops,
287};
288
289static struct clk pll_clk = {
290 .name = "PLLCLK",
291 .rate = 500000000,
292 .parent = &sys_clkin,
293 .ops = &pll_ops,
294 .flags = NEEDS_INITIALIZATION,
295};
296
297static 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,
305};
306
307static struct clk cclk0 = {
308 .name = "CCLK0",
309 .parent = &cclk,
310 .ops = &cclk_ops,
311};
312
313static struct clk cclk1 = {
314 .name = "CCLK1",
315 .parent = &cclk,
316 .ops = &cclk_ops,
317};
318
319static 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,
327};
328
329static 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,
336};
337
338static 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,
345};
346
347static struct clk dclk = {
348 .name = "DCLK",
349 .rate = 500000000,
350 .mask = CGU0_DIV_DSEL_MASK,
351 .shift = CGU0_DIV_DSEL_SHIFT,
7c141c1c 352 .parent = &sys_clkin,
96900315
SM
353 .ops = &sys_clk_ops,
354};
355
356static 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,
362};
363
3036dccf
SM
364static struct clk ethclk = {
365 .name = "stmmaceth",
366 .parent = &sclk0,
367 .ops = &dummy_clk_ops,
368};
369
d91e14b3
SM
370static struct clk ethpclk = {
371 .name = "pclk",
372 .parent = &sclk0,
373 .ops = &dummy_clk_ops,
374};
375
c34cc248
SJ
376static struct clk spiclk = {
377 .name = "spi",
378 .parent = &sclk1,
379 .ops = &dummy_clk_ops,
380};
381
96900315
SM
382static 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"),
3036dccf 393 CLK(ethclk, NULL, "stmmaceth"),
d91e14b3 394 CLK(ethpclk, NULL, "pclk"),
c34cc248 395 CLK(spiclk, NULL, "spi"),
96900315
SM
396};
397
398int __init clk_init(void)
399{
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);
406 }
407 clkdev_add_table(bf609_clks, ARRAY_SIZE(bf609_clks));
408 return 0;
409}