1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Base on code in drivers/clk/clk-composite.c.
5*4882a593Smuzhiyun * See clk-composite.c for further copyright information.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
8*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
9*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License, or
10*4882a593Smuzhiyun * (at your option) any later version.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
13*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*4882a593Smuzhiyun * GNU General Public License for more details.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "clk-regmap.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct clk_regmap_composite {
21*4882a593Smuzhiyun struct device *dev;
22*4882a593Smuzhiyun struct clk_hw hw;
23*4882a593Smuzhiyun struct clk_ops ops;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct clk_hw *mux_hw;
26*4882a593Smuzhiyun struct clk_hw *rate_hw;
27*4882a593Smuzhiyun struct clk_hw *gate_hw;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun const struct clk_ops *mux_ops;
30*4882a593Smuzhiyun const struct clk_ops *rate_ops;
31*4882a593Smuzhiyun const struct clk_ops *gate_ops;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define to_clk_regmap_composite(_hw) \
35*4882a593Smuzhiyun container_of(_hw, struct clk_regmap_composite, hw)
36*4882a593Smuzhiyun
clk_regmap_composite_get_parent(struct clk_hw * hw)37*4882a593Smuzhiyun static u8 clk_regmap_composite_get_parent(struct clk_hw *hw)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
40*4882a593Smuzhiyun const struct clk_ops *mux_ops = composite->mux_ops;
41*4882a593Smuzhiyun struct clk_hw *mux_hw = composite->mux_hw;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun __clk_hw_set_clk(mux_hw, hw);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun return mux_ops->get_parent(mux_hw);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
clk_regmap_composite_set_parent(struct clk_hw * hw,u8 index)48*4882a593Smuzhiyun static int clk_regmap_composite_set_parent(struct clk_hw *hw, u8 index)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
51*4882a593Smuzhiyun const struct clk_ops *mux_ops = composite->mux_ops;
52*4882a593Smuzhiyun struct clk_hw *mux_hw = composite->mux_hw;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun __clk_hw_set_clk(mux_hw, hw);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return mux_ops->set_parent(mux_hw, index);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
clk_regmap_composite_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)59*4882a593Smuzhiyun static unsigned long clk_regmap_composite_recalc_rate(struct clk_hw *hw,
60*4882a593Smuzhiyun unsigned long parent_rate)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
63*4882a593Smuzhiyun const struct clk_ops *rate_ops = composite->rate_ops;
64*4882a593Smuzhiyun struct clk_hw *rate_hw = composite->rate_hw;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun __clk_hw_set_clk(rate_hw, hw);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun return rate_ops->recalc_rate(rate_hw, parent_rate);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
clk_regmap_composite_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)71*4882a593Smuzhiyun static int clk_regmap_composite_determine_rate(struct clk_hw *hw,
72*4882a593Smuzhiyun struct clk_rate_request *req)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
75*4882a593Smuzhiyun const struct clk_ops *rate_ops = composite->rate_ops;
76*4882a593Smuzhiyun const struct clk_ops *mux_ops = composite->mux_ops;
77*4882a593Smuzhiyun struct clk_hw *rate_hw = composite->rate_hw;
78*4882a593Smuzhiyun struct clk_hw *mux_hw = composite->mux_hw;
79*4882a593Smuzhiyun struct clk_hw *parent;
80*4882a593Smuzhiyun unsigned long parent_rate;
81*4882a593Smuzhiyun long tmp_rate, best_rate = 0;
82*4882a593Smuzhiyun unsigned long rate_diff;
83*4882a593Smuzhiyun unsigned long best_rate_diff = ULONG_MAX;
84*4882a593Smuzhiyun long rate;
85*4882a593Smuzhiyun unsigned int i;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (rate_hw && rate_ops && rate_ops->determine_rate) {
88*4882a593Smuzhiyun __clk_hw_set_clk(rate_hw, hw);
89*4882a593Smuzhiyun return rate_ops->determine_rate(rate_hw, req);
90*4882a593Smuzhiyun } else if (rate_hw && rate_ops && rate_ops->round_rate &&
91*4882a593Smuzhiyun mux_hw && mux_ops && mux_ops->set_parent) {
92*4882a593Smuzhiyun req->best_parent_hw = NULL;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
95*4882a593Smuzhiyun parent = clk_hw_get_parent(mux_hw);
96*4882a593Smuzhiyun req->best_parent_hw = parent;
97*4882a593Smuzhiyun req->best_parent_rate = clk_hw_get_rate(parent);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun rate = rate_ops->round_rate(rate_hw, req->rate,
100*4882a593Smuzhiyun &req->best_parent_rate);
101*4882a593Smuzhiyun if (rate < 0)
102*4882a593Smuzhiyun return rate;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun req->rate = rate;
105*4882a593Smuzhiyun return 0;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
109*4882a593Smuzhiyun parent = clk_hw_get_parent_by_index(mux_hw, i);
110*4882a593Smuzhiyun if (!parent)
111*4882a593Smuzhiyun continue;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun parent_rate = clk_hw_get_rate(parent);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
116*4882a593Smuzhiyun &parent_rate);
117*4882a593Smuzhiyun if (tmp_rate < 0)
118*4882a593Smuzhiyun continue;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun rate_diff = abs(req->rate - tmp_rate);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (!rate_diff || !req->best_parent_hw ||
123*4882a593Smuzhiyun best_rate_diff > rate_diff) {
124*4882a593Smuzhiyun req->best_parent_hw = parent;
125*4882a593Smuzhiyun req->best_parent_rate = parent_rate;
126*4882a593Smuzhiyun best_rate_diff = rate_diff;
127*4882a593Smuzhiyun best_rate = tmp_rate;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (!rate_diff)
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun req->rate = best_rate;
135*4882a593Smuzhiyun return 0;
136*4882a593Smuzhiyun } else if (mux_hw && mux_ops && mux_ops->determine_rate) {
137*4882a593Smuzhiyun __clk_hw_set_clk(mux_hw, hw);
138*4882a593Smuzhiyun return mux_ops->determine_rate(mux_hw, req);
139*4882a593Smuzhiyun } else {
140*4882a593Smuzhiyun return -EINVAL;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
clk_regmap_composite_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)146*4882a593Smuzhiyun static long clk_regmap_composite_round_rate(struct clk_hw *hw,
147*4882a593Smuzhiyun unsigned long rate,
148*4882a593Smuzhiyun unsigned long *prate)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
151*4882a593Smuzhiyun const struct clk_ops *rate_ops = composite->rate_ops;
152*4882a593Smuzhiyun struct clk_hw *rate_hw = composite->rate_hw;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun __clk_hw_set_clk(rate_hw, hw);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return rate_ops->round_rate(rate_hw, rate, prate);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
clk_regmap_composite_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)159*4882a593Smuzhiyun static int clk_regmap_composite_set_rate(struct clk_hw *hw,
160*4882a593Smuzhiyun unsigned long rate,
161*4882a593Smuzhiyun unsigned long parent_rate)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
164*4882a593Smuzhiyun const struct clk_ops *rate_ops = composite->rate_ops;
165*4882a593Smuzhiyun struct clk_hw *rate_hw = composite->rate_hw;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun __clk_hw_set_clk(rate_hw, hw);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun return rate_ops->set_rate(rate_hw, rate, parent_rate);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
clk_regmap_composite_is_prepared(struct clk_hw * hw)172*4882a593Smuzhiyun static int clk_regmap_composite_is_prepared(struct clk_hw *hw)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
175*4882a593Smuzhiyun const struct clk_ops *gate_ops = composite->gate_ops;
176*4882a593Smuzhiyun struct clk_hw *gate_hw = composite->gate_hw;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun __clk_hw_set_clk(gate_hw, hw);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return gate_ops->is_prepared(gate_hw);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
clk_regmap_composite_prepare(struct clk_hw * hw)183*4882a593Smuzhiyun static int clk_regmap_composite_prepare(struct clk_hw *hw)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
186*4882a593Smuzhiyun const struct clk_ops *gate_ops = composite->gate_ops;
187*4882a593Smuzhiyun struct clk_hw *gate_hw = composite->gate_hw;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun __clk_hw_set_clk(gate_hw, hw);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun return gate_ops->prepare(gate_hw);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
clk_regmap_composite_unprepare(struct clk_hw * hw)194*4882a593Smuzhiyun static void clk_regmap_composite_unprepare(struct clk_hw *hw)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun struct clk_regmap_composite *composite = to_clk_regmap_composite(hw);
197*4882a593Smuzhiyun const struct clk_ops *gate_ops = composite->gate_ops;
198*4882a593Smuzhiyun struct clk_hw *gate_hw = composite->gate_hw;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun __clk_hw_set_clk(gate_hw, hw);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun gate_ops->unprepare(gate_hw);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun struct clk *
devm_clk_regmap_register_composite(struct device * dev,const char * name,const char * const * parent_names,u8 num_parents,struct regmap * regmap,u32 mux_reg,u8 mux_shift,u8 mux_width,u32 div_reg,u8 div_shift,u8 div_width,u8 div_flags,u32 gate_reg,u8 gate_shift,unsigned long flags)206*4882a593Smuzhiyun devm_clk_regmap_register_composite(struct device *dev, const char *name,
207*4882a593Smuzhiyun const char *const *parent_names,
208*4882a593Smuzhiyun u8 num_parents, struct regmap *regmap,
209*4882a593Smuzhiyun u32 mux_reg, u8 mux_shift, u8 mux_width,
210*4882a593Smuzhiyun u32 div_reg, u8 div_shift, u8 div_width,
211*4882a593Smuzhiyun u8 div_flags,
212*4882a593Smuzhiyun u32 gate_reg, u8 gate_shift,
213*4882a593Smuzhiyun unsigned long flags)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun struct clk_regmap_gate *gate = NULL;
216*4882a593Smuzhiyun struct clk_regmap_mux *mux = NULL;
217*4882a593Smuzhiyun struct clk_regmap_divider *div = NULL;
218*4882a593Smuzhiyun struct clk_regmap_fractional_divider *fd = NULL;
219*4882a593Smuzhiyun const struct clk_ops *mux_ops = NULL, *div_ops = NULL, *gate_ops = NULL;
220*4882a593Smuzhiyun const struct clk_ops *fd_ops = NULL;
221*4882a593Smuzhiyun struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL;
222*4882a593Smuzhiyun struct clk_hw *fd_hw = NULL;
223*4882a593Smuzhiyun struct clk *clk;
224*4882a593Smuzhiyun struct clk_init_data init = {};
225*4882a593Smuzhiyun struct clk_regmap_composite *composite;
226*4882a593Smuzhiyun struct clk_ops *clk_composite_ops;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (num_parents > 1) {
229*4882a593Smuzhiyun mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
230*4882a593Smuzhiyun if (!mux)
231*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun mux->dev = dev;
234*4882a593Smuzhiyun mux->regmap = regmap;
235*4882a593Smuzhiyun mux->reg = mux_reg;
236*4882a593Smuzhiyun mux->shift = mux_shift;
237*4882a593Smuzhiyun mux->mask = BIT(mux_width) - 1;
238*4882a593Smuzhiyun mux_ops = &clk_regmap_mux_ops;
239*4882a593Smuzhiyun mux_hw = &mux->hw;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (gate_reg > 0) {
243*4882a593Smuzhiyun gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
244*4882a593Smuzhiyun if (!gate)
245*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun gate->dev = dev;
248*4882a593Smuzhiyun gate->regmap = regmap;
249*4882a593Smuzhiyun gate->reg = gate_reg;
250*4882a593Smuzhiyun gate->shift = gate_shift;
251*4882a593Smuzhiyun gate_ops = &clk_regmap_gate_ops;
252*4882a593Smuzhiyun gate_hw = &gate->hw;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (div_reg > 0) {
256*4882a593Smuzhiyun if (div_flags & CLK_DIVIDER_HIWORD_MASK) {
257*4882a593Smuzhiyun div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
258*4882a593Smuzhiyun if (!div)
259*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun div->dev = dev;
262*4882a593Smuzhiyun div->regmap = regmap;
263*4882a593Smuzhiyun div->reg = div_reg;
264*4882a593Smuzhiyun div->shift = div_shift;
265*4882a593Smuzhiyun div->width = div_width;
266*4882a593Smuzhiyun div_ops = &clk_regmap_divider_ops;
267*4882a593Smuzhiyun div_hw = &div->hw;
268*4882a593Smuzhiyun } else {
269*4882a593Smuzhiyun fd = devm_kzalloc(dev, sizeof(*fd), GFP_KERNEL);
270*4882a593Smuzhiyun if (!fd)
271*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun fd->dev = dev;
274*4882a593Smuzhiyun fd->regmap = regmap;
275*4882a593Smuzhiyun fd->reg = div_reg;
276*4882a593Smuzhiyun fd->mshift = 16;
277*4882a593Smuzhiyun fd->mwidth = 16;
278*4882a593Smuzhiyun fd->mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift;
279*4882a593Smuzhiyun fd->nshift = 0;
280*4882a593Smuzhiyun fd->nwidth = 16;
281*4882a593Smuzhiyun fd->nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift;
282*4882a593Smuzhiyun fd_ops = &clk_regmap_fractional_divider_ops;
283*4882a593Smuzhiyun fd_hw = &fd->hw;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun composite = devm_kzalloc(dev, sizeof(*composite), GFP_KERNEL);
288*4882a593Smuzhiyun if (!composite)
289*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun init.name = name;
292*4882a593Smuzhiyun init.flags = flags;
293*4882a593Smuzhiyun init.parent_names = parent_names;
294*4882a593Smuzhiyun init.num_parents = num_parents;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun clk_composite_ops = &composite->ops;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (mux_hw && mux_ops) {
299*4882a593Smuzhiyun if (!mux_ops->get_parent)
300*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun composite->mux_hw = mux_hw;
303*4882a593Smuzhiyun composite->mux_ops = mux_ops;
304*4882a593Smuzhiyun clk_composite_ops->get_parent =
305*4882a593Smuzhiyun clk_regmap_composite_get_parent;
306*4882a593Smuzhiyun if (mux_ops->set_parent)
307*4882a593Smuzhiyun clk_composite_ops->set_parent =
308*4882a593Smuzhiyun clk_regmap_composite_set_parent;
309*4882a593Smuzhiyun if (mux_ops->determine_rate)
310*4882a593Smuzhiyun clk_composite_ops->determine_rate =
311*4882a593Smuzhiyun clk_regmap_composite_determine_rate;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (div_hw && div_ops) {
315*4882a593Smuzhiyun if (!div_ops->recalc_rate)
316*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun clk_composite_ops->recalc_rate =
319*4882a593Smuzhiyun clk_regmap_composite_recalc_rate;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (div_ops->determine_rate)
322*4882a593Smuzhiyun clk_composite_ops->determine_rate =
323*4882a593Smuzhiyun clk_regmap_composite_determine_rate;
324*4882a593Smuzhiyun else if (div_ops->round_rate)
325*4882a593Smuzhiyun clk_composite_ops->round_rate =
326*4882a593Smuzhiyun clk_regmap_composite_round_rate;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun /* .set_rate requires either .round_rate or .determine_rate */
329*4882a593Smuzhiyun if (div_ops->set_rate) {
330*4882a593Smuzhiyun if (div_ops->determine_rate || div_ops->round_rate)
331*4882a593Smuzhiyun clk_composite_ops->set_rate =
332*4882a593Smuzhiyun clk_regmap_composite_set_rate;
333*4882a593Smuzhiyun else
334*4882a593Smuzhiyun WARN(1, "missing round_rate op\n");
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun composite->rate_hw = div_hw;
338*4882a593Smuzhiyun composite->rate_ops = div_ops;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (fd_hw && fd_ops) {
342*4882a593Smuzhiyun if (!fd_ops->recalc_rate)
343*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun clk_composite_ops->recalc_rate =
346*4882a593Smuzhiyun clk_regmap_composite_recalc_rate;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (fd_ops->determine_rate)
349*4882a593Smuzhiyun clk_composite_ops->determine_rate =
350*4882a593Smuzhiyun clk_regmap_composite_determine_rate;
351*4882a593Smuzhiyun else if (fd_ops->round_rate)
352*4882a593Smuzhiyun clk_composite_ops->round_rate =
353*4882a593Smuzhiyun clk_regmap_composite_round_rate;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* .set_rate requires either .round_rate or .determine_rate */
356*4882a593Smuzhiyun if (fd_ops->set_rate) {
357*4882a593Smuzhiyun if (fd_ops->determine_rate || fd_ops->round_rate)
358*4882a593Smuzhiyun clk_composite_ops->set_rate =
359*4882a593Smuzhiyun clk_regmap_composite_set_rate;
360*4882a593Smuzhiyun else
361*4882a593Smuzhiyun WARN(1, "missing round_rate op\n");
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun composite->rate_hw = fd_hw;
365*4882a593Smuzhiyun composite->rate_ops = fd_ops;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (gate_hw && gate_ops) {
369*4882a593Smuzhiyun if (!gate_ops->is_prepared || !gate_ops->prepare ||
370*4882a593Smuzhiyun !gate_ops->unprepare)
371*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun composite->gate_hw = gate_hw;
374*4882a593Smuzhiyun composite->gate_ops = gate_ops;
375*4882a593Smuzhiyun clk_composite_ops->is_prepared =
376*4882a593Smuzhiyun clk_regmap_composite_is_prepared;
377*4882a593Smuzhiyun clk_composite_ops->prepare = clk_regmap_composite_prepare;
378*4882a593Smuzhiyun clk_composite_ops->unprepare = clk_regmap_composite_unprepare;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun init.ops = clk_composite_ops;
382*4882a593Smuzhiyun composite->dev = dev;
383*4882a593Smuzhiyun composite->hw.init = &init;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun clk = devm_clk_register(dev, &composite->hw);
386*4882a593Smuzhiyun if (IS_ERR(clk))
387*4882a593Smuzhiyun return clk;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (composite->mux_hw)
390*4882a593Smuzhiyun composite->mux_hw->clk = clk;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if (composite->rate_hw)
393*4882a593Smuzhiyun composite->rate_hw->clk = clk;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (composite->gate_hw)
396*4882a593Smuzhiyun composite->gate_hw->clk = clk;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return clk;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_clk_regmap_register_composite);
401