1 /*
2 * PRCMU clock implementation for ux500 platform.
3 *
4 * Copyright (C) 2012 ST-Ericsson SA
5 * Author: Ulf Hansson <ulf.hansson@linaro.org>
6 *
7 * License terms: GNU General Public License (GPL) version 2
8 */
9
10 #include <linux/clk-provider.h>
11 #include <linux/mfd/dbx500-prcmu.h>
12 #include <linux/slab.h>
13 #include <linux/io.h>
14 #include <linux/err.h>
15 #include "clk.h"
16
17 #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
18
19 struct clk_prcmu {
20 struct clk_hw hw;
21 u8 cg_sel;
22 int is_prepared;
23 int is_enabled;
24 int opp_requested;
25 };
26
27 /* PRCMU clock operations. */
28
clk_prcmu_prepare(struct clk_hw * hw)29 static int clk_prcmu_prepare(struct clk_hw *hw)
30 {
31 int ret;
32 struct clk_prcmu *clk = to_clk_prcmu(hw);
33
34 ret = prcmu_request_clock(clk->cg_sel, true);
35 if (!ret)
36 clk->is_prepared = 1;
37
38 return ret;
39 }
40
clk_prcmu_unprepare(struct clk_hw * hw)41 static void clk_prcmu_unprepare(struct clk_hw *hw)
42 {
43 struct clk_prcmu *clk = to_clk_prcmu(hw);
44 if (prcmu_request_clock(clk->cg_sel, false))
45 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
46 clk_hw_get_name(hw));
47 else
48 clk->is_prepared = 0;
49 }
50
clk_prcmu_is_prepared(struct clk_hw * hw)51 static int clk_prcmu_is_prepared(struct clk_hw *hw)
52 {
53 struct clk_prcmu *clk = to_clk_prcmu(hw);
54 return clk->is_prepared;
55 }
56
clk_prcmu_enable(struct clk_hw * hw)57 static int clk_prcmu_enable(struct clk_hw *hw)
58 {
59 struct clk_prcmu *clk = to_clk_prcmu(hw);
60 clk->is_enabled = 1;
61 return 0;
62 }
63
clk_prcmu_disable(struct clk_hw * hw)64 static void clk_prcmu_disable(struct clk_hw *hw)
65 {
66 struct clk_prcmu *clk = to_clk_prcmu(hw);
67 clk->is_enabled = 0;
68 }
69
clk_prcmu_is_enabled(struct clk_hw * hw)70 static int clk_prcmu_is_enabled(struct clk_hw *hw)
71 {
72 struct clk_prcmu *clk = to_clk_prcmu(hw);
73 return clk->is_enabled;
74 }
75
clk_prcmu_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)76 static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
77 unsigned long parent_rate)
78 {
79 struct clk_prcmu *clk = to_clk_prcmu(hw);
80 return prcmu_clock_rate(clk->cg_sel);
81 }
82
clk_prcmu_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)83 static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
84 unsigned long *parent_rate)
85 {
86 struct clk_prcmu *clk = to_clk_prcmu(hw);
87 return prcmu_round_clock_rate(clk->cg_sel, rate);
88 }
89
clk_prcmu_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)90 static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
91 unsigned long parent_rate)
92 {
93 struct clk_prcmu *clk = to_clk_prcmu(hw);
94 return prcmu_set_clock_rate(clk->cg_sel, rate);
95 }
96
clk_prcmu_opp_prepare(struct clk_hw * hw)97 static int clk_prcmu_opp_prepare(struct clk_hw *hw)
98 {
99 int err;
100 struct clk_prcmu *clk = to_clk_prcmu(hw);
101
102 if (!clk->opp_requested) {
103 err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
104 (char *)clk_hw_get_name(hw),
105 100);
106 if (err) {
107 pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
108 __func__, clk_hw_get_name(hw));
109 return err;
110 }
111 clk->opp_requested = 1;
112 }
113
114 err = prcmu_request_clock(clk->cg_sel, true);
115 if (err) {
116 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
117 (char *)clk_hw_get_name(hw));
118 clk->opp_requested = 0;
119 return err;
120 }
121
122 clk->is_prepared = 1;
123 return 0;
124 }
125
clk_prcmu_opp_unprepare(struct clk_hw * hw)126 static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
127 {
128 struct clk_prcmu *clk = to_clk_prcmu(hw);
129
130 if (prcmu_request_clock(clk->cg_sel, false)) {
131 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
132 clk_hw_get_name(hw));
133 return;
134 }
135
136 if (clk->opp_requested) {
137 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
138 (char *)clk_hw_get_name(hw));
139 clk->opp_requested = 0;
140 }
141
142 clk->is_prepared = 0;
143 }
144
clk_prcmu_opp_volt_prepare(struct clk_hw * hw)145 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
146 {
147 int err;
148 struct clk_prcmu *clk = to_clk_prcmu(hw);
149
150 if (!clk->opp_requested) {
151 err = prcmu_request_ape_opp_100_voltage(true);
152 if (err) {
153 pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
154 __func__, clk_hw_get_name(hw));
155 return err;
156 }
157 clk->opp_requested = 1;
158 }
159
160 err = prcmu_request_clock(clk->cg_sel, true);
161 if (err) {
162 prcmu_request_ape_opp_100_voltage(false);
163 clk->opp_requested = 0;
164 return err;
165 }
166
167 clk->is_prepared = 1;
168 return 0;
169 }
170
clk_prcmu_opp_volt_unprepare(struct clk_hw * hw)171 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
172 {
173 struct clk_prcmu *clk = to_clk_prcmu(hw);
174
175 if (prcmu_request_clock(clk->cg_sel, false)) {
176 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
177 clk_hw_get_name(hw));
178 return;
179 }
180
181 if (clk->opp_requested) {
182 prcmu_request_ape_opp_100_voltage(false);
183 clk->opp_requested = 0;
184 }
185
186 clk->is_prepared = 0;
187 }
188
189 static const struct clk_ops clk_prcmu_scalable_ops = {
190 .prepare = clk_prcmu_prepare,
191 .unprepare = clk_prcmu_unprepare,
192 .is_prepared = clk_prcmu_is_prepared,
193 .enable = clk_prcmu_enable,
194 .disable = clk_prcmu_disable,
195 .is_enabled = clk_prcmu_is_enabled,
196 .recalc_rate = clk_prcmu_recalc_rate,
197 .round_rate = clk_prcmu_round_rate,
198 .set_rate = clk_prcmu_set_rate,
199 };
200
201 static const struct clk_ops clk_prcmu_gate_ops = {
202 .prepare = clk_prcmu_prepare,
203 .unprepare = clk_prcmu_unprepare,
204 .is_prepared = clk_prcmu_is_prepared,
205 .enable = clk_prcmu_enable,
206 .disable = clk_prcmu_disable,
207 .is_enabled = clk_prcmu_is_enabled,
208 .recalc_rate = clk_prcmu_recalc_rate,
209 };
210
211 static const struct clk_ops clk_prcmu_scalable_rate_ops = {
212 .is_enabled = clk_prcmu_is_enabled,
213 .recalc_rate = clk_prcmu_recalc_rate,
214 .round_rate = clk_prcmu_round_rate,
215 .set_rate = clk_prcmu_set_rate,
216 };
217
218 static const struct clk_ops clk_prcmu_rate_ops = {
219 .is_enabled = clk_prcmu_is_enabled,
220 .recalc_rate = clk_prcmu_recalc_rate,
221 };
222
223 static const struct clk_ops clk_prcmu_opp_gate_ops = {
224 .prepare = clk_prcmu_opp_prepare,
225 .unprepare = clk_prcmu_opp_unprepare,
226 .is_prepared = clk_prcmu_is_prepared,
227 .enable = clk_prcmu_enable,
228 .disable = clk_prcmu_disable,
229 .is_enabled = clk_prcmu_is_enabled,
230 .recalc_rate = clk_prcmu_recalc_rate,
231 };
232
233 static const struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
234 .prepare = clk_prcmu_opp_volt_prepare,
235 .unprepare = clk_prcmu_opp_volt_unprepare,
236 .is_prepared = clk_prcmu_is_prepared,
237 .enable = clk_prcmu_enable,
238 .disable = clk_prcmu_disable,
239 .is_enabled = clk_prcmu_is_enabled,
240 .recalc_rate = clk_prcmu_recalc_rate,
241 .round_rate = clk_prcmu_round_rate,
242 .set_rate = clk_prcmu_set_rate,
243 };
244
clk_reg_prcmu(const char * name,const char * parent_name,u8 cg_sel,unsigned long rate,unsigned long flags,const struct clk_ops * clk_prcmu_ops)245 static struct clk *clk_reg_prcmu(const char *name,
246 const char *parent_name,
247 u8 cg_sel,
248 unsigned long rate,
249 unsigned long flags,
250 const struct clk_ops *clk_prcmu_ops)
251 {
252 struct clk_prcmu *clk;
253 struct clk_init_data clk_prcmu_init;
254 struct clk *clk_reg;
255
256 if (!name) {
257 pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
258 return ERR_PTR(-EINVAL);
259 }
260
261 clk = kzalloc(sizeof(*clk), GFP_KERNEL);
262 if (!clk)
263 return ERR_PTR(-ENOMEM);
264
265 clk->cg_sel = cg_sel;
266 clk->is_prepared = 1;
267 clk->is_enabled = 1;
268 clk->opp_requested = 0;
269 /* "rate" can be used for changing the initial frequency */
270 if (rate)
271 prcmu_set_clock_rate(cg_sel, rate);
272
273 clk_prcmu_init.name = name;
274 clk_prcmu_init.ops = clk_prcmu_ops;
275 clk_prcmu_init.flags = flags;
276 clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
277 clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
278 clk->hw.init = &clk_prcmu_init;
279
280 clk_reg = clk_register(NULL, &clk->hw);
281 if (IS_ERR_OR_NULL(clk_reg))
282 goto free_clk;
283
284 return clk_reg;
285
286 free_clk:
287 kfree(clk);
288 pr_err("clk_prcmu: %s failed to register clk\n", __func__);
289 return ERR_PTR(-ENOMEM);
290 }
291
clk_reg_prcmu_scalable(const char * name,const char * parent_name,u8 cg_sel,unsigned long rate,unsigned long flags)292 struct clk *clk_reg_prcmu_scalable(const char *name,
293 const char *parent_name,
294 u8 cg_sel,
295 unsigned long rate,
296 unsigned long flags)
297 {
298 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
299 &clk_prcmu_scalable_ops);
300 }
301
clk_reg_prcmu_gate(const char * name,const char * parent_name,u8 cg_sel,unsigned long flags)302 struct clk *clk_reg_prcmu_gate(const char *name,
303 const char *parent_name,
304 u8 cg_sel,
305 unsigned long flags)
306 {
307 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
308 &clk_prcmu_gate_ops);
309 }
310
clk_reg_prcmu_scalable_rate(const char * name,const char * parent_name,u8 cg_sel,unsigned long rate,unsigned long flags)311 struct clk *clk_reg_prcmu_scalable_rate(const char *name,
312 const char *parent_name,
313 u8 cg_sel,
314 unsigned long rate,
315 unsigned long flags)
316 {
317 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
318 &clk_prcmu_scalable_rate_ops);
319 }
320
clk_reg_prcmu_rate(const char * name,const char * parent_name,u8 cg_sel,unsigned long flags)321 struct clk *clk_reg_prcmu_rate(const char *name,
322 const char *parent_name,
323 u8 cg_sel,
324 unsigned long flags)
325 {
326 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
327 &clk_prcmu_rate_ops);
328 }
329
clk_reg_prcmu_opp_gate(const char * name,const char * parent_name,u8 cg_sel,unsigned long flags)330 struct clk *clk_reg_prcmu_opp_gate(const char *name,
331 const char *parent_name,
332 u8 cg_sel,
333 unsigned long flags)
334 {
335 return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
336 &clk_prcmu_opp_gate_ops);
337 }
338
clk_reg_prcmu_opp_volt_scalable(const char * name,const char * parent_name,u8 cg_sel,unsigned long rate,unsigned long flags)339 struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
340 const char *parent_name,
341 u8 cg_sel,
342 unsigned long rate,
343 unsigned long flags)
344 {
345 return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
346 &clk_prcmu_opp_volt_scalable_ops);
347 }
348