aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-composite.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-composite.c')
-rw-r--r--drivers/clk/clk-composite.c93
1 files changed, 81 insertions, 12 deletions
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 1f903e1f86a2..00269de2f390 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -151,6 +151,33 @@ static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
151 return rate_ops->set_rate(rate_hw, rate, parent_rate); 151 return rate_ops->set_rate(rate_hw, rate, parent_rate);
152} 152}
153 153
154static int clk_composite_set_rate_and_parent(struct clk_hw *hw,
155 unsigned long rate,
156 unsigned long parent_rate,
157 u8 index)
158{
159 struct clk_composite *composite = to_clk_composite(hw);
160 const struct clk_ops *rate_ops = composite->rate_ops;
161 const struct clk_ops *mux_ops = composite->mux_ops;
162 struct clk_hw *rate_hw = composite->rate_hw;
163 struct clk_hw *mux_hw = composite->mux_hw;
164 unsigned long temp_rate;
165
166 __clk_hw_set_clk(rate_hw, hw);
167 __clk_hw_set_clk(mux_hw, hw);
168
169 temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate);
170 if (temp_rate > rate) {
171 rate_ops->set_rate(rate_hw, rate, parent_rate);
172 mux_ops->set_parent(mux_hw, index);
173 } else {
174 mux_ops->set_parent(mux_hw, index);
175 rate_ops->set_rate(rate_hw, rate, parent_rate);
176 }
177
178 return 0;
179}
180
154static int clk_composite_is_enabled(struct clk_hw *hw) 181static int clk_composite_is_enabled(struct clk_hw *hw)
155{ 182{
156 struct clk_composite *composite = to_clk_composite(hw); 183 struct clk_composite *composite = to_clk_composite(hw);
@@ -184,17 +211,18 @@ static void clk_composite_disable(struct clk_hw *hw)
184 gate_ops->disable(gate_hw); 211 gate_ops->disable(gate_hw);
185} 212}
186 213
187struct clk *clk_register_composite(struct device *dev, const char *name, 214struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
188 const char * const *parent_names, int num_parents, 215 const char * const *parent_names, int num_parents,
189 struct clk_hw *mux_hw, const struct clk_ops *mux_ops, 216 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
190 struct clk_hw *rate_hw, const struct clk_ops *rate_ops, 217 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
191 struct clk_hw *gate_hw, const struct clk_ops *gate_ops, 218 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
192 unsigned long flags) 219 unsigned long flags)
193{ 220{
194 struct clk *clk; 221 struct clk_hw *hw;
195 struct clk_init_data init; 222 struct clk_init_data init;
196 struct clk_composite *composite; 223 struct clk_composite *composite;
197 struct clk_ops *clk_composite_ops; 224 struct clk_ops *clk_composite_ops;
225 int ret;
198 226
199 composite = kzalloc(sizeof(*composite), GFP_KERNEL); 227 composite = kzalloc(sizeof(*composite), GFP_KERNEL);
200 if (!composite) 228 if (!composite)
@@ -204,12 +232,13 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
204 init.flags = flags | CLK_IS_BASIC; 232 init.flags = flags | CLK_IS_BASIC;
205 init.parent_names = parent_names; 233 init.parent_names = parent_names;
206 init.num_parents = num_parents; 234 init.num_parents = num_parents;
235 hw = &composite->hw;
207 236
208 clk_composite_ops = &composite->ops; 237 clk_composite_ops = &composite->ops;
209 238
210 if (mux_hw && mux_ops) { 239 if (mux_hw && mux_ops) {
211 if (!mux_ops->get_parent) { 240 if (!mux_ops->get_parent) {
212 clk = ERR_PTR(-EINVAL); 241 hw = ERR_PTR(-EINVAL);
213 goto err; 242 goto err;
214 } 243 }
215 244
@@ -224,7 +253,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
224 253
225 if (rate_hw && rate_ops) { 254 if (rate_hw && rate_ops) {
226 if (!rate_ops->recalc_rate) { 255 if (!rate_ops->recalc_rate) {
227 clk = ERR_PTR(-EINVAL); 256 hw = ERR_PTR(-EINVAL);
228 goto err; 257 goto err;
229 } 258 }
230 clk_composite_ops->recalc_rate = clk_composite_recalc_rate; 259 clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
@@ -250,10 +279,16 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
250 composite->rate_ops = rate_ops; 279 composite->rate_ops = rate_ops;
251 } 280 }
252 281
282 if (mux_hw && mux_ops && rate_hw && rate_ops) {
283 if (mux_ops->set_parent && rate_ops->set_rate)
284 clk_composite_ops->set_rate_and_parent =
285 clk_composite_set_rate_and_parent;
286 }
287
253 if (gate_hw && gate_ops) { 288 if (gate_hw && gate_ops) {
254 if (!gate_ops->is_enabled || !gate_ops->enable || 289 if (!gate_ops->is_enabled || !gate_ops->enable ||
255 !gate_ops->disable) { 290 !gate_ops->disable) {
256 clk = ERR_PTR(-EINVAL); 291 hw = ERR_PTR(-EINVAL);
257 goto err; 292 goto err;
258 } 293 }
259 294
@@ -267,22 +302,56 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
267 init.ops = clk_composite_ops; 302 init.ops = clk_composite_ops;
268 composite->hw.init = &init; 303 composite->hw.init = &init;
269 304
270 clk = clk_register(dev, &composite->hw); 305 ret = clk_hw_register(dev, hw);
271 if (IS_ERR(clk)) 306 if (ret) {
307 hw = ERR_PTR(ret);
272 goto err; 308 goto err;
309 }
273 310
274 if (composite->mux_hw) 311 if (composite->mux_hw)
275 composite->mux_hw->clk = clk; 312 composite->mux_hw->clk = hw->clk;
276 313
277 if (composite->rate_hw) 314 if (composite->rate_hw)
278 composite->rate_hw->clk = clk; 315 composite->rate_hw->clk = hw->clk;
279 316
280 if (composite->gate_hw) 317 if (composite->gate_hw)
281 composite->gate_hw->clk = clk; 318 composite->gate_hw->clk = hw->clk;
282 319
283 return clk; 320 return hw;
284 321
285err: 322err:
286 kfree(composite); 323 kfree(composite);
287 return clk; 324 return hw;
325}
326
327struct clk *clk_register_composite(struct device *dev, const char *name,
328 const char * const *parent_names, int num_parents,
329 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
330 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
331 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
332 unsigned long flags)
333{
334 struct clk_hw *hw;
335
336 hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
337 mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops,
338 flags);
339 if (IS_ERR(hw))
340 return ERR_CAST(hw);
341 return hw->clk;
342}
343
344void clk_unregister_composite(struct clk *clk)
345{
346 struct clk_composite *composite;
347 struct clk_hw *hw;
348
349 hw = __clk_get_hw(clk);
350 if (!hw)
351 return;
352
353 composite = to_clk_composite(hw);
354
355 clk_unregister(clk);
356 kfree(composite);
288} 357}