1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // OWL composite clock driver |
4 | // |
5 | // Copyright (c) 2014 Actions Semi Inc. |
6 | // Author: David Liu <liuwei@actions-semi.com> |
7 | // |
8 | // Copyright (c) 2018 Linaro Ltd. |
9 | // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
10 | |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/regmap.h> |
13 | |
14 | #include "owl-composite.h" |
15 | |
16 | static u8 owl_comp_get_parent(struct clk_hw *hw) |
17 | { |
18 | struct owl_composite *comp = hw_to_owl_comp(hw); |
19 | |
20 | return owl_mux_helper_get_parent(common: &comp->common, mux_hw: &comp->mux_hw); |
21 | } |
22 | |
23 | static int owl_comp_set_parent(struct clk_hw *hw, u8 index) |
24 | { |
25 | struct owl_composite *comp = hw_to_owl_comp(hw); |
26 | |
27 | return owl_mux_helper_set_parent(common: &comp->common, mux_hw: &comp->mux_hw, index); |
28 | } |
29 | |
30 | static void owl_comp_disable(struct clk_hw *hw) |
31 | { |
32 | struct owl_composite *comp = hw_to_owl_comp(hw); |
33 | struct owl_clk_common *common = &comp->common; |
34 | |
35 | owl_gate_set(common, gate_hw: &comp->gate_hw, enable: false); |
36 | } |
37 | |
38 | static int owl_comp_enable(struct clk_hw *hw) |
39 | { |
40 | struct owl_composite *comp = hw_to_owl_comp(hw); |
41 | struct owl_clk_common *common = &comp->common; |
42 | |
43 | owl_gate_set(common, gate_hw: &comp->gate_hw, enable: true); |
44 | |
45 | return 0; |
46 | } |
47 | |
48 | static int owl_comp_is_enabled(struct clk_hw *hw) |
49 | { |
50 | struct owl_composite *comp = hw_to_owl_comp(hw); |
51 | struct owl_clk_common *common = &comp->common; |
52 | |
53 | return owl_gate_clk_is_enabled(common, gate_hw: &comp->gate_hw); |
54 | } |
55 | |
56 | static int owl_comp_div_determine_rate(struct clk_hw *hw, |
57 | struct clk_rate_request *req) |
58 | { |
59 | struct owl_composite *comp = hw_to_owl_comp(hw); |
60 | long rate; |
61 | |
62 | rate = owl_divider_helper_round_rate(common: &comp->common, div_hw: &comp->rate.div_hw, |
63 | rate: req->rate, parent_rate: &req->best_parent_rate); |
64 | if (rate < 0) |
65 | return rate; |
66 | |
67 | req->rate = rate; |
68 | return 0; |
69 | } |
70 | |
71 | static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw, |
72 | unsigned long parent_rate) |
73 | { |
74 | struct owl_composite *comp = hw_to_owl_comp(hw); |
75 | |
76 | return owl_divider_helper_recalc_rate(common: &comp->common, div_hw: &comp->rate.div_hw, |
77 | parent_rate); |
78 | } |
79 | |
80 | static int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate, |
81 | unsigned long parent_rate) |
82 | { |
83 | struct owl_composite *comp = hw_to_owl_comp(hw); |
84 | |
85 | return owl_divider_helper_set_rate(common: &comp->common, div_hw: &comp->rate.div_hw, |
86 | rate, parent_rate); |
87 | } |
88 | |
89 | static int owl_comp_fact_determine_rate(struct clk_hw *hw, |
90 | struct clk_rate_request *req) |
91 | { |
92 | struct owl_composite *comp = hw_to_owl_comp(hw); |
93 | long rate; |
94 | |
95 | rate = owl_factor_helper_round_rate(common: &comp->common, |
96 | factor_hw: &comp->rate.factor_hw, |
97 | rate: req->rate, parent_rate: &req->best_parent_rate); |
98 | if (rate < 0) |
99 | return rate; |
100 | |
101 | req->rate = rate; |
102 | return 0; |
103 | } |
104 | |
105 | static unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw, |
106 | unsigned long parent_rate) |
107 | { |
108 | struct owl_composite *comp = hw_to_owl_comp(hw); |
109 | |
110 | return owl_factor_helper_recalc_rate(common: &comp->common, |
111 | factor_hw: &comp->rate.factor_hw, |
112 | parent_rate); |
113 | } |
114 | |
115 | static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate, |
116 | unsigned long parent_rate) |
117 | { |
118 | struct owl_composite *comp = hw_to_owl_comp(hw); |
119 | |
120 | return owl_factor_helper_set_rate(common: &comp->common, |
121 | factor_hw: &comp->rate.factor_hw, |
122 | rate, parent_rate); |
123 | } |
124 | |
125 | static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate, |
126 | unsigned long *parent_rate) |
127 | { |
128 | struct owl_composite *comp = hw_to_owl_comp(hw); |
129 | struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw; |
130 | |
131 | return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate); |
132 | } |
133 | |
134 | static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw, |
135 | unsigned long parent_rate) |
136 | { |
137 | struct owl_composite *comp = hw_to_owl_comp(hw); |
138 | struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw; |
139 | |
140 | return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate); |
141 | |
142 | } |
143 | |
144 | static int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate, |
145 | unsigned long parent_rate) |
146 | { |
147 | /* |
148 | * We must report success but we can do so unconditionally because |
149 | * owl_comp_fix_fact_round_rate returns values that ensure this call is |
150 | * a nop. |
151 | */ |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | const struct clk_ops owl_comp_div_ops = { |
157 | /* mux_ops */ |
158 | .get_parent = owl_comp_get_parent, |
159 | .set_parent = owl_comp_set_parent, |
160 | |
161 | /* gate_ops */ |
162 | .disable = owl_comp_disable, |
163 | .enable = owl_comp_enable, |
164 | .is_enabled = owl_comp_is_enabled, |
165 | |
166 | /* div_ops */ |
167 | .determine_rate = owl_comp_div_determine_rate, |
168 | .recalc_rate = owl_comp_div_recalc_rate, |
169 | .set_rate = owl_comp_div_set_rate, |
170 | }; |
171 | |
172 | |
173 | const struct clk_ops owl_comp_fact_ops = { |
174 | /* mux_ops */ |
175 | .get_parent = owl_comp_get_parent, |
176 | .set_parent = owl_comp_set_parent, |
177 | |
178 | /* gate_ops */ |
179 | .disable = owl_comp_disable, |
180 | .enable = owl_comp_enable, |
181 | .is_enabled = owl_comp_is_enabled, |
182 | |
183 | /* fact_ops */ |
184 | .determine_rate = owl_comp_fact_determine_rate, |
185 | .recalc_rate = owl_comp_fact_recalc_rate, |
186 | .set_rate = owl_comp_fact_set_rate, |
187 | }; |
188 | |
189 | const struct clk_ops owl_comp_fix_fact_ops = { |
190 | /* gate_ops */ |
191 | .disable = owl_comp_disable, |
192 | .enable = owl_comp_enable, |
193 | .is_enabled = owl_comp_is_enabled, |
194 | |
195 | /* fix_fact_ops */ |
196 | .round_rate = owl_comp_fix_fact_round_rate, |
197 | .recalc_rate = owl_comp_fix_fact_recalc_rate, |
198 | .set_rate = owl_comp_fix_fact_set_rate, |
199 | }; |
200 | |
201 | |
202 | const struct clk_ops owl_comp_pass_ops = { |
203 | /* mux_ops */ |
204 | .determine_rate = clk_hw_determine_rate_no_reparent, |
205 | .get_parent = owl_comp_get_parent, |
206 | .set_parent = owl_comp_set_parent, |
207 | |
208 | /* gate_ops */ |
209 | .disable = owl_comp_disable, |
210 | .enable = owl_comp_enable, |
211 | .is_enabled = owl_comp_is_enabled, |
212 | }; |
213 | |