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
,