1 // SPDX-License-Identifier: GPL-2.0
3 // Spreadtrum pll clock driver
5 // Copyright (C) 2015~2017 Spreadtrum, Inc.
6 // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
8 #include <linux/delay.h>
10 #include <linux/regmap.h>
11 #include <linux/slab.h>
15 #define CLK_PLL_1M 1000000
16 #define CLK_PLL_10M (CLK_PLL_1M * 10)
18 #define pindex(pll, member) \
19 (pll->factors[member].shift / (8 * sizeof(pll->regs_num)))
21 #define pshift(pll, member) \
22 (pll->factors[member].shift % (8 * sizeof(pll->regs_num)))
24 #define pwidth(pll, member) \
25 pll->factors[member].width
27 #define pmask(pll, member) \
28 ((pwidth(pll, member)) ? \
29 GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
30 pshift(pll, member)) : 0)
32 #define pinternal(pll, cfg, member) \
33 (cfg[pindex(pll, member)] & pmask(pll, member))
35 #define pinternal_val(pll, cfg, member) \
36 (pinternal(pll, cfg, member) >> pshift(pll, member))
38 static inline unsigned int
39 sprd_pll_read(const struct sprd_pll
*pll
, u8 index
)
41 const struct sprd_clk_common
*common
= &pll
->common
;
44 if (WARN_ON(index
>= pll
->regs_num
))
47 regmap_read(common
->regmap
, common
->reg
+ index
* 4, &val
);
53 sprd_pll_write(const struct sprd_pll
*pll
, u8 index
,
56 const struct sprd_clk_common
*common
= &pll
->common
;
57 unsigned int offset
, reg
;
60 if (WARN_ON(index
>= pll
->regs_num
))
63 offset
= common
->reg
+ index
* 4;
64 ret
= regmap_read(common
->regmap
, offset
, ®
);
66 regmap_write(common
->regmap
, offset
, (reg
& ~msk
) | val
);
69 static unsigned long pll_get_refin(const struct sprd_pll
*pll
)
71 u32 shift
, mask
, index
, refin_id
= 3;
72 const unsigned long refin
[4] = { 2, 4, 13, 26 };
74 if (pwidth(pll
, PLL_REFIN
)) {
75 index
= pindex(pll
, PLL_REFIN
);
76 shift
= pshift(pll
, PLL_REFIN
);
77 mask
= pmask(pll
, PLL_REFIN
);
78 refin_id
= (sprd_pll_read(pll
, index
) & mask
) >> shift
;
83 return refin
[refin_id
];
86 static u32
pll_get_ibias(u64 rate
, const u64
*table
)
88 u32 i
, num
= table
[0];
90 /* table[0] indicates the number of items in this table */
91 for (i
= 0; i
< num
; i
++)
92 if (rate
<= table
[i
+ 1])
95 return i
== num
? num
- 1 : i
;
98 static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll
*pll
,
99 unsigned long parent_rate
)
102 u32 i
, mask
, regs_num
= pll
->regs_num
;
103 unsigned long rate
, nint
, kint
= 0;
107 cfg
= kcalloc(regs_num
, sizeof(*cfg
), GFP_KERNEL
);
111 for (i
= 0; i
< regs_num
; i
++)
112 cfg
[i
] = sprd_pll_read(pll
, i
);
114 refin
= pll_get_refin(pll
);
116 if (pinternal(pll
, cfg
, PLL_PREDIV
))
119 if (pwidth(pll
, PLL_POSTDIV
) &&
120 ((pll
->fflag
== 1 && pinternal(pll
, cfg
, PLL_POSTDIV
)) ||
121 (!pll
->fflag
&& !pinternal(pll
, cfg
, PLL_POSTDIV
))))
124 if (!pinternal(pll
, cfg
, PLL_DIV_S
)) {
125 rate
= refin
* pinternal_val(pll
, cfg
, PLL_N
) * CLK_PLL_10M
;
127 nint
= pinternal_val(pll
, cfg
, PLL_NINT
);
128 if (pinternal(pll
, cfg
, PLL_SDM_EN
))
129 kint
= pinternal_val(pll
, cfg
, PLL_KINT
);
131 mask
= pmask(pll
, PLL_KINT
);
135 rate
= DIV_ROUND_CLOSEST_ULL(refin
* kint
* k1
,
136 ((mask
>> __ffs(mask
)) + 1)) *
137 k2
+ refin
* nint
* CLK_PLL_1M
;
144 #define SPRD_PLL_WRITE_CHECK(pll, i, mask, val) \
145 (((sprd_pll_read(pll, i) & mask) == val) ? 0 : (-EFAULT))
147 static int _sprd_pll_set_rate(const struct sprd_pll
*pll
,
149 unsigned long parent_rate
)
153 u32 mask
, shift
, width
, ibias_val
, index
;
154 u32 regs_num
= pll
->regs_num
, i
= 0;
155 unsigned long kint
, nint
;
156 u64 tmp
, refin
, fvco
= rate
;
158 cfg
= kcalloc(regs_num
, sizeof(*cfg
), GFP_KERNEL
);
162 refin
= pll_get_refin(pll
);
164 mask
= pmask(pll
, PLL_PREDIV
);
165 index
= pindex(pll
, PLL_PREDIV
);
166 width
= pwidth(pll
, PLL_PREDIV
);
167 if (width
&& (sprd_pll_read(pll
, index
) & mask
))
170 mask
= pmask(pll
, PLL_POSTDIV
);
171 index
= pindex(pll
, PLL_POSTDIV
);
172 width
= pwidth(pll
, PLL_POSTDIV
);
173 cfg
[index
].msk
= mask
;
174 if (width
&& ((pll
->fflag
== 1 && fvco
<= pll
->fvco
) ||
175 (pll
->fflag
== 0 && fvco
> pll
->fvco
)))
176 cfg
[index
].val
|= mask
;
178 if (width
&& fvco
<= pll
->fvco
)
181 mask
= pmask(pll
, PLL_DIV_S
);
182 index
= pindex(pll
, PLL_DIV_S
);
183 cfg
[index
].val
|= mask
;
184 cfg
[index
].msk
|= mask
;
186 mask
= pmask(pll
, PLL_SDM_EN
);
187 index
= pindex(pll
, PLL_SDM_EN
);
188 cfg
[index
].val
|= mask
;
189 cfg
[index
].msk
|= mask
;
191 nint
= do_div(fvco
, refin
* CLK_PLL_1M
);
192 mask
= pmask(pll
, PLL_NINT
);
193 index
= pindex(pll
, PLL_NINT
);
194 shift
= pshift(pll
, PLL_NINT
);
195 cfg
[index
].val
|= (nint
<< shift
) & mask
;
196 cfg
[index
].msk
|= mask
;
198 mask
= pmask(pll
, PLL_KINT
);
199 index
= pindex(pll
, PLL_KINT
);
200 width
= pwidth(pll
, PLL_KINT
);
201 shift
= pshift(pll
, PLL_KINT
);
202 tmp
= fvco
- refin
* nint
* CLK_PLL_1M
;
203 tmp
= do_div(tmp
, 10000) * ((mask
>> shift
) + 1);
204 kint
= DIV_ROUND_CLOSEST_ULL(tmp
, refin
* 100);
205 cfg
[index
].val
|= (kint
<< shift
) & mask
;
206 cfg
[index
].msk
|= mask
;
208 ibias_val
= pll_get_ibias(fvco
, pll
->itable
);
210 mask
= pmask(pll
, PLL_IBIAS
);
211 index
= pindex(pll
, PLL_IBIAS
);
212 shift
= pshift(pll
, PLL_IBIAS
);
213 cfg
[index
].val
|= ibias_val
<< shift
& mask
;
214 cfg
[index
].msk
|= mask
;
216 for (i
= 0; i
< regs_num
; i
++) {
218 sprd_pll_write(pll
, i
, cfg
[i
].msk
, cfg
[i
].val
);
219 ret
|= SPRD_PLL_WRITE_CHECK(pll
, i
, cfg
[i
].msk
,
231 static unsigned long sprd_pll_recalc_rate(struct clk_hw
*hw
,
232 unsigned long parent_rate
)
234 struct sprd_pll
*pll
= hw_to_sprd_pll(hw
);
236 return _sprd_pll_recalc_rate(pll
, parent_rate
);
239 static int sprd_pll_set_rate(struct clk_hw
*hw
,
241 unsigned long parent_rate
)
243 struct sprd_pll
*pll
= hw_to_sprd_pll(hw
);
245 return _sprd_pll_set_rate(pll
, rate
, parent_rate
);
248 static int sprd_pll_clk_prepare(struct clk_hw
*hw
)
250 struct sprd_pll
*pll
= hw_to_sprd_pll(hw
);
257 static long sprd_pll_round_rate(struct clk_hw
*hw
, unsigned long rate
,
258 unsigned long *prate
)
263 const struct clk_ops sprd_pll_ops
= {
264 .prepare
= sprd_pll_clk_prepare
,
265 .recalc_rate
= sprd_pll_recalc_rate
,
266 .round_rate
= sprd_pll_round_rate
,
267 .set_rate
= sprd_pll_set_rate
,
269 EXPORT_SYMBOL_GPL(sprd_pll_ops
);