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>
7 #include <linux/string.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>
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) \
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
)
71 val2
= bfin_read32(reg
);
74 bfin_write32(reg
, val2
);
77 int wait_for_pll_align(void)
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");
90 int clk_enable(struct clk
*clk
)
93 if (clk
->ops
&& clk
->ops
->enable
)
94 ret
= clk
->ops
->enable(clk
);
97 EXPORT_SYMBOL(clk_enable
);
99 void clk_disable(struct clk
*clk
)
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
);
117 EXPORT_SYMBOL(clk_get_rate
);
119 long clk_round_rate(struct clk
*clk
, unsigned long rate
)
122 if (clk
->ops
&& clk
->ops
->round_rate
)
123 ret
= clk
->ops
->round_rate(clk
, rate
);
126 EXPORT_SYMBOL(clk_round_rate
);
128 int clk_set_rate(struct clk
*clk
, unsigned long rate
)
131 if (clk
->ops
&& clk
->ops
->set_rate
)
132 ret
= clk
->ops
->set_rate(clk
, rate
);
135 EXPORT_SYMBOL(clk_set_rate
);
137 unsigned long vco_get_rate(struct clk
*clk
)
142 unsigned long pll_get_rate(struct clk
*clk
)
146 u32 ctl
= bfin_read32(CGU0_CTL
);
147 u32 stat
= bfin_read32(CGU0_STAT
);
148 if (stat
& CGU0_STAT_PLLBP
)
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
)
159 div
= rate
/ clk
->parent
->rate
;
160 return clk
->parent
->rate
* div
;
163 int pll_set_rate(struct clk
*clk
, unsigned long rate
)
166 u32 stat
= bfin_read32(CGU0_STAT
);
167 if (!(stat
& CGU0_STAT_PLLEN
))
169 if (!(stat
& CGU0_STAT_PLLLK
))
171 if (wait_for_pll_align())
173 msel
= rate
/ clk
->parent
->rate
/ 2;
174 clk_reg_write_mask(CGU0_CTL
, msel
<< CGU0_CTL_MSEL_SHIFT
,
180 unsigned long cclk_get_rate(struct clk
*clk
)
183 return clk
->parent
->rate
;
188 unsigned long sys_clk_get_rate(struct clk
*clk
)
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);
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
;
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
;
232 for (i
= 1; i
< clk
->mask
; i
++) {
233 drate
= max_rate
/ i
;
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
);
250 div
= (clk_get_rate(clk
) * div
) / rate
;
252 if (wait_for_pll_align())
254 clk_reg_write_mask(CGU0_DIV
, div
<< clk
->shift
,
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
= {
285 .rate
= CONFIG_CLKIN_HZ
,
289 static struct clk pll_clk
= {
292 .parent
= &sys_clkin
,
294 .flags
= NEEDS_INITIALIZATION
,
297 static struct clk cclk
= {
300 .mask
= CGU0_DIV_CSEL_MASK
,
301 .shift
= CGU0_DIV_CSEL_SHIFT
,
302 .parent
= &sys_clkin
,
304 .flags
= NEEDS_INITIALIZATION
,
307 static struct clk cclk0
= {
313 static struct clk cclk1
= {
319 static struct clk sysclk
= {
322 .mask
= CGU0_DIV_SYSSEL_MASK
,
323 .shift
= CGU0_DIV_SYSSEL_SHIFT
,
324 .parent
= &sys_clkin
,
326 .flags
= NEEDS_INITIALIZATION
,
329 static struct clk sclk0
= {
332 .mask
= CGU0_DIV_S0SEL_MASK
,
333 .shift
= CGU0_DIV_S0SEL_SHIFT
,
338 static struct clk sclk1
= {
341 .mask
= CGU0_DIV_S1SEL_MASK
,
342 .shift
= CGU0_DIV_S1SEL_SHIFT
,
347 static struct clk dclk
= {
350 .mask
= CGU0_DIV_DSEL_MASK
,
351 .shift
= CGU0_DIV_DSEL_SHIFT
,
352 .parent
= &sys_clkin
,
356 static struct clk oclk
= {
359 .mask
= CGU0_DIV_OSEL_MASK
,
360 .shift
= CGU0_DIV_OSEL_SHIFT
,
364 static struct clk ethclk
= {
367 .ops
= &dummy_clk_ops
,
370 static struct clk ethpclk
= {
373 .ops
= &dummy_clk_ops
,
376 static struct clk spiclk
= {
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)
402 for (i
= 0; i
< ARRAY_SIZE(bf609_clks
); i
++) {
403 clkp
= bf609_clks
[i
].clk
;
404 if (clkp
->flags
& NEEDS_INITIALIZATION
)
407 clkdev_add_table(bf609_clks
, ARRAY_SIZE(bf609_clks
));