clk-peripheral.c (42324d953b38e74cf5cb05a02c81d4922a2ddcd5) clk-peripheral.c (b4c115c76184f2c56a295579161652fd5eb2dcc1)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 */
5
6#include <linux/bitops.h>
7#include <linux/clk-provider.h>
8#include <linux/clkdev.h>

--- 24 unchanged lines hidden (view full) ---

33 struct clk_hw hw;
34 struct regmap *regmap;
35 struct clk_range range;
36 spinlock_t *lock;
37 u32 id;
38 u32 div;
39 const struct clk_pcr_layout *layout;
40 bool auto_div;
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 */
5
6#include <linux/bitops.h>
7#include <linux/clk-provider.h>
8#include <linux/clkdev.h>

--- 24 unchanged lines hidden (view full) ---

33 struct clk_hw hw;
34 struct regmap *regmap;
35 struct clk_range range;
36 spinlock_t *lock;
37 u32 id;
38 u32 div;
39 const struct clk_pcr_layout *layout;
40 bool auto_div;
41 int chg_pid;
41};
42
43#define to_clk_sam9x5_peripheral(hw) \
44 container_of(hw, struct clk_sam9x5_peripheral, hw)
45
46static int clk_peripheral_enable(struct clk_hw *hw)
47{
48 struct clk_peripheral *periph = to_clk_peripheral(hw);

--- 184 unchanged lines hidden (view full) ---

233 periph->auto_div = false;
234 } else {
235 clk_sam9x5_peripheral_autodiv(periph);
236 }
237
238 return parent_rate >> periph->div;
239}
240
42};
43
44#define to_clk_sam9x5_peripheral(hw) \
45 container_of(hw, struct clk_sam9x5_peripheral, hw)
46
47static int clk_peripheral_enable(struct clk_hw *hw)
48{
49 struct clk_peripheral *periph = to_clk_peripheral(hw);

--- 184 unchanged lines hidden (view full) ---

234 periph->auto_div = false;
235 } else {
236 clk_sam9x5_peripheral_autodiv(periph);
237 }
238
239 return parent_rate >> periph->div;
240}
241
242static void clk_sam9x5_peripheral_best_diff(struct clk_rate_request *req,
243 struct clk_hw *parent,
244 unsigned long parent_rate,
245 u32 shift, long *best_diff,
246 long *best_rate)
247{
248 unsigned long tmp_rate = parent_rate >> shift;
249 unsigned long tmp_diff = abs(req->rate - tmp_rate);
250
251 if (*best_diff < 0 || *best_diff >= tmp_diff) {
252 *best_rate = tmp_rate;
253 *best_diff = tmp_diff;
254 req->best_parent_rate = parent_rate;
255 req->best_parent_hw = parent;
256 }
257}
258
259static int clk_sam9x5_peripheral_determine_rate(struct clk_hw *hw,
260 struct clk_rate_request *req)
261{
262 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
263 struct clk_hw *parent = clk_hw_get_parent(hw);
264 struct clk_rate_request req_parent = *req;
265 unsigned long parent_rate = clk_hw_get_rate(parent);
266 unsigned long tmp_rate;
267 long best_rate = LONG_MIN;
268 long best_diff = LONG_MIN;
269 u32 shift;
270
271 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
272 return parent_rate;
273
274 /* Fist step: check the available dividers. */
275 for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
276 tmp_rate = parent_rate >> shift;
277
278 if (periph->range.max && tmp_rate > periph->range.max)
279 continue;
280
281 clk_sam9x5_peripheral_best_diff(req, parent, parent_rate,
282 shift, &best_diff, &best_rate);
283
284 if (!best_diff || best_rate <= req->rate)
285 break;
286 }
287
288 if (periph->chg_pid < 0)
289 goto end;
290
291 /* Step two: try to request rate from parent. */
292 parent = clk_hw_get_parent_by_index(hw, periph->chg_pid);
293 if (!parent)
294 goto end;
295
296 for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
297 req_parent.rate = req->rate << shift;
298
299 if (__clk_determine_rate(parent, &req_parent))
300 continue;
301
302 clk_sam9x5_peripheral_best_diff(req, parent, req_parent.rate,
303 shift, &best_diff, &best_rate);
304
305 if (!best_diff)
306 break;
307 }
308end:
309 if (best_rate < 0 ||
310 (periph->range.max && best_rate > periph->range.max))
311 return -EINVAL;
312
313 pr_debug("PCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
314 __func__, best_rate,
315 __clk_get_name((req->best_parent_hw)->clk),
316 req->best_parent_rate);
317
318 req->rate = best_rate;
319
320 return 0;
321}
322
241static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
242 unsigned long rate,
243 unsigned long *parent_rate)
244{
245 int shift = 0;
246 unsigned long best_rate;
247 unsigned long best_diff;
248 unsigned long cur_rate = *parent_rate;

--- 66 unchanged lines hidden (view full) ---

315 .enable = clk_sam9x5_peripheral_enable,
316 .disable = clk_sam9x5_peripheral_disable,
317 .is_enabled = clk_sam9x5_peripheral_is_enabled,
318 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
319 .round_rate = clk_sam9x5_peripheral_round_rate,
320 .set_rate = clk_sam9x5_peripheral_set_rate,
321};
322
323static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
324 unsigned long rate,
325 unsigned long *parent_rate)
326{
327 int shift = 0;
328 unsigned long best_rate;
329 unsigned long best_diff;
330 unsigned long cur_rate = *parent_rate;

--- 66 unchanged lines hidden (view full) ---

397 .enable = clk_sam9x5_peripheral_enable,
398 .disable = clk_sam9x5_peripheral_disable,
399 .is_enabled = clk_sam9x5_peripheral_is_enabled,
400 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
401 .round_rate = clk_sam9x5_peripheral_round_rate,
402 .set_rate = clk_sam9x5_peripheral_set_rate,
403};
404
405static const struct clk_ops sam9x5_peripheral_chg_ops = {
406 .enable = clk_sam9x5_peripheral_enable,
407 .disable = clk_sam9x5_peripheral_disable,
408 .is_enabled = clk_sam9x5_peripheral_is_enabled,
409 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
410 .determine_rate = clk_sam9x5_peripheral_determine_rate,
411 .set_rate = clk_sam9x5_peripheral_set_rate,
412};
413
323struct clk_hw * __init
324at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
325 const struct clk_pcr_layout *layout,
326 const char *name, const char *parent_name,
414struct clk_hw * __init
415at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
416 const struct clk_pcr_layout *layout,
417 const char *name, const char *parent_name,
327 u32 id, const struct clk_range *range)
418 u32 id, const struct clk_range *range,
419 int chg_pid)
328{
329 struct clk_sam9x5_peripheral *periph;
330 struct clk_init_data init;
331 struct clk_hw *hw;
332 int ret;
333
334 if (!name || !parent_name)
335 return ERR_PTR(-EINVAL);
336
337 periph = kzalloc(sizeof(*periph), GFP_KERNEL);
338 if (!periph)
339 return ERR_PTR(-ENOMEM);
340
341 init.name = name;
420{
421 struct clk_sam9x5_peripheral *periph;
422 struct clk_init_data init;
423 struct clk_hw *hw;
424 int ret;
425
426 if (!name || !parent_name)
427 return ERR_PTR(-EINVAL);
428
429 periph = kzalloc(sizeof(*periph), GFP_KERNEL);
430 if (!periph)
431 return ERR_PTR(-ENOMEM);
432
433 init.name = name;
342 init.ops = &sam9x5_peripheral_ops;
343 init.parent_names = (parent_name ? &parent_name : NULL);
344 init.num_parents = (parent_name ? 1 : 0);
345 init.flags = 0;
434 init.parent_names = &parent_name;
435 init.num_parents = 1;
436 if (chg_pid < 0) {
437 init.flags = 0;
438 init.ops = &sam9x5_peripheral_ops;
439 } else {
440 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
441 CLK_SET_RATE_PARENT;
442 init.ops = &sam9x5_peripheral_chg_ops;
443 }
346
347 periph->id = id;
348 periph->hw.init = &init;
349 periph->div = 0;
350 periph->regmap = regmap;
351 periph->lock = lock;
352 if (layout->div_mask)
353 periph->auto_div = true;
354 periph->layout = layout;
355 periph->range = *range;
444
445 periph->id = id;
446 periph->hw.init = &init;
447 periph->div = 0;
448 periph->regmap = regmap;
449 periph->lock = lock;
450 if (layout->div_mask)
451 periph->auto_div = true;
452 periph->layout = layout;
453 periph->range = *range;
454 periph->chg_pid = chg_pid;
356
357 hw = &periph->hw;
358 ret = clk_hw_register(NULL, &periph->hw);
359 if (ret) {
360 kfree(periph);
361 hw = ERR_PTR(ret);
362 } else {
363 clk_sam9x5_peripheral_autodiv(periph);
364 pmc_register_id(id);
365 }
366
367 return hw;
368}
455
456 hw = &periph->hw;
457 ret = clk_hw_register(NULL, &periph->hw);
458 if (ret) {
459 kfree(periph);
460 hw = ERR_PTR(ret);
461 } else {
462 clk_sam9x5_peripheral_autodiv(periph);
463 pmc_register_id(id);
464 }
465
466 return hw;
467}