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/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
 19struct 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
 29static 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
 41static 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
 51static 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
 57static 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
 64static 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
 70static 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
 76static 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
 83static 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
 90static 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
 97static 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
126static 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
145static 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
171static 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
189static 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
201static 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
211static 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
218static struct clk_ops clk_prcmu_rate_ops = {
219	.is_enabled = clk_prcmu_is_enabled,
220	.recalc_rate = clk_prcmu_recalc_rate,
221};
222
223static 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
233static 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
245static 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				 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(struct clk_prcmu), GFP_KERNEL);
262	if (!clk) {
263		pr_err("clk_prcmu: %s could not allocate clk\n", __func__);
264		return ERR_PTR(-ENOMEM);
265	}
266
267	clk->cg_sel = cg_sel;
268	clk->is_prepared = 1;
269	clk->is_enabled = 1;
270	clk->opp_requested = 0;
271	/* "rate" can be used for changing the initial frequency */
272	if (rate)
273		prcmu_set_clock_rate(cg_sel, rate);
274
275	clk_prcmu_init.name = name;
276	clk_prcmu_init.ops = clk_prcmu_ops;
277	clk_prcmu_init.flags = flags;
278	clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
279	clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
280	clk->hw.init = &clk_prcmu_init;
281
282	clk_reg = clk_register(NULL, &clk->hw);
283	if (IS_ERR_OR_NULL(clk_reg))
284		goto free_clk;
285
286	return clk_reg;
287
288free_clk:
289	kfree(clk);
290	pr_err("clk_prcmu: %s failed to register clk\n", __func__);
291	return ERR_PTR(-ENOMEM);
292}
293
294struct clk *clk_reg_prcmu_scalable(const char *name,
295				   const char *parent_name,
296				   u8 cg_sel,
297				   unsigned long rate,
298				   unsigned long flags)
299{
300	return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
301			&clk_prcmu_scalable_ops);
302}
303
304struct clk *clk_reg_prcmu_gate(const char *name,
305			       const char *parent_name,
306			       u8 cg_sel,
307			       unsigned long flags)
308{
309	return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
310			&clk_prcmu_gate_ops);
311}
312
313struct clk *clk_reg_prcmu_scalable_rate(const char *name,
314					const char *parent_name,
315					u8 cg_sel,
316					unsigned long rate,
317					unsigned long flags)
318{
319	return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
320			&clk_prcmu_scalable_rate_ops);
321}
322
323struct clk *clk_reg_prcmu_rate(const char *name,
324			       const char *parent_name,
325			       u8 cg_sel,
326			       unsigned long flags)
327{
328	return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
329			&clk_prcmu_rate_ops);
330}
331
332struct clk *clk_reg_prcmu_opp_gate(const char *name,
333				   const char *parent_name,
334				   u8 cg_sel,
335				   unsigned long flags)
336{
337	return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
338			&clk_prcmu_opp_gate_ops);
339}
340
341struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
342					    const char *parent_name,
343					    u8 cg_sel,
344					    unsigned long rate,
345					    unsigned long flags)
346{
347	return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
348			&clk_prcmu_opp_volt_scalable_ops);
349}