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