1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License, or
7*4882a593Smuzhiyun * (at your option) any later version.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*4882a593Smuzhiyun * GNU General Public License for more details.
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "clk-regmap.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define PLLCON_OFFSET(x) (x * 4)
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define PLL_BYPASS(x) HIWORD_UPDATE(x, 15, 15)
20*4882a593Smuzhiyun #define PLL_BYPASS_MASK BIT(15)
21*4882a593Smuzhiyun #define PLL_BYPASS_SHIFT 15
22*4882a593Smuzhiyun #define PLL_POSTDIV1(x) HIWORD_UPDATE(x, 14, 12)
23*4882a593Smuzhiyun #define PLL_POSTDIV1_MASK GENMASK(14, 12)
24*4882a593Smuzhiyun #define PLL_POSTDIV1_SHIFT 12
25*4882a593Smuzhiyun #define PLL_FBDIV(x) HIWORD_UPDATE(x, 11, 0)
26*4882a593Smuzhiyun #define PLL_FBDIV_MASK GENMASK(11, 0)
27*4882a593Smuzhiyun #define PLL_FBDIV_SHIFT 0
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define PLL_POSTDIV2(x) HIWORD_UPDATE(x, 8, 6)
30*4882a593Smuzhiyun #define PLL_POSTDIV2_MASK GENMASK(8, 6)
31*4882a593Smuzhiyun #define PLL_POSTDIV2_SHIFT 6
32*4882a593Smuzhiyun #define PLL_REFDIV(x) HIWORD_UPDATE(x, 5, 0)
33*4882a593Smuzhiyun #define PLL_REFDIV_MASK GENMASK(5, 0)
34*4882a593Smuzhiyun #define PLL_REFDIV_SHIFT 0
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define PLL_FOUT_4PHASE_CLK_POWER_DOWN BIT(27)
37*4882a593Smuzhiyun #define PLL_FOUT_VCO_CLK_POWER_DOWN BIT(26)
38*4882a593Smuzhiyun #define PLL_FOUT_POST_DIV_POWER_DOWN BIT(25)
39*4882a593Smuzhiyun #define PLL_DAC_POWER_DOWN BIT(24)
40*4882a593Smuzhiyun #define PLL_FRAC(x) UPDATE(x, 23, 0)
41*4882a593Smuzhiyun #define PLL_FRAC_MASK GENMASK(23, 0)
42*4882a593Smuzhiyun #define PLL_FRAC_SHIFT 0
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define MIN_FREF_RATE 10000000UL
45*4882a593Smuzhiyun #define MAX_FREF_RATE 800000000UL
46*4882a593Smuzhiyun #define MIN_FREFDIV_RATE 1000000UL
47*4882a593Smuzhiyun #define MAX_FREFDIV_RATE 40000000UL
48*4882a593Smuzhiyun #define MIN_FVCO_RATE 400000000UL
49*4882a593Smuzhiyun #define MAX_FVCO_RATE 1600000000UL
50*4882a593Smuzhiyun #define MIN_FOUTPOSTDIV_RATE 8000000UL
51*4882a593Smuzhiyun #define MAX_FOUTPOSTDIV_RATE 1600000000UL
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct clk_regmap_pll {
54*4882a593Smuzhiyun struct clk_hw hw;
55*4882a593Smuzhiyun struct device *dev;
56*4882a593Smuzhiyun struct regmap *regmap;
57*4882a593Smuzhiyun unsigned int reg;
58*4882a593Smuzhiyun u8 pd_shift;
59*4882a593Smuzhiyun u8 dsmpd_shift;
60*4882a593Smuzhiyun u8 lock_shift;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define to_clk_regmap_pll(_hw) container_of(_hw, struct clk_regmap_pll, hw)
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static unsigned long
clk_regmap_pll_recalc_rate(struct clk_hw * hw,unsigned long prate)66*4882a593Smuzhiyun clk_regmap_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
69*4882a593Smuzhiyun unsigned int postdiv1, fbdiv, dsmpd, postdiv2, refdiv, frac, bypass;
70*4882a593Smuzhiyun unsigned int con0, con1, con2;
71*4882a593Smuzhiyun u64 foutvco, foutpostdiv;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(0), &con0);
74*4882a593Smuzhiyun regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(1), &con1);
75*4882a593Smuzhiyun regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(2), &con2);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun bypass = (con0 & PLL_BYPASS_MASK) >> PLL_BYPASS_SHIFT;
78*4882a593Smuzhiyun postdiv1 = (con0 & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
79*4882a593Smuzhiyun fbdiv = (con0 & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
80*4882a593Smuzhiyun dsmpd = (con1 & BIT(pll->dsmpd_shift)) >> pll->dsmpd_shift;
81*4882a593Smuzhiyun postdiv2 = (con1 & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
82*4882a593Smuzhiyun refdiv = (con1 & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
83*4882a593Smuzhiyun frac = (con2 & PLL_FRAC_MASK) >> PLL_FRAC_SHIFT;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (bypass)
86*4882a593Smuzhiyun return prate;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun foutvco = prate * fbdiv;
89*4882a593Smuzhiyun do_div(foutvco, refdiv);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (!dsmpd) {
92*4882a593Smuzhiyun u64 frac_rate = (u64)prate * frac;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun do_div(frac_rate, refdiv);
95*4882a593Smuzhiyun foutvco += frac_rate >> 24;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun foutpostdiv = foutvco;
99*4882a593Smuzhiyun do_div(foutpostdiv, postdiv1);
100*4882a593Smuzhiyun do_div(foutpostdiv, postdiv2);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun return foutpostdiv;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
clk_pll_round_rate(unsigned long fin,unsigned long fout,u8 * refdiv,u16 * fbdiv,u8 * postdiv1,u8 * postdiv2,u32 * frac,u8 * dsmpd,u8 * bypass)105*4882a593Smuzhiyun static long clk_pll_round_rate(unsigned long fin, unsigned long fout,
106*4882a593Smuzhiyun u8 *refdiv, u16 *fbdiv,
107*4882a593Smuzhiyun u8 *postdiv1, u8 *postdiv2,
108*4882a593Smuzhiyun u32 *frac, u8 *dsmpd, u8 *bypass)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun u8 min_refdiv, max_refdiv, postdiv;
111*4882a593Smuzhiyun u8 _dsmpd = 1, _postdiv1 = 0, _postdiv2 = 0, _refdiv = 0;
112*4882a593Smuzhiyun u16 _fbdiv = 0;
113*4882a593Smuzhiyun u32 _frac = 0;
114*4882a593Smuzhiyun u64 foutvco, foutpostdiv;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun * FREF : 10MHz ~ 800MHz
118*4882a593Smuzhiyun * FREFDIV : 1MHz ~ 40MHz
119*4882a593Smuzhiyun * FOUTVCO : 400MHz ~ 1.6GHz
120*4882a593Smuzhiyun * FOUTPOSTDIV : 8MHz ~ 1.6GHz
121*4882a593Smuzhiyun */
122*4882a593Smuzhiyun if (fin < MIN_FREF_RATE || fin > MAX_FREF_RATE)
123*4882a593Smuzhiyun return -EINVAL;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (fout < MIN_FOUTPOSTDIV_RATE || fout > MAX_FOUTPOSTDIV_RATE)
126*4882a593Smuzhiyun return -EINVAL;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (fin == fout) {
129*4882a593Smuzhiyun if (bypass)
130*4882a593Smuzhiyun *bypass = true;
131*4882a593Smuzhiyun return fin;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun min_refdiv = DIV_ROUND_UP(fin, MAX_FREFDIV_RATE);
135*4882a593Smuzhiyun max_refdiv = fin / MIN_FREFDIV_RATE;
136*4882a593Smuzhiyun if (max_refdiv > 64)
137*4882a593Smuzhiyun max_refdiv = 64;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (fout < MIN_FVCO_RATE) {
140*4882a593Smuzhiyun postdiv = DIV_ROUND_UP_ULL(MIN_FVCO_RATE, fout);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun for (_postdiv2 = 1; _postdiv2 < 8; _postdiv2++) {
143*4882a593Smuzhiyun if (postdiv % _postdiv2)
144*4882a593Smuzhiyun continue;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun _postdiv1 = postdiv / _postdiv2;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (_postdiv1 > 0 && _postdiv1 < 8)
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (_postdiv2 > 7)
153*4882a593Smuzhiyun return -EINVAL;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun fout *= _postdiv1 * _postdiv2;
156*4882a593Smuzhiyun } else {
157*4882a593Smuzhiyun _postdiv1 = 1;
158*4882a593Smuzhiyun _postdiv2 = 1;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun for (_refdiv = min_refdiv; _refdiv <= max_refdiv; _refdiv++) {
162*4882a593Smuzhiyun u64 tmp, frac_rate;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (fin % _refdiv)
165*4882a593Smuzhiyun continue;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun tmp = (u64)fout * _refdiv;
168*4882a593Smuzhiyun do_div(tmp, fin);
169*4882a593Smuzhiyun _fbdiv = tmp;
170*4882a593Smuzhiyun if (_fbdiv < 10 || _fbdiv > 1600)
171*4882a593Smuzhiyun continue;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun tmp = (u64)_fbdiv * fin;
174*4882a593Smuzhiyun do_div(tmp, _refdiv);
175*4882a593Smuzhiyun if (fout < MIN_FVCO_RATE || fout > MAX_FVCO_RATE)
176*4882a593Smuzhiyun continue;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun frac_rate = fout - tmp;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (frac_rate) {
181*4882a593Smuzhiyun tmp = (u64)frac_rate * _refdiv;
182*4882a593Smuzhiyun tmp <<= 24;
183*4882a593Smuzhiyun do_div(tmp, fin);
184*4882a593Smuzhiyun _frac = tmp;
185*4882a593Smuzhiyun _dsmpd = 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /*
192*4882a593Smuzhiyun * If DSMPD = 1 (DSM is disabled, "integer mode")
193*4882a593Smuzhiyun * FOUTVCO = FREF / REFDIV * FBDIV
194*4882a593Smuzhiyun * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
195*4882a593Smuzhiyun *
196*4882a593Smuzhiyun * If DSMPD = 0 (DSM is enabled, "fractional mode")
197*4882a593Smuzhiyun * FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
198*4882a593Smuzhiyun * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun foutvco = fin * _fbdiv;
201*4882a593Smuzhiyun do_div(foutvco, _refdiv);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (!_dsmpd) {
204*4882a593Smuzhiyun u64 frac_rate = (u64)fin * _frac;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun do_div(frac_rate, _refdiv);
207*4882a593Smuzhiyun foutvco += frac_rate >> 24;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun foutpostdiv = foutvco;
211*4882a593Smuzhiyun do_div(foutpostdiv, _postdiv1);
212*4882a593Smuzhiyun do_div(foutpostdiv, _postdiv2);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun if (refdiv)
215*4882a593Smuzhiyun *refdiv = _refdiv;
216*4882a593Smuzhiyun if (fbdiv)
217*4882a593Smuzhiyun *fbdiv = _fbdiv;
218*4882a593Smuzhiyun if (postdiv1)
219*4882a593Smuzhiyun *postdiv1 = _postdiv1;
220*4882a593Smuzhiyun if (postdiv2)
221*4882a593Smuzhiyun *postdiv2 = _postdiv2;
222*4882a593Smuzhiyun if (frac)
223*4882a593Smuzhiyun *frac = _frac;
224*4882a593Smuzhiyun if (dsmpd)
225*4882a593Smuzhiyun *dsmpd = _dsmpd;
226*4882a593Smuzhiyun if (bypass)
227*4882a593Smuzhiyun *bypass = false;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun return (unsigned long)foutpostdiv;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun static long
clk_regmap_pll_round_rate(struct clk_hw * hw,unsigned long drate,unsigned long * prate)233*4882a593Smuzhiyun clk_regmap_pll_round_rate(struct clk_hw *hw, unsigned long drate,
234*4882a593Smuzhiyun unsigned long *prate)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
237*4882a593Smuzhiyun long rate;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun rate = clk_pll_round_rate(*prate, drate, NULL, NULL, NULL, NULL, NULL,
240*4882a593Smuzhiyun NULL, NULL);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun dev_dbg(pll->dev, "%s: prate=%ld, drate=%ld, rate=%ld\n",
243*4882a593Smuzhiyun clk_hw_get_name(hw), *prate, drate, rate);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun return rate;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun static int
clk_regmap_pll_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)249*4882a593Smuzhiyun clk_regmap_pll_set_rate(struct clk_hw *hw, unsigned long drate,
250*4882a593Smuzhiyun unsigned long prate)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
253*4882a593Smuzhiyun u8 refdiv, postdiv1, postdiv2, dsmpd, bypass;
254*4882a593Smuzhiyun u16 fbdiv;
255*4882a593Smuzhiyun u32 frac;
256*4882a593Smuzhiyun long rate;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun rate = clk_pll_round_rate(prate, drate, &refdiv, &fbdiv, &postdiv1,
259*4882a593Smuzhiyun &postdiv2, &frac, &dsmpd, &bypass);
260*4882a593Smuzhiyun if (rate < 0)
261*4882a593Smuzhiyun return rate;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun dev_dbg(pll->dev, "%s: rate=%ld, bypass=%d\n",
264*4882a593Smuzhiyun clk_hw_get_name(hw), drate, bypass);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (bypass) {
267*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(0),
268*4882a593Smuzhiyun PLL_BYPASS(1));
269*4882a593Smuzhiyun } else {
270*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(0),
271*4882a593Smuzhiyun PLL_BYPASS(0) | PLL_POSTDIV1(postdiv1) |
272*4882a593Smuzhiyun PLL_FBDIV(fbdiv));
273*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
274*4882a593Smuzhiyun HIWORD_UPDATE(dsmpd, pll->dsmpd_shift, pll->dsmpd_shift) |
275*4882a593Smuzhiyun PLL_POSTDIV2(postdiv2) | PLL_REFDIV(refdiv));
276*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(2),
277*4882a593Smuzhiyun PLL_FRAC(frac));
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun dev_dbg(pll->dev, "refdiv=%d, fbdiv=%d, frac=%d\n",
280*4882a593Smuzhiyun refdiv, fbdiv, frac);
281*4882a593Smuzhiyun dev_dbg(pll->dev, "postdiv1=%d, postdiv2=%d\n",
282*4882a593Smuzhiyun postdiv1, postdiv2);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
clk_regmap_pll_prepare(struct clk_hw * hw)288*4882a593Smuzhiyun static int clk_regmap_pll_prepare(struct clk_hw *hw)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
291*4882a593Smuzhiyun u32 v;
292*4882a593Smuzhiyun int ret;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
295*4882a593Smuzhiyun HIWORD_UPDATE(0, pll->pd_shift, pll->pd_shift));
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun ret = regmap_read_poll_timeout(pll->regmap,
298*4882a593Smuzhiyun pll->reg + PLLCON_OFFSET(1),
299*4882a593Smuzhiyun v, v & BIT(pll->lock_shift), 50, 50000);
300*4882a593Smuzhiyun if (ret)
301*4882a593Smuzhiyun dev_err(pll->dev, "%s is not lock\n", clk_hw_get_name(hw));
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun return 0;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
clk_regmap_pll_unprepare(struct clk_hw * hw)306*4882a593Smuzhiyun static void clk_regmap_pll_unprepare(struct clk_hw *hw)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun regmap_write(pll->regmap, pll->reg + PLLCON_OFFSET(1),
311*4882a593Smuzhiyun HIWORD_UPDATE(1, pll->pd_shift, pll->pd_shift));
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
clk_regmap_pll_is_prepared(struct clk_hw * hw)314*4882a593Smuzhiyun static int clk_regmap_pll_is_prepared(struct clk_hw *hw)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun struct clk_regmap_pll *pll = to_clk_regmap_pll(hw);
317*4882a593Smuzhiyun unsigned int con1;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun regmap_read(pll->regmap, pll->reg + PLLCON_OFFSET(1), &con1);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return !(con1 & BIT(pll->pd_shift));
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun static const struct clk_ops clk_regmap_pll_ops = {
325*4882a593Smuzhiyun .recalc_rate = clk_regmap_pll_recalc_rate,
326*4882a593Smuzhiyun .round_rate = clk_regmap_pll_round_rate,
327*4882a593Smuzhiyun .set_rate = clk_regmap_pll_set_rate,
328*4882a593Smuzhiyun .prepare = clk_regmap_pll_prepare,
329*4882a593Smuzhiyun .unprepare = clk_regmap_pll_unprepare,
330*4882a593Smuzhiyun .is_prepared = clk_regmap_pll_is_prepared,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun struct clk *
devm_clk_regmap_register_pll(struct device * dev,const char * name,const char * parent_name,struct regmap * regmap,u32 reg,u8 pd_shift,u8 dsmpd_shift,u8 lock_shift,unsigned long flags)334*4882a593Smuzhiyun devm_clk_regmap_register_pll(struct device *dev, const char *name,
335*4882a593Smuzhiyun const char *parent_name,
336*4882a593Smuzhiyun struct regmap *regmap, u32 reg, u8 pd_shift,
337*4882a593Smuzhiyun u8 dsmpd_shift, u8 lock_shift,
338*4882a593Smuzhiyun unsigned long flags)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct clk_regmap_pll *pll;
341*4882a593Smuzhiyun struct clk_init_data init = {};
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
344*4882a593Smuzhiyun if (!pll)
345*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun init.name = name;
348*4882a593Smuzhiyun init.ops = &clk_regmap_pll_ops;
349*4882a593Smuzhiyun init.flags = flags;
350*4882a593Smuzhiyun init.parent_names = (parent_name ? &parent_name : NULL);
351*4882a593Smuzhiyun init.num_parents = (parent_name ? 1 : 0);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun pll->dev = dev;
354*4882a593Smuzhiyun pll->regmap = regmap;
355*4882a593Smuzhiyun pll->reg = reg;
356*4882a593Smuzhiyun pll->pd_shift = pd_shift;
357*4882a593Smuzhiyun pll->dsmpd_shift = dsmpd_shift;
358*4882a593Smuzhiyun pll->lock_shift = lock_shift;
359*4882a593Smuzhiyun pll->hw.init = &init;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun return devm_clk_register(dev, &pll->hw);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_clk_regmap_register_pll);
364