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