Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 20struct 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
 30static 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
 42static 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
 52static 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
 58static 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
 65static 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
 71static 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
 77static 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
 84static 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
 91static 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
 98static 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
127static 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
146static 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
172static 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
190static 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
202static 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
212static 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
219static struct clk_ops clk_prcmu_rate_ops = {
220	.is_enabled = clk_prcmu_is_enabled,
221	.recalc_rate = clk_prcmu_recalc_rate,
222};
223
224static 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
234static 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
246static 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
289free_clk:
290	kfree(clk);
291	pr_err("clk_prcmu: %s failed to register clk\n", __func__);
292	return ERR_PTR(-ENOMEM);
293}
294
295struct 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
305struct 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
314struct 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
324struct 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
333struct 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
342struct 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}