GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / clk / ux500 / clk-prcmu.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PRCMU clock implementation for ux500 platform.
4  *
5  * Copyright (C) 2012 ST-Ericsson SA
6  * Author: Ulf Hansson <ulf.hansson@linaro.org>
7  */
8
9 #include <linux/clk-provider.h>
10 #include <linux/mfd/dbx500-prcmu.h>
11 #include <linux/slab.h>
12 #include <linux/io.h>
13 #include <linux/err.h>
14 #include "clk.h"
15
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)
18
19 struct clk_prcmu {
20         struct clk_hw hw;
21         u8 cg_sel;
22         int opp_requested;
23 };
24
25 struct clk_prcmu_clkout {
26         struct clk_hw hw;
27         u8 clkout_id;
28         u8 source;
29         u8 divider;
30 };
31
32 /* PRCMU clock operations. */
33
34 static int clk_prcmu_prepare(struct clk_hw *hw)
35 {
36         struct clk_prcmu *clk = to_clk_prcmu(hw);
37
38         return prcmu_request_clock(clk->cg_sel, true);
39 }
40
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 }
48
49 static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
50                                            unsigned long parent_rate)
51 {
52         struct clk_prcmu *clk = to_clk_prcmu(hw);
53         return prcmu_clock_rate(clk->cg_sel);
54 }
55
56 static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
57                                  unsigned long *parent_rate)
58 {
59         struct clk_prcmu *clk = to_clk_prcmu(hw);
60         return prcmu_round_clock_rate(clk->cg_sel, rate);
61 }
62
63 static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
64                               unsigned long parent_rate)
65 {
66         struct clk_prcmu *clk = to_clk_prcmu(hw);
67         return prcmu_set_clock_rate(clk->cg_sel, rate);
68 }
69
70 static int clk_prcmu_opp_prepare(struct clk_hw *hw)
71 {
72         int err;
73         struct clk_prcmu *clk = to_clk_prcmu(hw);
74
75         if (!clk->opp_requested) {
76                 err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
77                                                 (char *)clk_hw_get_name(hw),
78                                                 100);
79                 if (err) {
80                         pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
81                                 __func__, clk_hw_get_name(hw));
82                         return err;
83                 }
84                 clk->opp_requested = 1;
85         }
86
87         err = prcmu_request_clock(clk->cg_sel, true);
88         if (err) {
89                 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
90                                         (char *)clk_hw_get_name(hw));
91                 clk->opp_requested = 0;
92                 return err;
93         }
94
95         return 0;
96 }
97
98 static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
99 {
100         struct clk_prcmu *clk = to_clk_prcmu(hw);
101
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));
105                 return;
106         }
107
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;
112         }
113 }
114
115 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
116 {
117         int err;
118         struct clk_prcmu *clk = to_clk_prcmu(hw);
119
120         if (!clk->opp_requested) {
121                 err = prcmu_request_ape_opp_100_voltage(true);
122                 if (err) {
123                         pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
124                                 __func__, clk_hw_get_name(hw));
125                         return err;
126                 }
127                 clk->opp_requested = 1;
128         }
129
130         err = prcmu_request_clock(clk->cg_sel, true);
131         if (err) {
132                 prcmu_request_ape_opp_100_voltage(false);
133                 clk->opp_requested = 0;
134                 return err;
135         }
136
137         return 0;
138 }
139
140 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
141 {
142         struct clk_prcmu *clk = to_clk_prcmu(hw);
143
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));
147                 return;
148         }
149
150         if (clk->opp_requested) {
151                 prcmu_request_ape_opp_100_voltage(false);
152                 clk->opp_requested = 0;
153         }
154 }
155
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,
162 };
163
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,
168 };
169
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,
174 };
175
176 static const struct clk_ops clk_prcmu_rate_ops = {
177         .recalc_rate = clk_prcmu_recalc_rate,
178 };
179
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,
184 };
185
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,
192 };
193
194 static struct clk_hw *clk_reg_prcmu(const char *name,
195                                     const char *parent_name,
196                                     u8 cg_sel,
197                                     unsigned long rate,
198                                     unsigned long flags,
199                                     const struct clk_ops *clk_prcmu_ops)
200 {
201         struct clk_prcmu *clk;
202         struct clk_init_data clk_prcmu_init;
203         int ret;
204
205         if (!name) {
206                 pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
207                 return ERR_PTR(-EINVAL);
208         }
209
210         clk = kzalloc(sizeof(*clk), GFP_KERNEL);
211         if (!clk)
212                 return ERR_PTR(-ENOMEM);
213
214         clk->cg_sel = cg_sel;
215         clk->opp_requested = 0;
216         /* "rate" can be used for changing the initial frequency */
217         if (rate)
218                 prcmu_set_clock_rate(cg_sel, rate);
219
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;
226
227         ret = clk_hw_register(NULL, &clk->hw);
228         if (ret)
229                 goto free_clk;
230
231         return &clk->hw;
232
233 free_clk:
234         kfree(clk);
235         pr_err("clk_prcmu: %s failed to register clk\n", __func__);
236         return ERR_PTR(-ENOMEM);
237 }
238
239 struct clk_hw *clk_reg_prcmu_scalable(const char *name,
240                                       const char *parent_name,
241                                       u8 cg_sel,
242                                       unsigned long rate,
243                                       unsigned long flags)
244 {
245         return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
246                         &clk_prcmu_scalable_ops);
247 }
248
249 struct clk_hw *clk_reg_prcmu_gate(const char *name,
250                                   const char *parent_name,
251                                   u8 cg_sel,
252                                   unsigned long flags)
253 {
254         return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
255                         &clk_prcmu_gate_ops);
256 }
257
258 struct clk_hw *clk_reg_prcmu_scalable_rate(const char *name,
259                                            const char *parent_name,
260                                            u8 cg_sel,
261                                            unsigned long rate,
262                                            unsigned long flags)
263 {
264         return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
265                         &clk_prcmu_scalable_rate_ops);
266 }
267
268 struct clk_hw *clk_reg_prcmu_rate(const char *name,
269                                   const char *parent_name,
270                                   u8 cg_sel,
271                                   unsigned long flags)
272 {
273         return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
274                         &clk_prcmu_rate_ops);
275 }
276
277 struct clk_hw *clk_reg_prcmu_opp_gate(const char *name,
278                                       const char *parent_name,
279                                       u8 cg_sel,
280                                       unsigned long flags)
281 {
282         return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
283                         &clk_prcmu_opp_gate_ops);
284 }
285
286 struct clk_hw *clk_reg_prcmu_opp_volt_scalable(const char *name,
287                                                const char *parent_name,
288                                                u8 cg_sel,
289                                                unsigned long rate,
290                                                unsigned long flags)
291 {
292         return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
293                         &clk_prcmu_opp_volt_scalable_ops);
294 }
295
296 /* The clkout (external) clock is special and need special ops */
297
298 static int clk_prcmu_clkout_prepare(struct clk_hw *hw)
299 {
300         struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
301
302         return prcmu_config_clkout(clk->clkout_id, clk->source, clk->divider);
303 }
304
305 static void clk_prcmu_clkout_unprepare(struct clk_hw *hw)
306 {
307         struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
308         int ret;
309
310         /* The clkout clock is disabled by dividing by 0 */
311         ret = prcmu_config_clkout(clk->clkout_id, clk->source, 0);
312         if (ret)
313                 pr_err("clk_prcmu: %s failed to disable %s\n", __func__,
314                        clk_hw_get_name(hw));
315 }
316
317 static unsigned long clk_prcmu_clkout_recalc_rate(struct clk_hw *hw,
318                                                   unsigned long parent_rate)
319 {
320         struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
321
322         return (parent_rate / clk->divider);
323 }
324
325 static u8 clk_prcmu_clkout_get_parent(struct clk_hw *hw)
326 {
327         struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
328
329         return clk->source;
330 }
331
332 static int clk_prcmu_clkout_set_parent(struct clk_hw *hw, u8 index)
333 {
334         struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
335
336         clk->source = index;
337         /* Make sure the change reaches the hardware immediately */
338         if (clk_hw_is_prepared(hw))
339                 return clk_prcmu_clkout_prepare(hw);
340         return 0;
341 }
342
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,
350 };
351
352 struct clk_hw *clk_reg_prcmu_clkout(const char *name,
353                                     const char * const *parent_names,
354                                     int num_parents,
355                                     u8 source, u8 divider)
356
357 {
358         struct clk_prcmu_clkout *clk;
359         struct clk_init_data clk_prcmu_clkout_init;
360         u8 clkout_id;
361         int ret;
362
363         if (!name) {
364                 pr_err("clk_prcmu_clkout: %s invalid arguments passed\n", __func__);
365                 return ERR_PTR(-EINVAL);
366         }
367
368         if (!strcmp(name, "clkout1"))
369                 clkout_id = 0;
370         else if (!strcmp(name, "clkout2"))
371                 clkout_id = 1;
372         else {
373                 pr_err("clk_prcmu_clkout: %s bad clock name\n", __func__);
374                 return ERR_PTR(-EINVAL);
375         }
376
377         clk = kzalloc(sizeof(*clk), GFP_KERNEL);
378         if (!clk)
379                 return ERR_PTR(-ENOMEM);
380
381         clk->clkout_id = clkout_id;
382         clk->source = source;
383         clk->divider = divider;
384
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;
391
392         ret = clk_hw_register(NULL, &clk->hw);
393         if (ret)
394                 goto free_clkout;
395
396         return &clk->hw;
397 free_clkout:
398         kfree(clk);
399         pr_err("clk_prcmu_clkout: %s failed to register clk\n", __func__);
400         return ERR_PTR(-ENOMEM);
401 }