This source file includes following definitions.
- ccu_phase_get_phase
- ccu_phase_set_phase
1
2
3
4
5
6
7 #include <linux/clk-provider.h>
8 #include <linux/io.h>
9 #include <linux/spinlock.h>
10
11 #include "ccu_phase.h"
12
13 static int ccu_phase_get_phase(struct clk_hw *hw)
14 {
15 struct ccu_phase *phase = hw_to_ccu_phase(hw);
16 struct clk_hw *parent, *grandparent;
17 unsigned int parent_rate, grandparent_rate;
18 u16 step, parent_div;
19 u32 reg;
20 u8 delay;
21
22 reg = readl(phase->common.base + phase->common.reg);
23 delay = (reg >> phase->shift);
24 delay &= (1 << phase->width) - 1;
25
26 if (!delay)
27 return 180;
28
29
30 parent = clk_hw_get_parent(hw);
31 if (!parent)
32 return -EINVAL;
33
34
35 parent_rate = clk_hw_get_rate(parent);
36 if (!parent_rate)
37 return -EINVAL;
38
39
40 grandparent = clk_hw_get_parent(parent);
41 if (!grandparent)
42 return -EINVAL;
43
44
45 grandparent_rate = clk_hw_get_rate(grandparent);
46 if (!grandparent_rate)
47 return -EINVAL;
48
49
50 parent_div = grandparent_rate / parent_rate;
51
52 step = DIV_ROUND_CLOSEST(360, parent_div);
53 return delay * step;
54 }
55
56 static int ccu_phase_set_phase(struct clk_hw *hw, int degrees)
57 {
58 struct ccu_phase *phase = hw_to_ccu_phase(hw);
59 struct clk_hw *parent, *grandparent;
60 unsigned int parent_rate, grandparent_rate;
61 unsigned long flags;
62 u32 reg;
63 u8 delay;
64
65
66 parent = clk_hw_get_parent(hw);
67 if (!parent)
68 return -EINVAL;
69
70
71 parent_rate = clk_hw_get_rate(parent);
72 if (!parent_rate)
73 return -EINVAL;
74
75
76 grandparent = clk_hw_get_parent(parent);
77 if (!grandparent)
78 return -EINVAL;
79
80
81 grandparent_rate = clk_hw_get_rate(grandparent);
82 if (!grandparent_rate)
83 return -EINVAL;
84
85 if (degrees != 180) {
86 u16 step, parent_div;
87
88
89 parent_div = grandparent_rate / parent_rate;
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 step = DIV_ROUND_CLOSEST(360, parent_div);
105 delay = DIV_ROUND_CLOSEST(degrees, step);
106 } else {
107 delay = 0;
108 }
109
110 spin_lock_irqsave(phase->common.lock, flags);
111 reg = readl(phase->common.base + phase->common.reg);
112 reg &= ~GENMASK(phase->width + phase->shift - 1, phase->shift);
113 writel(reg | (delay << phase->shift),
114 phase->common.base + phase->common.reg);
115 spin_unlock_irqrestore(phase->common.lock, flags);
116
117 return 0;
118 }
119
120 const struct clk_ops ccu_phase_ops = {
121 .get_phase = ccu_phase_get_phase,
122 .set_phase = ccu_phase_set_phase,
123 };