1 // SPDX-License-Identifier: GPL-2.0-only
3 * PRCMU clock implementation for ux500 platform.
5 * Copyright (C) 2012 ST-Ericsson SA
6 * Author: Ulf Hansson <ulf.hansson@linaro.org>
9 #include <linux/clk-provider.h>
10 #include <linux/mfd/dbx500-prcmu.h>
11 #include <linux/slab.h>
13 #include <linux/err.h>
16 #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
17 #define to_clk_prcmu_clkout(_hw) container_of(_hw, struct clk_prcmu_clkout, hw)
25 struct clk_prcmu_clkout
{
32 /* PRCMU clock operations. */
34 static int clk_prcmu_prepare(struct clk_hw
*hw
)
36 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
38 return prcmu_request_clock(clk
->cg_sel
, true);
41 static void clk_prcmu_unprepare(struct clk_hw
*hw
)
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__
,
49 static unsigned long clk_prcmu_recalc_rate(struct clk_hw
*hw
,
50 unsigned long parent_rate
)
52 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
53 return prcmu_clock_rate(clk
->cg_sel
);
56 static long clk_prcmu_round_rate(struct clk_hw
*hw
, unsigned long rate
,
57 unsigned long *parent_rate
)
59 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
60 return prcmu_round_clock_rate(clk
->cg_sel
, rate
);
63 static int clk_prcmu_set_rate(struct clk_hw
*hw
, unsigned long rate
,
64 unsigned long parent_rate
)
66 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
67 return prcmu_set_clock_rate(clk
->cg_sel
, rate
);
70 static int clk_prcmu_opp_prepare(struct clk_hw
*hw
)
73 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
75 if (!clk
->opp_requested
) {
76 err
= prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP
,
77 (char *)clk_hw_get_name(hw
),
80 pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
81 __func__
, clk_hw_get_name(hw
));
84 clk
->opp_requested
= 1;
87 err
= prcmu_request_clock(clk
->cg_sel
, true);
89 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP
,
90 (char *)clk_hw_get_name(hw
));
91 clk
->opp_requested
= 0;
98 static void clk_prcmu_opp_unprepare(struct clk_hw
*hw
)
100 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
102 if (prcmu_request_clock(clk
->cg_sel
, false)) {
103 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__
,
104 clk_hw_get_name(hw
));
108 if (clk
->opp_requested
) {
109 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP
,
110 (char *)clk_hw_get_name(hw
));
111 clk
->opp_requested
= 0;
115 static int clk_prcmu_opp_volt_prepare(struct clk_hw
*hw
)
118 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
120 if (!clk
->opp_requested
) {
121 err
= prcmu_request_ape_opp_100_voltage(true);
123 pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
124 __func__
, clk_hw_get_name(hw
));
127 clk
->opp_requested
= 1;
130 err
= prcmu_request_clock(clk
->cg_sel
, true);
132 prcmu_request_ape_opp_100_voltage(false);
133 clk
->opp_requested
= 0;
140 static void clk_prcmu_opp_volt_unprepare(struct clk_hw
*hw
)
142 struct clk_prcmu
*clk
= to_clk_prcmu(hw
);
144 if (prcmu_request_clock(clk
->cg_sel
, false)) {
145 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__
,
146 clk_hw_get_name(hw
));
150 if (clk
->opp_requested
) {
151 prcmu_request_ape_opp_100_voltage(false);
152 clk
->opp_requested
= 0;
156 static const struct clk_ops clk_prcmu_scalable_ops
= {
157 .prepare
= clk_prcmu_prepare
,
158 .unprepare
= clk_prcmu_unprepare
,
159 .recalc_rate
= clk_prcmu_recalc_rate
,
160 .round_rate
= clk_prcmu_round_rate
,
161 .set_rate
= clk_prcmu_set_rate
,
164 static const struct clk_ops clk_prcmu_gate_ops
= {
165 .prepare
= clk_prcmu_prepare
,
166 .unprepare
= clk_prcmu_unprepare
,
167 .recalc_rate
= clk_prcmu_recalc_rate
,
170 static const struct clk_ops clk_prcmu_scalable_rate_ops
= {
171 .recalc_rate
= clk_prcmu_recalc_rate
,
172 .round_rate
= clk_prcmu_round_rate
,
173 .set_rate
= clk_prcmu_set_rate
,
176 static const struct clk_ops clk_prcmu_rate_ops
= {
177 .recalc_rate
= clk_prcmu_recalc_rate
,
180 static const struct clk_ops clk_prcmu_opp_gate_ops
= {
181 .prepare
= clk_prcmu_opp_prepare
,
182 .unprepare
= clk_prcmu_opp_unprepare
,
183 .recalc_rate
= clk_prcmu_recalc_rate
,
186 static const struct clk_ops clk_prcmu_opp_volt_scalable_ops
= {
187 .prepare
= clk_prcmu_opp_volt_prepare
,
188 .unprepare
= clk_prcmu_opp_volt_unprepare
,
189 .recalc_rate
= clk_prcmu_recalc_rate
,
190 .round_rate
= clk_prcmu_round_rate
,
191 .set_rate
= clk_prcmu_set_rate
,
194 static struct clk_hw
*clk_reg_prcmu(const char *name
,
195 const char *parent_name
,
199 const struct clk_ops
*clk_prcmu_ops
)
201 struct clk_prcmu
*clk
;
202 struct clk_init_data clk_prcmu_init
;
206 pr_err("clk_prcmu: %s invalid arguments passed\n", __func__
);
207 return ERR_PTR(-EINVAL
);
210 clk
= kzalloc(sizeof(*clk
), GFP_KERNEL
);
212 return ERR_PTR(-ENOMEM
);
214 clk
->cg_sel
= cg_sel
;
215 clk
->opp_requested
= 0;
216 /* "rate" can be used for changing the initial frequency */
218 prcmu_set_clock_rate(cg_sel
, rate
);
220 clk_prcmu_init
.name
= name
;
221 clk_prcmu_init
.ops
= clk_prcmu_ops
;
222 clk_prcmu_init
.flags
= flags
;
223 clk_prcmu_init
.parent_names
= (parent_name
? &parent_name
: NULL
);
224 clk_prcmu_init
.num_parents
= (parent_name
? 1 : 0);
225 clk
->hw
.init
= &clk_prcmu_init
;
227 ret
= clk_hw_register(NULL
, &clk
->hw
);
235 pr_err("clk_prcmu: %s failed to register clk\n", __func__
);
236 return ERR_PTR(-ENOMEM
);
239 struct clk_hw
*clk_reg_prcmu_scalable(const char *name
,
240 const char *parent_name
,
245 return clk_reg_prcmu(name
, parent_name
, cg_sel
, rate
, flags
,
246 &clk_prcmu_scalable_ops
);
249 struct clk_hw
*clk_reg_prcmu_gate(const char *name
,
250 const char *parent_name
,
254 return clk_reg_prcmu(name
, parent_name
, cg_sel
, 0, flags
,
255 &clk_prcmu_gate_ops
);
258 struct clk_hw
*clk_reg_prcmu_scalable_rate(const char *name
,
259 const char *parent_name
,
264 return clk_reg_prcmu(name
, parent_name
, cg_sel
, rate
, flags
,
265 &clk_prcmu_scalable_rate_ops
);
268 struct clk_hw
*clk_reg_prcmu_rate(const char *name
,
269 const char *parent_name
,
273 return clk_reg_prcmu(name
, parent_name
, cg_sel
, 0, flags
,
274 &clk_prcmu_rate_ops
);
277 struct clk_hw
*clk_reg_prcmu_opp_gate(const char *name
,
278 const char *parent_name
,
282 return clk_reg_prcmu(name
, parent_name
, cg_sel
, 0, flags
,
283 &clk_prcmu_opp_gate_ops
);
286 struct clk_hw
*clk_reg_prcmu_opp_volt_scalable(const char *name
,
287 const char *parent_name
,
292 return clk_reg_prcmu(name
, parent_name
, cg_sel
, rate
, flags
,
293 &clk_prcmu_opp_volt_scalable_ops
);
296 /* The clkout (external) clock is special and need special ops */
298 static int clk_prcmu_clkout_prepare(struct clk_hw
*hw
)
300 struct clk_prcmu_clkout
*clk
= to_clk_prcmu_clkout(hw
);
302 return prcmu_config_clkout(clk
->clkout_id
, clk
->source
, clk
->divider
);
305 static void clk_prcmu_clkout_unprepare(struct clk_hw
*hw
)
307 struct clk_prcmu_clkout
*clk
= to_clk_prcmu_clkout(hw
);
310 /* The clkout clock is disabled by dividing by 0 */
311 ret
= prcmu_config_clkout(clk
->clkout_id
, clk
->source
, 0);
313 pr_err("clk_prcmu: %s failed to disable %s\n", __func__
,
314 clk_hw_get_name(hw
));
317 static unsigned long clk_prcmu_clkout_recalc_rate(struct clk_hw
*hw
,
318 unsigned long parent_rate
)
320 struct clk_prcmu_clkout
*clk
= to_clk_prcmu_clkout(hw
);
322 return (parent_rate
/ clk
->divider
);
325 static u8
clk_prcmu_clkout_get_parent(struct clk_hw
*hw
)
327 struct clk_prcmu_clkout
*clk
= to_clk_prcmu_clkout(hw
);
332 static int clk_prcmu_clkout_set_parent(struct clk_hw
*hw
, u8 index
)
334 struct clk_prcmu_clkout
*clk
= to_clk_prcmu_clkout(hw
);
337 /* Make sure the change reaches the hardware immediately */
338 if (clk_hw_is_prepared(hw
))
339 return clk_prcmu_clkout_prepare(hw
);
343 static const struct clk_ops clk_prcmu_clkout_ops
= {
344 .prepare
= clk_prcmu_clkout_prepare
,
345 .unprepare
= clk_prcmu_clkout_unprepare
,
346 .recalc_rate
= clk_prcmu_clkout_recalc_rate
,
347 .determine_rate
= clk_hw_determine_rate_no_reparent
,
348 .get_parent
= clk_prcmu_clkout_get_parent
,
349 .set_parent
= clk_prcmu_clkout_set_parent
,
352 struct clk_hw
*clk_reg_prcmu_clkout(const char *name
,
353 const char * const *parent_names
,
355 u8 source
, u8 divider
)
358 struct clk_prcmu_clkout
*clk
;
359 struct clk_init_data clk_prcmu_clkout_init
;
364 pr_err("clk_prcmu_clkout: %s invalid arguments passed\n", __func__
);
365 return ERR_PTR(-EINVAL
);
368 if (!strcmp(name
, "clkout1"))
370 else if (!strcmp(name
, "clkout2"))
373 pr_err("clk_prcmu_clkout: %s bad clock name\n", __func__
);
374 return ERR_PTR(-EINVAL
);
377 clk
= kzalloc(sizeof(*clk
), GFP_KERNEL
);
379 return ERR_PTR(-ENOMEM
);
381 clk
->clkout_id
= clkout_id
;
382 clk
->source
= source
;
383 clk
->divider
= divider
;
385 clk_prcmu_clkout_init
.name
= name
;
386 clk_prcmu_clkout_init
.ops
= &clk_prcmu_clkout_ops
;
387 clk_prcmu_clkout_init
.flags
= CLK_GET_RATE_NOCACHE
;
388 clk_prcmu_clkout_init
.parent_names
= parent_names
;
389 clk_prcmu_clkout_init
.num_parents
= num_parents
;
390 clk
->hw
.init
= &clk_prcmu_clkout_init
;
392 ret
= clk_hw_register(NULL
, &clk
->hw
);
399 pr_err("clk_prcmu_clkout: %s failed to register clk\n", __func__
);
400 return ERR_PTR(-ENOMEM
);