2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
11 #include <linux/clk-provider.h>
12 #include <linux/spinlock.h>
14 #include "ccu_phase.h"
16 static int ccu_phase_get_phase(struct clk_hw *hw)
18 struct ccu_phase *phase = hw_to_ccu_phase(hw);
19 struct clk_hw *parent, *grandparent;
20 unsigned int parent_rate, grandparent_rate;
25 reg = readl(phase->common.base + phase->common.reg);
26 delay = (reg >> phase->shift);
27 delay &= (1 << phase->width) - 1;
32 /* Get our parent clock, it's the one that can adjust its rate */
33 parent = clk_hw_get_parent(hw);
38 parent_rate = clk_hw_get_rate(parent);
42 /* Now, get our parent's parent (most likely some PLL) */
43 grandparent = clk_hw_get_parent(parent);
48 grandparent_rate = clk_hw_get_rate(grandparent);
49 if (!grandparent_rate)
52 /* Get our parent clock divider */
53 parent_div = grandparent_rate / parent_rate;
55 step = DIV_ROUND_CLOSEST(360, parent_div);
59 static int ccu_phase_set_phase(struct clk_hw *hw, int degrees)
61 struct ccu_phase *phase = hw_to_ccu_phase(hw);
62 struct clk_hw *parent, *grandparent;
63 unsigned int parent_rate, grandparent_rate;
68 /* Get our parent clock, it's the one that can adjust its rate */
69 parent = clk_hw_get_parent(hw);
74 parent_rate = clk_hw_get_rate(parent);
78 /* Now, get our parent's parent (most likely some PLL) */
79 grandparent = clk_hw_get_parent(parent);
84 grandparent_rate = clk_hw_get_rate(grandparent);
85 if (!grandparent_rate)
91 /* Get our parent divider */
92 parent_div = grandparent_rate / parent_rate;
95 * We can only outphase the clocks by multiple of the
98 * Since our parent clock is only a divider, and the
99 * formula to get the outphasing in degrees is deg =
100 * 360 * delta / period
102 * If we simplify this formula, we can see that the
103 * only thing that we're concerned about is the number
104 * of period we want to outphase our clock from, and
105 * the divider set by our parent clock.
107 step = DIV_ROUND_CLOSEST(360, parent_div);
108 delay = DIV_ROUND_CLOSEST(degrees, step);
113 spin_lock_irqsave(phase->common.lock, flags);
114 reg = readl(phase->common.base + phase->common.reg);
115 reg &= ~GENMASK(phase->width + phase->shift - 1, phase->shift);
116 writel(reg | (delay << phase->shift),
117 phase->common.base + phase->common.reg);
118 spin_unlock_irqrestore(phase->common.lock, flags);
123 const struct clk_ops ccu_phase_ops = {
124 .get_phase = ccu_phase_get_phase,
125 .set_phase = ccu_phase_set_phase,